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);