Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
template.js.base.jquery.ui.tabs.js Maven / Gradle / Ivy
/*!
* jQuery UI Tabs 1.10.4
* http://jqueryui.com
*
* Copyright 2014 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/tabs/
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
*/
(function ($, undefined) {
var tabId = 0,
rhash = /#.*$/;
function getNextTabId() {
return ++tabId;
}
function isLocal(anchor) {
// support: IE7
// IE7 doesn't normalize the href property when set via script (#9317)
anchor = anchor.cloneNode(false);
return anchor.hash.length > 1 &&
decodeURIComponent(anchor.href.replace(rhash, "")) ===
decodeURIComponent(location.href.replace(rhash, ""));
}
$.widget("ui.tabs", {
version: "1.10.4",
delay: 300,
options: {
active: null,
collapsible: false,
event: "click",
heightStyle: "content",
hide: null,
show: null,
// callbacks
activate: null,
beforeActivate: null,
beforeLoad: null,
load: null
},
_create: function () {
var that = this,
options = this.options;
this.running = false;
this.element
.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all")
.toggleClass("ui-tabs-collapsible", options.collapsible)
// Prevent users from focusing disabled tabs via click
.delegate(".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function (event) {
if ($(this).is(".ui-state-disabled")) {
event.preventDefault();
}
})
// support: IE <9
// Preventing the default action in mousedown doesn't prevent IE
// from focusing the element, so if the anchor gets focused, blur.
// We don't have to worry about focusing the previously focused
// element since clicking on a non-focusable element should focus
// the body anyway.
.delegate(".ui-tabs-anchor", "focus" + this.eventNamespace, function () {
if ($(this).closest("li").is(".ui-state-disabled")) {
this.blur();
}
});
this._processTabs();
options.active = this._initialActive();
// Take disabling tabs via class attribute from HTML
// into account and update option properly.
if ($.isArray(options.disabled)) {
options.disabled = $.unique(options.disabled.concat(
$.map(this.tabs.filter(".ui-state-disabled"), function (li) {
return that.tabs.index(li);
})
)).sort();
}
// check for length avoids error when initializing empty list
if (this.options.active !== false && this.anchors.length) {
this.active = this._findActive(options.active);
} else {
this.active = $();
}
this._refresh();
if (this.active.length) {
this.load(options.active);
}
},
_initialActive: function () {
var active = this.options.active,
collapsible = this.options.collapsible,
locationHash = location.hash.substring(1);
if (active === null) {
// check the fragment identifier in the URL
if (locationHash) {
this.tabs.each(function (i, tab) {
if ($(tab).attr("aria-controls") === locationHash) {
active = i;
return false;
}
});
}
// check for a tab marked active via a class
if (active === null) {
active = this.tabs.index(this.tabs.filter(".ui-tabs-active"));
}
// no active tab, set to false
if (active === null || active === -1) {
active = this.tabs.length ? 0 : false;
}
}
// handle numbers: negative, out of range
if (active !== false) {
active = this.tabs.index(this.tabs.eq(active));
if (active === -1) {
active = collapsible ? false : 0;
}
}
// don't allow collapsible: false and active: false
if (!collapsible && active === false && this.anchors.length) {
active = 0;
}
return active;
},
_getCreateEventData: function () {
return {
tab: this.active,
panel: !this.active.length ? $() : this._getPanelForTab(this.active)
};
},
_tabKeydown: function (event) {
var focusedTab = $(this.document[0].activeElement).closest("li"),
selectedIndex = this.tabs.index(focusedTab),
goingForward = true;
if (this._handlePageNav(event)) {
return;
}
switch (event.keyCode) {
case $.ui.keyCode.RIGHT:
case $.ui.keyCode.DOWN:
selectedIndex++;
break;
case $.ui.keyCode.UP:
case $.ui.keyCode.LEFT:
goingForward = false;
selectedIndex--;
break;
case $.ui.keyCode.END:
selectedIndex = this.anchors.length - 1;
break;
case $.ui.keyCode.HOME:
selectedIndex = 0;
break;
case $.ui.keyCode.SPACE:
// Activate only, no collapsing
event.preventDefault();
clearTimeout(this.activating);
this._activate(selectedIndex);
return;
case $.ui.keyCode.ENTER:
// Toggle (cancel delayed activation, allow collapsing)
event.preventDefault();
clearTimeout(this.activating);
// Determine if we should collapse or activate
this._activate(selectedIndex === this.options.active ? false : selectedIndex);
return;
default:
return;
}
// Focus the appropriate tab, based on which key was pressed
event.preventDefault();
clearTimeout(this.activating);
selectedIndex = this._focusNextTab(selectedIndex, goingForward);
// Navigating with control key will prevent automatic activation
if (!event.ctrlKey) {
// Update aria-selected immediately so that AT think the tab is already selected.
// Otherwise AT may confuse the user by stating that they need to activate the tab,
// but the tab will already be activated by the time the announcement finishes.
focusedTab.attr("aria-selected", "false");
this.tabs.eq(selectedIndex).attr("aria-selected", "true");
this.activating = this._delay(function () {
this.option("active", selectedIndex);
}, this.delay);
}
},
_panelKeydown: function (event) {
if (this._handlePageNav(event)) {
return;
}
// Ctrl+up moves focus to the current tab
if (event.ctrlKey && event.keyCode === $.ui.keyCode.UP) {
event.preventDefault();
this.active.focus();
}
},
// Alt+page up/down moves focus to the previous/next tab (and activates)
_handlePageNav: function (event) {
if (event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP) {
this._activate(this._focusNextTab(this.options.active - 1, false));
return true;
}
if (event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN) {
this._activate(this._focusNextTab(this.options.active + 1, true));
return true;
}
},
_findNextTab: function (index, goingForward) {
var lastTabIndex = this.tabs.length - 1;
function constrain() {
if (index > lastTabIndex) {
index = 0;
}
if (index < 0) {
index = lastTabIndex;
}
return index;
}
while ($.inArray(constrain(), this.options.disabled) !== -1) {
index = goingForward ? index + 1 : index - 1;
}
return index;
},
_focusNextTab: function (index, goingForward) {
index = this._findNextTab(index, goingForward);
this.tabs.eq(index).focus();
return index;
},
_setOption: function (key, value) {
if (key === "active") {
// _activate() will handle invalid values and update this.options
this._activate(value);
return;
}
if (key === "disabled") {
// don't use the widget factory's disabled handling
this._setupDisabled(value);
return;
}
this._super(key, value);
if (key === "collapsible") {
this.element.toggleClass("ui-tabs-collapsible", value);
// Setting collapsible: false while collapsed; open first panel
if (!value && this.options.active === false) {
this._activate(0);
}
}
if (key === "event") {
this._setupEvents(value);
}
if (key === "heightStyle") {
this._setupHeightStyle(value);
}
},
_tabId: function (tab) {
return tab.attr("aria-controls") || "ui-tabs-" + getNextTabId();
},
_sanitizeSelector: function (hash) {
return hash ? hash.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&") : "";
},
refresh: function () {
var options = this.options,
lis = this.tablist.children(":has(a[href])");
// get disabled tabs from class attribute from HTML
// this will get converted to a boolean if needed in _refresh()
options.disabled = $.map(lis.filter(".ui-state-disabled"), function (tab) {
return lis.index(tab);
});
this._processTabs();
// was collapsed or no tabs
if (options.active === false || !this.anchors.length) {
options.active = false;
this.active = $();
// was active, but active tab is gone
} else if (this.active.length && !$.contains(this.tablist[ 0 ], this.active[ 0 ])) {
// all remaining tabs are disabled
if (this.tabs.length === options.disabled.length) {
options.active = false;
this.active = $();
// activate previous tab
} else {
this._activate(this._findNextTab(Math.max(0, options.active - 1), false));
}
// was active, active tab still exists
} else {
// make sure active index is correct
options.active = this.tabs.index(this.active);
}
this._refresh();
},
_refresh: function () {
this._setupDisabled(this.options.disabled);
this._setupEvents(this.options.event);
this._setupHeightStyle(this.options.heightStyle);
this.tabs.not(this.active).attr({
"aria-selected": "false",
tabIndex: -1
});
this.panels.not(this._getPanelForTab(this.active))
.hide()
.attr({
"aria-expanded": "false",
"aria-hidden": "true"
});
// Make sure one tab is in the tab order
if (!this.active.length) {
this.tabs.eq(0).attr("tabIndex", 0);
} else {
this.active
.addClass("ui-tabs-active ui-state-active")
.attr({
"aria-selected": "true",
tabIndex: 0
});
this._getPanelForTab(this.active)
.show()
.attr({
"aria-expanded": "true",
"aria-hidden": "false"
});
}
},
_processTabs: function () {
var that = this;
this.tablist = this._getList()
.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all")
.attr("role", "tablist");
this.tabs = this.tablist.find("> li:has(a[href])")
.addClass("ui-state-default ui-corner-top")
.attr({
role: "tab",
tabIndex: -1
});
this.anchors = this.tabs.map(function () {
return $("a", this)[ 0 ];
})
.addClass("ui-tabs-anchor")
.attr({
role: "presentation",
tabIndex: -1
});
this.panels = $();
this.anchors.each(function (i, anchor) {
var selector, panel, panelId,
anchorId = $(anchor).uniqueId().attr("id"),
tab = $(anchor).closest("li"),
originalAriaControls = tab.attr("aria-controls");
// inline tab
if (isLocal(anchor)) {
selector = anchor.hash;
panel = that.element.find(that._sanitizeSelector(selector));
// remote tab
} else {
panelId = that._tabId(tab);
selector = "#" + panelId;
panel = that.element.find(selector);
if (!panel.length) {
panel = that._createPanel(panelId);
panel.insertAfter(that.panels[ i - 1 ] || that.tablist);
}
panel.attr("aria-live", "polite");
}
if (panel.length) {
that.panels = that.panels.add(panel);
}
if (originalAriaControls) {
tab.data("ui-tabs-aria-controls", originalAriaControls);
}
tab.attr({
"aria-controls": selector.substring(1),
"aria-labelledby": anchorId
});
panel.attr("aria-labelledby", anchorId);
});
this.panels
.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom")
.attr("role", "tabpanel");
},
// allow overriding how to find the list for rare usage scenarios (#7715)
_getList: function () {
return this.tablist || this.element.find("ol,ul").eq(0);
},
_createPanel: function (id) {
return $("")
.attr("id", id)
.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom")
.data("ui-tabs-destroy", true);
},
_setupDisabled: function (disabled) {
if ($.isArray(disabled)) {
if (!disabled.length) {
disabled = false;
} else if (disabled.length === this.anchors.length) {
disabled = true;
}
}
// disable tabs
for (var i = 0, li; ( li = this.tabs[ i ] ); i++) {
if (disabled === true || $.inArray(i, disabled) !== -1) {
$(li)
.addClass("ui-state-disabled")
.attr("aria-disabled", "true");
} else {
$(li)
.removeClass("ui-state-disabled")
.removeAttr("aria-disabled");
}
}
this.options.disabled = disabled;
},
_setupEvents: function (event) {
var events = {
click: function (event) {
event.preventDefault();
}
};
if (event) {
$.each(event.split(" "), function (index, eventName) {
events[ eventName ] = "_eventHandler";
});
}
this._off(this.anchors.add(this.tabs).add(this.panels));
this._on(this.anchors, events);
this._on(this.tabs, { keydown: "_tabKeydown" });
this._on(this.panels, { keydown: "_panelKeydown" });
this._focusable(this.tabs);
this._hoverable(this.tabs);
},
_setupHeightStyle: function (heightStyle) {
var maxHeight,
parent = this.element.parent();
if (heightStyle === "fill") {
maxHeight = parent.height();
maxHeight -= this.element.outerHeight() - this.element.height();
this.element.siblings(":visible").each(function () {
var elem = $(this),
position = elem.css("position");
if (position === "absolute" || position === "fixed") {
return;
}
maxHeight -= elem.outerHeight(true);
});
this.element.children().not(this.panels).each(function () {
maxHeight -= $(this).outerHeight(true);
});
this.panels.each(function () {
$(this).height(Math.max(0, maxHeight -
$(this).innerHeight() + $(this).height()));
})
.css("overflow", "auto");
} else if (heightStyle === "auto") {
maxHeight = 0;
this.panels.each(function () {
maxHeight = Math.max(maxHeight, $(this).height("").height());
}).height(maxHeight);
}
},
_eventHandler: function (event) {
var options = this.options,
active = this.active,
anchor = $(event.currentTarget),
tab = anchor.closest("li"),
clickedIsActive = tab[ 0 ] === active[ 0 ],
collapsing = clickedIsActive && options.collapsible,
toShow = collapsing ? $() : this._getPanelForTab(tab),
toHide = !active.length ? $() : this._getPanelForTab(active),
eventData = {
oldTab: active,
oldPanel: toHide,
newTab: collapsing ? $() : tab,
newPanel: toShow
};
event.preventDefault();
if (tab.hasClass("ui-state-disabled") ||
// tab is already loading
tab.hasClass("ui-tabs-loading") ||
// can't switch durning an animation
this.running ||
// click on active header, but not collapsible
( clickedIsActive && !options.collapsible ) ||
// allow canceling activation
( this._trigger("beforeActivate", event, eventData) === false )) {
return;
}
options.active = collapsing ? false : this.tabs.index(tab);
this.active = clickedIsActive ? $() : tab;
if (this.xhr) {
this.xhr.abort();
}
if (!toHide.length && !toShow.length) {
$.error("jQuery UI Tabs: Mismatching fragment identifier.");
}
if (toShow.length) {
this.load(this.tabs.index(tab), event);
}
this._toggle(event, eventData);
},
// handles show/hide for selecting tabs
_toggle: function (event, eventData) {
var that = this,
toShow = eventData.newPanel,
toHide = eventData.oldPanel;
this.running = true;
function complete() {
that.running = false;
that._trigger("activate", event, eventData);
}
function show() {
eventData.newTab.closest("li").addClass("ui-tabs-active ui-state-active");
if (toShow.length && that.options.show) {
that._show(toShow, that.options.show, complete);
} else {
toShow.show();
complete();
}
}
// start out by hiding, then showing, then completing
if (toHide.length && this.options.hide) {
this._hide(toHide, this.options.hide, function () {
eventData.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");
show();
});
} else {
eventData.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");
toHide.hide();
show();
}
toHide.attr({
"aria-expanded": "false",
"aria-hidden": "true"
});
eventData.oldTab.attr("aria-selected", "false");
// If we're switching tabs, remove the old tab from the tab order.
// If we're opening from collapsed state, remove the previous tab from the tab order.
// If we're collapsing, then keep the collapsing tab in the tab order.
if (toShow.length && toHide.length) {
eventData.oldTab.attr("tabIndex", -1);
} else if (toShow.length) {
this.tabs.filter(function () {
return $(this).attr("tabIndex") === 0;
})
.attr("tabIndex", -1);
}
toShow.attr({
"aria-expanded": "true",
"aria-hidden": "false"
});
eventData.newTab.attr({
"aria-selected": "true",
tabIndex: 0
});
},
_activate: function (index) {
var anchor,
active = this._findActive(index);
// trying to activate the already active panel
if (active[ 0 ] === this.active[ 0 ]) {
return;
}
// trying to collapse, simulate a click on the current active header
if (!active.length) {
active = this.active;
}
anchor = active.find(".ui-tabs-anchor")[ 0 ];
this._eventHandler({
target: anchor,
currentTarget: anchor,
preventDefault: $.noop
});
},
_findActive: function (index) {
return index === false ? $() : this.tabs.eq(index);
},
_getIndex: function (index) {
// meta-function to give users option to provide a href string instead of a numerical index.
if (typeof index === "string") {
index = this.anchors.index(this.anchors.filter("[href$='" + index + "']"));
}
return index;
},
_destroy: function () {
if (this.xhr) {
this.xhr.abort();
}
this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible");
this.tablist
.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all")
.removeAttr("role");
this.anchors
.removeClass("ui-tabs-anchor")
.removeAttr("role")
.removeAttr("tabIndex")
.removeUniqueId();
this.tabs.add(this.panels).each(function () {
if ($.data(this, "ui-tabs-destroy")) {
$(this).remove();
} else {
$(this)
.removeClass("ui-state-default ui-state-active ui-state-disabled " +
"ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel")
.removeAttr("tabIndex")
.removeAttr("aria-live")
.removeAttr("aria-busy")
.removeAttr("aria-selected")
.removeAttr("aria-labelledby")
.removeAttr("aria-hidden")
.removeAttr("aria-expanded")
.removeAttr("role");
}
});
this.tabs.each(function () {
var li = $(this),
prev = li.data("ui-tabs-aria-controls");
if (prev) {
li
.attr("aria-controls", prev)
.removeData("ui-tabs-aria-controls");
} else {
li.removeAttr("aria-controls");
}
});
this.panels.show();
if (this.options.heightStyle !== "content") {
this.panels.css("height", "");
}
},
enable: function (index) {
var disabled = this.options.disabled;
if (disabled === false) {
return;
}
if (index === undefined) {
disabled = false;
} else {
index = this._getIndex(index);
if ($.isArray(disabled)) {
disabled = $.map(disabled, function (num) {
return num !== index ? num : null;
});
} else {
disabled = $.map(this.tabs, function (li, num) {
return num !== index ? num : null;
});
}
}
this._setupDisabled(disabled);
},
disable: function (index) {
var disabled = this.options.disabled;
if (disabled === true) {
return;
}
if (index === undefined) {
disabled = true;
} else {
index = this._getIndex(index);
if ($.inArray(index, disabled) !== -1) {
return;
}
if ($.isArray(disabled)) {
disabled = $.merge([ index ], disabled).sort();
} else {
disabled = [ index ];
}
}
this._setupDisabled(disabled);
},
load: function (index, event) {
index = this._getIndex(index);
var that = this,
tab = this.tabs.eq(index),
anchor = tab.find(".ui-tabs-anchor"),
panel = this._getPanelForTab(tab),
eventData = {
tab: tab,
panel: panel
};
// not remote
if (isLocal(anchor[ 0 ])) {
return;
}
this.xhr = $.ajax(this._ajaxSettings(anchor, event, eventData));
// support: jQuery <1.8
// jQuery <1.8 returns false if the request is canceled in beforeSend,
// but as of 1.8, $.ajax() always returns a jqXHR object.
if (this.xhr && this.xhr.statusText !== "canceled") {
tab.addClass("ui-tabs-loading");
panel.attr("aria-busy", "true");
this.xhr
.success(function (response) {
// support: jQuery <1.8
// http://bugs.jquery.com/ticket/11778
setTimeout(function () {
panel.html(response);
that._trigger("load", event, eventData);
}, 1);
})
.complete(function (jqXHR, status) {
// support: jQuery <1.8
// http://bugs.jquery.com/ticket/11778
setTimeout(function () {
if (status === "abort") {
that.panels.stop(false, true);
}
tab.removeClass("ui-tabs-loading");
panel.removeAttr("aria-busy");
if (jqXHR === that.xhr) {
delete that.xhr;
}
}, 1);
});
}
},
_ajaxSettings: function (anchor, event, eventData) {
var that = this;
return {
url: anchor.attr("href"),
beforeSend: function (jqXHR, settings) {
return that._trigger("beforeLoad", event,
$.extend({ jqXHR: jqXHR, ajaxSettings: settings }, eventData));
}
};
},
_getPanelForTab: function (tab) {
var id = $(tab).attr("aria-controls");
return this.element.find(this._sanitizeSelector("#" + id));
}
});
})(jQuery);