jui.defineUI("ui.tab", [ "jquery", "util.base", "ui.dropdown" ], function($, _, dropdown) {
/**
* @class ui.tab
* @extends core
* @alias Tab
* @requires jquery
* @requires util.base
* @requires ui.dropdown
*/
var UI = function() {
var ui_menu = null,
$anchor = null;
var menuIndex = -1, // menu index
activeIndex = 0;
function hideAll(self) {
var $list = $(self.root).children("li");
$list.removeClass("active");
}
function showMenu(self, elem) {
var pos = $(elem).offset();
$(elem).addClass("checked");
ui_menu.show(pos.left, pos.top + $(self.root).height());
}
function hideMenu(self) {
var $list = $(self.root).children("li"),
$menuTab = $list.eq(menuIndex);
$menuTab.removeClass("checked");
}
function changeTab(self, index) {
hideAll(self);
var $list = $(self.root).children("li"),
$tab = $list.eq(index).addClass("active");
$anchor.appendTo($tab);
showTarget(self.options.target, $tab[0]);
}
function showTarget(target, elem, isInit) {
var hash = $(elem).find("[href*=\#]").attr("href");
$(target).children("*").each(function(i) {
var self = this;
if(("#" + self.id) == hash) {
$(self).show();
} else {
$(self).hide();
}
});
}
function setEventNodes(self) {
$(self.root).children("li").each(function(i) {
// 메뉴 설정
if($(this).hasClass("menu")) {
menuIndex = i;
}
// 이벤트 설정
self.addEvent(this, [ "click", "contextmenu" ], function(e) {
if($(this).hasClass("disabled")) {
return false;
}
var text = $.trim($(this).text()),
value = $(this).val();
if(i != menuIndex) {
if(i != activeIndex) {
var args = [ { index: i, text: text, value: value }, e ];
if(self.options.target != "") {
showTarget(self.options.target, this);
}
// 엑티브 인덱스 변경
activeIndex = i;
self.emit("change", args);
self.emit("click", args);
changeTab(self, i);
}
} else {
self.emit("menu", [ { index: i, text: text }, e ]);
if(ui_menu.type != "show") showMenu(self, this);
}
return false;
});
});
setActiveNode(self);
setEventDragNodes(self);
}
function setEventDragNodes(self) {
if(!self.options.drag) return;
var $tabs = $(self.root).children("li"),
$origin = null,
$clone = null;
var index = null,
targetIndex = null;
$tabs.each(function(i) {
self.addEvent(this, "mousedown", function(e) {
$origin = $(this);
$clone = $origin.clone().css("opacity", "0.5");
index = i;
self.emit("dragstart", [ index, e ]);
return false;
});
self.addEvent(this, "mousemove", function(e) {
if(index == null) return;
targetIndex = i;
if(index > targetIndex) { // move 로직과 동일
if(targetIndex == 0) {
$clone.insertBefore($tabs.eq(0));
} else {
$clone.insertAfter($tabs.eq(targetIndex - 1));
}
} else {
if(targetIndex == $tabs.length - 1) {
$clone.insertAfter($tabs.eq(targetIndex));
} else {
$clone.insertBefore($tabs.eq(targetIndex + 1));
}
}
$origin.hide();
});
});
self.addEvent(self.root, "mouseup", function(e) {
if($origin != null) $origin.show();
if($clone != null) $clone.remove();
if(index != null && targetIndex != null) {
self.move(index, targetIndex);
self.emit("dragend", [ targetIndex, e ]);
}
index = null;
targetIndex = null;
});
}
function setActiveNode(self) {
var $list = $(self.root).children("li"),
$markupNode = $list.filter(".active"),
$indexNode = $list.eq(activeIndex),
$node = ($markupNode.length == 1) ? $markupNode : $indexNode;
// 노드가 없거나 disabled 상태일 때, 맨 첫번째 노드를 활성화
if($node.hasClass("disabled") || $node.length == 0) {
$node = $list.eq(0);
activeIndex = 0;
}
$anchor.appendTo($node);
changeTab(self, $list.index($node));
}
this.init = function() {
var self = this, opts = this.options;
// 활성화 인덱스 설정
activeIndex = opts.index;
// 컴포넌트 요소 세팅
$anchor = $("<div class='anchor'></div>");
// 탭 목록 갱신 및 이벤트 설정
if(opts.nodes.length > 0) {
this.update(opts.nodes);
} else {
setEventNodes(this);
}
// 드롭다운 메뉴
if(this.tpl.menu) {
var $menu = $(this.tpl.menu());
$("body").append($menu);
ui_menu = dropdown($menu, {
event: {
change: function(data, e) {
hideMenu(self);
self.emit("changemenu", [ data, e ]);
},
hide: function() {
hideMenu(self);
}
}
});
}
return this;
}
/**
* @method update
* Changes the tab list
*
* @param {Array} nodes
*/
this.update = function(nodes) {
if(!this.tpl.node) return;
$(this.root).empty();
for(var i = 0; i < nodes.length; i++) {
$(this.root).append(this.tpl.node(nodes[i]));
}
setEventNodes(this);
}
/**
* @method insert
* Adds a tab at a specified index
*
* @param {Integer} index
* @param {Object} node
*/
this.insert = function(index, node) {
if(!this.tpl.node) return;
var html = this.tpl.node(node),
$list = $(this.root).children("li");
if(index == $list.length) {
$(html).insertAfter($list.eq(index - 1));
} else {
$(html).insertBefore($list.eq(index));
}
setEventNodes(this);
}
/**
* @method append
* Adds a tab to the last node
*
* @param {Object} node
*/
this.append = function(node) {
if(!this.tpl.node) return;
var html = this.tpl.node(node);
if(menuIndex != -1) {
$(html).insertBefore($(this.root).find(".menu"));
menuIndex++;
} else {
$(this.root).append(html);
}
setEventNodes(this);
}
/**
* @method prepend
* Adds a tab to the first node
*
* @param {Object} node
*/
this.prepend = function(node) {
if(!this.tpl.node) return;
$(this.root).prepend(this.tpl.node(node));
setEventNodes(this);
}
/**
* @method remove
* Removes a tab at a specified index
*
* @param {Integer} index
*/
this.remove = function(index) {
$(this.root).children("li").eq(index).remove();
setEventNodes(this);
}
/**
* @method move
* Changes a specified tab to a tab at a target index
*
* @param {Integer} index
* @param {Integer} targetIndex
*/
this.move = function(index, targetIndex) {
if(index == targetIndex) return;
var $tabs = $(this.root).children("li"),
$target = $tabs.eq(index);
if(index > targetIndex) {
if(targetIndex == 0) {
$target.insertBefore($tabs.eq(0));
} else {
$target.insertAfter($tabs.eq(targetIndex - 1));
}
} else {
if(targetIndex == $tabs.length - 1) {
$target.insertAfter($tabs.eq(targetIndex));
} else {
$target.insertBefore($tabs.eq(targetIndex + 1));
}
}
activeIndex = targetIndex;
setEventNodes(this);
}
/**
* @method show
* Enables the tab at a specified index
*
* @param {Integer} index
*/
this.show = function(index) {
if(index == menuIndex || index == activeIndex) return;
var $target = $(this.root).children("li").eq(index);
if($target.hasClass("disabled")) return;
activeIndex = index;
this.emit("change", [{
index: index,
text: $.trim($target.text()),
value: $target.val()
}]);
changeTab(this, index);
}
/**
* @method enable
* Enables the tab at a specified index
*
* @param {Integer} index
*/
this.enable = function(index) {
if(index == menuIndex || index == activeIndex) return;
var $target = $(this.root).children("li").eq(index);
$target.removeClass("disabled");
}
/**
* @method disable
* Disables the tab at a specified index
*
* @param {Integer} index
*/
this.disable = function(index) {
if(index == menuIndex || index == activeIndex) return;
var $target = $(this.root).children("li").eq(index);
$target.addClass("disabled");
}
/**
* @method activeIndex
* Gets the index of the currently enabled tab
*
* @return {Integer}
*/
this.activeIndex = function() {
return activeIndex;
}
}
UI.setup = function() {
return {
/**
* @cfg {String/DOMElement} [target=""]
* Determines a selector in the area to become the content of a tab
*/
target: "",
/**
* @cfg {Integer} [index=0]
* Sets an enabled tab
*/
index: 0,
/**
* @cfg {Boolean} [drag=false]
* Changes the tab location through dragging
*/
drag: false,
/**
* @cfg {Array} nodes
* Sets a tab list to data rather than markup
*/
nodes: []
}
}
/**
* @event change
* Event that occurs when a tab is enabled
*
* @param {Object} data changed data
* @param {EventObject} e The event object
*/
/**
* @event click
* Event that occurs when a tab is mouse clicked
*
* @param {Object} data changed data
* @param {EventObject} e The event object
*/
* @event menu
* Event which occurs when tab menu shown
*
* @param {Object} data changed data
* @param {EventObject} e The event object
*/
* @event changemenu
* Event that occurs when a dropdown is selected
*
* @param {Object} data changed data
* @param {EventObject} e The event object
*/
/**
* @event dragstart
* Event that occurs when a tab starts to move
*
* @param {Integer} index
* @param {EventObject} e The event object
*/
/**
* @event dragend
* Event that occurs when the movement of a tab is completed
*
* @param {Integer} index
* @param {EventObject} e The event object
*/
return UI;
});