// Copyright (c) 2005 spinelz.org (http://script.spinelz.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
TabBox = Class.create();
TabBox.className = {
tabBox: 'tabBox_tabBox',
panelContainer: 'tabBox_panelContainer',
tabContainer: 'tabBox_tabContainer',
tabBar: 'tabBox_tabBar',
tab: 'tabBox_tab',
tabLeftInactive: 'tabBox_tabLeftInactive',
tabLeftActive: 'tabBox_tabLeftActive',
tabMiddleInactive: 'tabBox_tabMiddleInactive',
tabMiddleActive: 'tabBox_tabMiddleActive',
tabRightInactive: 'tabBox_tabRightInactive',
tabRightActive: 'tabBox_tabRightActive',
tabTitle: 'tabBox_tabTitle',
closeButton: 'tabBox_closeButton'
}
TabBox.prototype = {
initialize: function(element) {
var options = Object.extend({
selected: 1,
cssPrefix: 'custom_',
beforeSelect: function() { return true },
afterSelect: Prototype.emptyFunction,
afterSelectOnce: Prototype.emptyFunction,
onRemove: function() { return true },
sortable: false,
closeButton: false,
afterSort: Prototype.emptyFunction,
onSort: Prototype.emptyFunction,
lazyLoadUrl: [],
onLazyLoad: Prototype.emptyFunction,
afterLazyLoad: Prototype.emptyFunction,
lazyLoadFailure: Prototype.emptyFunction,
failureLimitOver: Prototype.emptyFunction,
failureLimit: 5,
tabRow: null,
titleLength: null
}, arguments[1] || {});
this.options = options;
this.element = $(element);
Element.setStyle(this.element, {visibility: 'hidden'});
Element.hide(this.element);
this.selected = (this.options.selected > 0) ? this.options.selected - 1 : 0 ;
this.css = CssUtil.getInstance(this.options.cssPrefix, TabBox.className);
this.classNames = this.css.allJoinClassNames();
this.css.addClassNames(this.element, 'tabBox');
this.start();
Element.setStyle(this.element, {visibility: 'visible'});
Element.show(this.element);
if (this.options.lazyLoadUrl.length > 0) this.lazyLoad(0);
},
start: function() {
this.tabs = [];
this.panelList = [];
this.tabId = this.element.id + '_tab';
this.tabLeftId = this.tabId + '_left';
this.tabMiddleId = this.tabId + '_middle';
this.tabRightId = this.tabId + '_right';
this.tabContainerId = this.element.id + '_tabContainer';
this.panelId = this.element.id + '_panel';
this.panelContainerId = this.element.id + '_panelContainer';
this.tabTitleId = this.element.id + '_tabTitle';
this.ids = [];
this.holder = [];
this.build();
this.tabs = this.tabs.collect(function(tab) { return $(tab) });
this.panelList = this.panelList.collect(function(panel) { return $(panel) });
this.tabContainer = $(this.tabContainerId);
this.panelContainer = $(this.panelContainerId);
this.selectTab();
this.setEvent();
this.appendElements();
if (this.options.sortable) this.setDrag();
},
setDrag: function() {
Sortable.create(this.tabContainerId, {
tag: 'div',
overlap: 'horizontal',
constraint: 'horizontal',
onChange: this.options.onSort,
onUpdate: this.options.afterSort,
starteffect: Prototype.emptyFunction,
endeffect: Prototype.emptyFunction
});
},
setEvent: function() {
this.ids.each(function(idSet) {
Event.observe(idSet.tab, 'click', this.selectTab.bindAsEventListener(this));
Event.observe(idSet.tab, 'mouseover', this.onMouseOver.bindAsEventListener(this));
Event.observe(idSet.tab, 'mouseout', this.onMouseOut.bindAsEventListener(this));
if (this.options.closeButton) {
Event.observe(idSet.button, 'click', this.onRemove.bindAsEventListener(this));
}
}.bind(this));
},
appendElements: function() {
this.holder.each(function(set) {
$(this.tabTitleId + set.number).appendChild(set.tab);
this.panelList[set.number].appendChild(set.content);
}.bind(this));
},
build: function() {
var tabContainer =
"
";
var panelContainer =
"
";
var tabSetCount = 0;
$A(this.element.childNodes).each(function(node) {
if (Element.isElementNode(node)) {
var tabSet = this.buildTabSet(node, tabSetCount);
tabContainer += tabSet.tab;
panelContainer += tabSet.panel;
tabSetCount++;
}
}.bind(this));
tabContainer += "
";
panelContainer += "
";
this.element.innerHTML = tabContainer +
"" + panelContainer;
},
buildTabSet: function(element, i) {
var nodes = Element.getChildNodesWithoutWhitespace(element);
this.holdElements(nodes[0], nodes[1], i);
return {
tab: this.buildTab(nodes[0], i, Element.attributeHTML(element, 'onclick')),
panel: this.buildPanel(nodes[1], i)
};
},
buildTab: function(tab, i, events) {
var tabId = this.tabId + i;
var ids = {tab: tabId};
this.ids.push(ids);
this.tabs[i] = tabId;
var button = "";
if (this.options.closeButton) {
var buttonId = this.element.id.appendSuffix('closeButton_' + i);
ids.button = buttonId;
button = "";
}
var tabStyle = "";
if (this.options.tabRow && !isNaN(this.options.tabRow) && ((i % this.options.tabRow) == 0)) {
tabStyle = " style='clear: left; float: none;'";
}
var tabText = this.getTabText(tab).escapeHTML().replace(/"/g, '"');
this.setTabText(tab, this.chopTabText(tabText));
var html =
"";
return html;
},
setTabText: function(element, text) {
if (Element.isTextNode(element)) {
element.nodeValue = text;
} else if (Element.isElementNode(element)) {
element.innerHTML = text;
}
},
getTabText: function(element) {
if (Element.isTextNode(element)) {
textNode = element;
} else if (Element.isElementNode(element)) {
textNode = Element.getTextNodes(element, true)[0];
} else {
return '';
}
return textNode.nodeValue.replace(/(^(\s)*) | ((\s)*$)/, '');
},
chopTabText: function(title) {
if (this.options.titleLength && !isNaN(this.options.titleLength)) {
title = title.substring(0, this.options.titleLength);
}
return title;
},
buildPanel: function(panelContent, i) {
var id = this.panelId + i;
this.panelList[i] = id;
return "";
},
holdElements: function(tab, content, number) {
this.holder.push({number: number, tab: tab, content: content});
var tmpParent = document.createDocumentFragment();
tmpParent.appendChild(tab);
tmpParent.appendChild(content);
},
selectTab: function(e){
if (!this.options.beforeSelect()) return;
if (!e) {
this.setTabActive(this.tabs[this.selected]);
Element.show(this.panelList[this.selected]);
return;
}
var currentPanel = this.getCurrentPanel();
var currentTab = this.getCurrentTab();
var targetElement = null;
if (e.nodeType) {
targetElement = e;
} else {
targetElement = Event.element(e);
}
var targetIndex = this.getTargetIndex(targetElement);
if (targetIndex == this.selected) {
return;
}
var targetPanel = this.panelList[targetIndex];
var targetTab = this.tabs[targetIndex];
if (currentTab) this.setTabInactive(currentTab);
this.setTabActive(targetTab);
if (currentPanel) Element.toggle(currentPanel);
Element.toggle(targetPanel);
this.selected = targetIndex;
this.options.afterSelect(targetPanel, currentPanel);
if (!targetPanel.selected) {
this._callAfterSelectOnce(targetPanel);
targetPanel.selected = true;
}
},
setTabActive: function(tab) {
var tabChildren = tab.childNodes;
this.css.refreshClassNames(tabChildren[0], 'tabLeftActive');
this.css.refreshClassNames(tabChildren[1], 'tabMiddleActive');
this.css.refreshClassNames(tabChildren[2], 'tabRightActive');
},
setTabInactive: function(tab) {
var tabChildren = tab.childNodes;
this.css.refreshClassNames(tabChildren[0], 'tabLeftInactive');
this.css.refreshClassNames(tabChildren[1], 'tabMiddleInactive');
this.css.refreshClassNames(tabChildren[2], 'tabRightInactive');
},
getTargetIndex: function(element) {
while(element) {
if (element.id && element.id.indexOf(this.tabId, 0) >= 0) {
var index = element.id.substring(this.tabId.length);
if (!isNaN(index)) {
return index;
}
}
element = element.parentNode;
}
},
onRemove: function(event) {
Event.stop(event);
var element = Event.element(event);
var index = this.getTargetIndex(element);
var tab = this.tabs[index];
if (this.options.onRemove(tab)) {
this.remove(tab);
}
},
remove: function(tab) {
if (tab) {
var index = this.getTargetIndex(tab);
var nextActiveTab = this.getNextTab();
if (!nextActiveTab) nextActiveTab = this.getPreviousTab();
Element.remove(tab);
Element.remove(this.panelList[index]);
this.tabs[index] = null;
this.panelList[index] = null;
if (index == this.selected) {
if (nextActiveTab) {
this.selectTab(nextActiveTab);
}
}
}
},
addByElement: function(element) {
this.holder = [];
this.ids = [];
this.contents = [];
var tabSet = this.buildTabSet($(element), this.tabs.length);
this.tabContainer.appendChild(tabSet.tab.toElement());
this.panelContainer.appendChild(tabSet.panel.toElement());
this.tabs[this.tabs.length - 1] = $(this.tabs.last());
this.panelList[this.panelList.length - 1] = $(this.panelList.last());
this.setEvent();
this.appendElements();
if (this.options.sortable) this.setDrag();
},
add: function(title, content) {
var contents = [];
var node = Builder.node('div');
node.innerHTML = title;
contents.push(node);
node = Builder.node('div');
node.innerHTML = content;
contents.push(node);
this.addByElement(Builder.node('div', contents));
},
lazyLoad: function(index) {
this.errorCount = 0;
this.loadedList = [];
this.load(index);
},
load: function(index) {
var container = this.panelList[index];
var url = this.options.lazyLoadUrl[index];
var self = this;
if (container && url) {
new Ajax.Updater(
{success: container},
url,
{
onSuccess: function() {
self.setLoaded(index);
self.options.onLazyLoad(container, self);
self.load(++index);
if (self.isFinishLazyLoad()) self.options.afterLazyLoad(self);
},
onFailure: function() {
self.errorCount++;
self.options.lazyLoadFailure(container, self);
if (self.errorCount <= self.options.failureLimit) {
self.load(index);
} else {
self.options.failureLimitOver(self);
}
},
asynchronous: true,
evalScripts: true
}
);
}
},
isFinishLazyLoad: function() {
return this.loadedList.length == this.panelList.length;
},
setLoaded: function(i) {
this.loadedList.push(i);
},
onMouseOver: function(event) {
var targetElement = Event.element(event);
var targetIndex = this.getTargetIndex(targetElement);
if (targetIndex != this.selected) {
var targetTab = this.tabs[targetIndex];
this.setTabActive(targetTab);
}
},
onMouseOut: function(event) {
var targetElement = Event.element(event);
var targetIndex = this.getTargetIndex(targetElement);
if (targetIndex != this.selected) {
var targetTab = this.tabs[targetIndex];
this.setTabInactive(targetTab);
}
},
hasNextTab: function() {
return this.getNextTab() ? true : false;
},
hasPreviousTab: function() {
return this.getPreviousTab() ? true : false;
},
getNextTab: function() {
return Element.next(this.getCurrentTab());
},
getPreviousTab: function() {
return Element.previous(this.getCurrentTab());
},
selectNextTab: function() {
this.selectTab(this.getNextTab());
},
selectPreviousTab: function() {
this.selectTab(this.getPreviousTab());
},
tabCount: function() {
return this.tabs.inject(0, function(i, t) {
return t ? ++i : i;
})
},
getCurrentPanel: function() {
return this.panelList[this.selected];
},
getCurrentTab: function() {
return this.tabs[this.selected];
},
_callAfterSelectOnce: function(targetPanel) {
var func = this.options.afterSelectOnce;
if (!func) return;
if (func.constructor != Function) {
if (func.constructor == Array) {
func = func[this.panelList.indexOf(targetPanel)];
} else {
func = func[this.panelList.indexOf(targetPanel).succ()];
}
}
if (func) func(targetPanel);
}
}