easyui tabs源码阅读(未完待续)

  1 /**
  2  * jQuery EasyUI 1.2.5
  3  * 
  4  * Licensed under the GPL terms
  5  * To use it on other terms please contact us
  6  *
  7  * Copyright(c) 2009-2011 stworthy [ stworthy@gmail.com ] 
  8  * 
  9  */
 10 (function($) {
 11     function getMaxScrollWidth(jq) {
 12         var header = $(jq).children("div.tabs-header");
 13         var tabsWidth = 0;
 14         $("ul.tabs li", header).each(function() {
 15             tabsWidth += $(this).outerWidth(true);
 16         });
 17         var wrapWidth = header.children("div.tabs-wrap").width();
 18         var padding = parseInt(header.find("ul.tabs").css("padding-left"));
 19         return tabsWidth - wrapWidth + padding;
 20     };
 21     function setScrollers(jq) {
 22         var opts = $.data(jq, "tabs").options;
 23         var header = $(jq).children("div.tabs-header");
 24         var tool = header.children("div.tabs-tool");
 25         var leftScroller = header.children("div.tabs-scroller-left");
 26         var rightScroller = header.children("div.tabs-scroller-right");
 27         var wrap = header.children("div.tabs-wrap");
 28         var height = ($.boxModel == true ? (header.outerHeight() - (tool.outerHeight() - tool
 29                 .height()))
 30                 : header.outerHeight());
 31         if (opts.plain) {
 32             height -= 2;
 33         }
 34         tool.height(height);
 35         var fullWidth = 0;
 36         $("ul.tabs li", header).each(function() {
 37             fullWidth += $(this).outerWidth(true);
 38         });
 39         var realWidth = header.width() - tool.outerWidth();
 40         if (fullWidth > realWidth) {
 41             leftScroller.show();
 42             rightScroller.show();
 43             tool.css("right", rightScroller.outerWidth());
 44             wrap.css( {
 45                 marginLeft : leftScroller.outerWidth(),
 46                 marginRight : rightScroller.outerWidth() + tool.outerWidth(),
 47                 left : 0,
 48                 width : realWidth - leftScroller.outerWidth() - rightScroller.outerWidth()
 49             });
 50         } else {
 51             leftScroller.hide();
 52             rightScroller.hide();
 53             tool.css("right", 0);
 54             wrap.css( {
 55                 marginLeft : 0,
 56                 marginRight : tool.outerWidth(),
 57                 left : 0,
 58                 width : realWidth
 59             });
 60             wrap.scrollLeft(0);
 61         }
 62     };
 63     function buildButton(jq) {
 64         var opts = $.data(jq, "tabs").options;
 65         var header = $(jq).children("div.tabs-header");
 66         if (opts.tools) {
 67             if (typeof opts.tools == "string") {
 68                 $(opts.tools).addClass("tabs-tool").appendTo(header);
 69                 $(opts.tools).show();
 70             } else {
 71                 header.children("div.tabs-tool").remove();
 72                 var tool = $("<div class=\"tabs-tool\"></div>").appendTo(header);
 73                 for ( var i = 0; i < opts.tools.length; i++) {
 74                     var button = $("<a href=\"javascript:void(0);\"></a>")
 75                             .appendTo(tool);
 76                     button[0].onclick = eval(opts.tools[i].handler || function() {
 77                     });
 78                     button.linkbutton($.extend( {}, opts.tools[i], {
 79                         plain : true
 80                     }));
 81                 }
 82             }
 83         } else {
 84             header.children("div.tabs-tool").remove();
 85         }
 86     };
 87     
 88     /**
 89     *设置tabs的尺寸,其中还判断了盒模式,以适用各种浏览器
 90     */
 91     function setSize(jq) {
 92         var opts = $.data(jq, "tabs").options;
 93         var cc = $(jq);
 94         if (opts.fit == true) {
 95             var p = cc.parent();
 96             opts.width = p.width();
 97             opts.height = p.height();
 98         }
 99         cc.width(opts.width).height(opts.height);
100         var header = $(jq).children("div.tabs-header");
101         if ($.boxModel == true) {
102             header.width(opts.width - (header.outerWidth() - header.width()));
103         } else {
104             header.width(opts.width);
105         }
106         setScrollers(jq);
107         var panels = $(jq).children("div.tabs-panels");
108         var height = opts.height;
109         if (!isNaN(height)) {
110             if ($.boxModel == true) {
111                 var height = panels.outerHeight() - panels.height();
112                 panels.css("height", (height - header.outerHeight() - height) || "auto");
113             } else {
114                 panels.css("height", height - header.outerHeight());
115             }
116         } else {
117             panels.height("auto");
118         }
119         var width = opts.width;
120         if (!isNaN(width)) {
121             if ($.boxModel == true) {
122                 panels.width(width - (panels.outerWidth() - panels.width()));
123             } else {
124                 panels.width(width);
125             }
126         } else {
127             panels.width("auto");
128         }
129     };
130     
131     function fitContent(jq) {
132         var opts = $.data(jq, "tabs").options;
133         var tab = getSelected(jq);
134         if (tab) {
135             var panels = $(jq).children("div.tabs-panels");
136             var width = opts.width == "auto" ? "auto" : panels.width();
137             var height = opts.height == "auto" ? "auto" : panels.height();
138             tab.panel("resize", {
139                 width : width,
140                 height : height
141             });
142         }
143     };
144     
145     /**
146     *此处的jq指class为"easyui-tabs"的div
147     */
148     function wrapTabs(jq) {
149         var cc = $(jq);
150         cc.addClass("tabs-container");
151         //将class为"easyui-tabs"的div的子内容用"<div class=\"tabs-panels\"/>"包裹起来;
152         cc.wrapInner("<div class=\"tabs-panels\"/>");
153         
154         //在class为"tabs-header"的div前添加div
155         $("<div class=\"tabs-header\">"
156                 + "<div class=\"tabs-scroller-left\"></div>"
157                 + "<div class=\"tabs-scroller-right\"></div>"
158                 + "<div class=\"tabs-wrap\">"
159                 + "<ul class=\"tabs\"></ul>" + "</div>" + "</div>")
160                 .prependTo(jq);
161         var tabs = [];
162         var tp = cc.children("div.tabs-panels");
163         tp.children("div[selected]").attr("toselect", "true");
164         //根据最初class为"easyui-tabs"的div的子div创建tabs
165         tp.children("div").each(function() {
166             var pp = $(this);
167             tabs.push(pp);
168             createTab(jq, pp);
169         });
170         cc.children("div.tabs-header").find(
171                 ".tabs-scroller-left, .tabs-scroller-right").hover(function() {
172             $(this).addClass("tabs-scroller-over");
173         }, function() {
174             $(this).removeClass("tabs-scroller-over");
175         });
176         cc.bind("_resize", function(e, param) {
177             var opts = $.data(jq, "tabs").options;
178             if (opts.fit == true || param) {
179                 setSize(jq);
180                 fitContent(jq);
181             }
182             return false;
183         });
184         return tabs;
185     };
186     function setProperties(jq) {
187         var opts = $.data(jq, "tabs").options;
188         var header = $(jq).children("div.tabs-header");//获取class为tabs-header的div,此div即为tabs标签部分;
189         var panel = $(jq).children("div.tabs-panels");//获取class为tabs-panels的div,此div即为tabs中要展示的内容;
190         //如果属性plain为true,则设置tabs标签的背景为透明(默认为true);
191         if (opts.plain == true) {
192             header.addClass("tabs-header-plain");
193         } else {
194             header.removeClass("tabs-header-plain");
195         }
196         if (opts.border == true) {
197             header.removeClass("tabs-header-noborder");
198             panel.removeClass("tabs-panels-noborder");
199         } else {
200             header.addClass("tabs-header-noborder");
201             panel.addClass("tabs-panels-noborder");
202         }
203         //给header的子孙元素中class为".tabs-scroller-left"的div绑定一个自定义事件"click.tabs";
204         $(".tabs-scroller-left", header).unbind(".tabs").bind("click.tabs",
205                 function() {
206                     var header = $(".tabs-wrap", header);
207                     //scrollLeft 获取匹配元素相对滚动条左侧的偏移;
208                     var pos = header.scrollLeft() - opts.scrollIncrement;
209                     header.animate( {
210                         scrollLeft : pos
211                     }, opts.scrollDuration);
212                 });
213         $(".tabs-scroller-right", header).unbind(".tabs").bind(
214                 "click.tabs",
215                 function() {
216                     var header = $(".tabs-wrap", header);
217                     var pos = Math.min(header.scrollLeft() + opts.scrollIncrement,
218                             getMaxScrollWidth(jq));
219                     header.animate( {
220                         scrollLeft : pos
221                     }, opts.scrollDuration);
222                 });
223         var tabs = $.data(jq, "tabs").tabs;
224         for ( var i = 0, len = tabs.length; i < len; i++) {
225             var tab = tabs[i];
226             var tab = tab.panel("options").tab;
227             tab.unbind(".tabs").bind("click.tabs", {
228                 p : tab
229             }, function(e) {
230                 selectTab(jq, getTabIndex(jq, e.data.p));
231             }).bind("contextmenu.tabs",{
232                         p : tab
233                     },
234                     function(e) {
235                         opts.onContextMenu.call(jq, e, e.data.p.panel("options").title);
236                     });
237             tab.find("a.tabs-close").unbind(".tabs").bind("click.tabs", {
238                 p : tab
239             }, function(e) {
240                 closeTab(jq, getTabIndex(jq, e.data.p));
241                 return false;
242             });
243         }
244     };
245     function createTab(container, pp, options) {
246         options = options || {};
247         pp.panel($.extend( {}, options, {
248             border : false,
249             noheader : true,
250             closed : true,
251             doSize : false,
252             iconCls : (options.icon ? options.icon : undefined),
253             onLoad : function() {
254                 if (options.onLoad) {
255                     options.onLoad.call(this, arguments);
256                 }
257                 $.data(container, "tabs").options.onLoad.call(container, pp);
258             }
259         }));
260         var opts = pp.panel("options");
261         var header = $(container).children("div.tabs-header");
262         var tabs = $("ul.tabs", header);
263         var tab = $("<li></li>").appendTo(tabs);
264         var tabInner = $("<a href=\"javascript:void(0)\" class=\"tabs-inner\"></a>")
265                 .appendTo(tab);
266         var tabTitle = $("<span class=\"tabs-title\"></span>").html(opts.title)
267                 .appendTo(tabInner);
268         var tabIcon = $("<span class=\"tabs-icon\"></span>").appendTo(tabInner);
269         if (opts.closable) {
270             tabTitle.addClass("tabs-closable");
271             $("<a href=\"javascript:void(0)\" class=\"tabs-close\"></a>")
272                     .appendTo(tab);
273         }
274         if (opts.iconCls) {
275             tabTitle.addClass("tabs-with-icon");
276             tabIcon.addClass(opts.iconCls);
277         }
278         if (opts.tools) {
279             var tool = $("<span class=\"tabs-p-tool\"></span>").insertAfter(tabInner);
280             if (typeof opts.tools == "string") {
281                 $(opts.tools).children().appendTo(tool);
282             } else {
283                 for ( var i = 0; i < opts.tools.length; i++) {
284                     var t = $("<a href=\"javascript:void(0)\"></a>").appendTo(tool);
285                     t.addClass(opts.tools[i].iconCls);
286                     if (opts.tools[i].handler) {
287                         t.bind("click", eval(opts.tools[i].handler));
288                     }
289                 }
290             }
291             var pr = tool.children().length * 12;
292             if (opts.closable) {
293                 pr += 8;
294             } else {
295                 pr -= 3;
296                 tool.css("right", "5px");
297             }
298             tabTitle.css("padding-right", pr + "px");
299         }
300         opts.tab = tab;
301     };
302     function addTab(jq, options) {
303         var opts = $.data(jq, "tabs").options;
304         var tabs = $.data(jq, "tabs").tabs;
305         var pp = $("<div></div>").appendTo($(jq).children("div.tabs-panels"));
306         tabs.push(pp);
307         createTab(jq, pp, options);
308         opts.onAdd.call(jq, options.title);
309         setScrollers(jq);
310         setProperties(jq);
311         selectTab(jq, tabs.length - 1);
312     };
313     function update(jq, param) {
314         var selectHis = $.data(jq, "tabs").selectHis;
315         var pp = param.tab;
316         var title = pp.panel("options").title;
317         pp.panel($.extend( {}, param.options, {
318             iconCls : (param.options.icon ? param.options.icon : undefined)
319         }));
320         var opts = pp.panel("options");
321         var tab = opts.tab;
322         tab.find("span.tabs-icon").attr("class", "tabs-icon");
323         tab.find("a.tabs-close").remove();
324         tab.find("span.tabs-title").html(opts.title);
325         if (opts.closable) {
326             tab.find("span.tabs-title").addClass("tabs-closable");
327             $("<a href=\"javascript:void(0)\" class=\"tabs-close\"></a>").appendTo(tab);
328         } else {
329             tab.find("span.tabs-title").removeClass("tabs-closable");
330         }
331         if (opts.iconCls) {
332             tab.find("span.tabs-title").addClass("tabs-with-icon");
333             tab.find("span.tabs-icon").addClass(opts.iconCls);
334         } else {
335             tab.find("span.tabs-title").removeClass("tabs-with-icon");
336         }
337         if (title != opts.title) {
338             for ( var i = 0; i < selectHis.length; i++) {
339                 if (selectHis[i] == title) {
340                     selectHis[i] = opts.title;
341                 }
342             }
343         }
344         setProperties(jq);
345         $.data(jq, "tabs").options.onUpdate.call(jq, opts.title);
346     };
347     function closeTab(container, title) {
348         var opts = $.data(container, "tabs").options;
349         var tabs = $.data(container, "tabs").tabs;
350         var selectHis = $.data(container, "tabs").selectHis;
351         if (!exists(container, title)) {
352             return;
353         }
354         var tab = getTab(container, title);
355         var title = tab.panel("options").title;
356         if (opts.onBeforeClose.call(container, title) == false) {
357             return;
358         }
359         var tab = getTab(container, title, true);
360         tab.panel("options").tab.remove();
361         tab.panel("destroy");
362         opts.onClose.call(container, title);
363         setScrollers(container);
364         for ( var i = 0; i < selectHis.length; i++) {
365             if (selectHis[i] == title) {
366                 selectHis.splice(i, 1);
367                 i--;
368             }
369         }
370         var lastTab = selectHis.pop();
371         if (lastTab) {
372             selectTab(container, lastTab);
373         } else {
374             if (tabs.length) {
375                 selectTab(container, 0);
376             }
377         }
378     };
379     function getTab(container, title, close) {
380         var tabs = $.data(container, "tabs").tabs;
381         if (typeof title == "number") {
382             if (title < 0 || title >= tabs.length) {
383                 return null;
384             } else {
385                 var tab = tabs[title];
386                 if (close) {
387                     tabs.splice(title, 1);
388                 }
389                 return tab;
390             }
391         }
392         for ( var i = 0; i < tabs.length; i++) {
393             var tab = tabs[i];
394             if (tab.panel("options").title == title) {
395                 if (close) {
396                     tabs.splice(i, 1);
397                 }
398                 return tab;
399             }
400         }
401         return null;
402     };
403     function getTabIndex(jq, tab) {
404         var tabs = $.data(jq, "tabs").tabs;
405         for ( var i = 0; i < tabs.length; i++) {
406             if (tabs[i][0] == $(tab)[0]) {
407                 return i;
408             }
409         }
410         return -1;
411     };
412     function getSelected(jq) {
413         var tabs = $.data(jq, "tabs").tabs;
414         for ( var i = 0; i < tabs.length; i++) {
415             var tab = tabs[i];
416             if (tab.panel("options").closed == false) {
417                 return tab;
418             }
419         }
420         return null;
421     };
422     function initSelectTab(jq) {
423         var tabs = $.data(jq, "tabs").tabs;
424         for ( var i = 0; i < tabs.length; i++) {
425             if (tabs[i].attr("toselect") == "true") {
426                 selectTab(jq, i);
427                 return;
428             }
429         }
430         if (tabs.length) {
431             selectTab(jq, 0);
432         }
433     };
434     function selectTab(jq, title) {
435         var opts = $.data(jq, "tabs").options;
436         var tabs = $.data(jq, "tabs").tabs;
437         var selectHis = $.data(jq, "tabs").selectHis;
438         if (tabs.length == 0) {
439             return;
440         }
441         var tab = getTab(jq, title);
442         if (!tab) {
443             return;
444         }
445         var selected = getSelected(jq);
446         if (selected) {
447             selected.panel("close");
448             selected.panel("options").tab.removeClass("tabs-selected");
449         }
450         tab.panel("open");
451         var title = tab.panel("options").title;
452         selectHis.push(title);
453         var tab = tab.panel("options").tab;
454         tab.addClass("tabs-selected");
455         var wrap = $(jq).find(">div.tabs-header div.tabs-wrap");
456         var leftPos = tab.position().left + wrap.scrollLeft();
457         var left = leftPos - wrap.scrollLeft();
458         var right = left + tab.outerWidth();
459         if (left < 0 || right > wrap.innerWidth()) {
460             var pos = Math.min(leftPos - (wrap.width() - tab.width()) / 2, getMaxScrollWidth(jq));
461             wrap.animate( {
462                 scrollLeft : pos
463             }, opts.scrollDuration);
464         } else {
465             var pos = Math.min(wrap.scrollLeft(), getMaxScrollWidth(jq));
466             wrap.animate( {
467                 scrollLeft : pos
468             }, opts.scrollDuration);
469         }
470         fitContent(jq);
471         opts.onSelect.call(jq, title);
472     };
473     function exists(container, title) {
474         return getTab(container, title) != null;
475     };
476     
477     //构造函数
478     $.fn.tabs = function(options, param) 
479         //如果options为string类型,表明是调用tabs的方法;
480         if (typeof options == "string") {
481             return $.fn.tabs.methods[options](this, param);
482         }
483         options = options || {};
484         return this.each(function() {
485             var state = $.data(this, "tabs");
486             var opts;
487             if (state) {
488                 opts = $.extend(state.options, options);
489                 state.options = opts;
490             } else {
491                 $.data(this, "tabs", {
492                     options : $.extend( {}, $.fn.tabs.defaults, $.fn.tabs
493                             .parseOptions(this), options),
494                     tabs : wrapTabs(this),
495                     selectHis : []
496                 });
497             }
498             buildButton(this);
499             setProperties(this);
500             setSize(this);
501             initSelectTab(this);
502         });
503     };
504     $.fn.tabs.methods = {
505         options : function(jq) {
506             return $.data(jq[0], "tabs").options;
507         },
508         tabs : function(jq) {
509             return $.data(jq[0], "tabs").tabs;
510         },
511         resize : function(jq) {
512             return jq.each(function() {
513                 setSize(this);
514                 fitContent(this);
515             });
516         },
517         add : function(jq, options) {
518             return jq.each(function() {
519                 addTab(this, options);
520             });
521         },
522         close : function(jq, title) {
523             return jq.each(function() {
524                 closeTab(this, title);
525             });
526         },
527         getTab : function(jq, title) {
528             return getTab(jq[0], title);
529         },
530         getTabIndex : function(jq, tab) {
531             return getTabIndex(jq[0], tab);
532         },
533         getSelected : function(jq) {
534             return getSelected(jq[0]);
535         },
536         select : function(jq, title) {
537             return jq.each(function() {
538                 selectTab(this, title);
539             });
540         },
541         exists : function(jq, title) {
542             return exists(jq[0], title);
543         },
544         update : function(jq, param) {
545             return jq.each(function() {
546                 update(this, param);
547             });
548         }
549     };
550     $.fn.tabs.parseOptions = function(target) {
551         var t = $(target);
552         return {
553             width : (parseInt(target.style.width) || undefined),
554             height : (parseInt(target.style.height) || undefined),
555             fit : (t.attr("fit") ? t.attr("fit") == "true" : undefined),
556             border : (t.attr("border") ? t.attr("border") == "true" : undefined),
557             plain : (t.attr("plain") ? t.attr("plain") == "true" : undefined),
558             tools : t.attr("tools")
559         };
560     };
561     $.fn.tabs.defaults = {
562         width : "auto",
563         height : "auto",
564         plain : false,
565         fit : false,
566         border : true,
567         tools : null,
568         scrollIncrement : 100,
569         scrollDuration : 400,
570         onLoad : function(panel) {
571         },
572         onSelect : function(title) {
573         },
574         onBeforeClose : function(title) {
575         },
576         onClose : function(title) {
577         },
578         onAdd : function(title) {
579         },
580         onUpdate : function(title) {
581         },
582         onContextMenu : function(e, title) {
583         }
584     };
585 })(jQuery);

 

posted @ 2013-02-17 11:17  Vincent.Pei  阅读(3171)  评论(0编辑  收藏  举报