/*! * jQuery UI Accordion - v1.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/accordion/ */ define([ 'jquery', 'jquery-ui-modules/core', 'jquery-ui-modules/widget' ], function ($, undefined) { var uid = 0, hideProps = {}, showProps = {}; hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; showProps.height = showProps.paddingTop = showProps.paddingBottom = showProps.borderTopWidth = showProps.borderBottomWidth = "show"; $.widget("ui.accordion", { version: "1.10.4", options: { active: 0, animate: {}, collapsible: false, event: "click", header: "> li > :first-child,> :not(li):even", heightStyle: "auto", icons: { activeHeader: "ui-icon-triangle-1-s", header: "ui-icon-triangle-1-e" }, // callbacks activate: null, beforeActivate: null }, _create: function () { var options = this.options; this.prevShow = this.prevHide = $(); this.element.addClass("ui-accordion ui-widget ui-helper-reset") // ARIA .attr("role", "tablist"); // don't allow collapsible: false and active: false / null if (!options.collapsible && (options.active === false || options.active == null)) { options.active = 0; } this._processPanels(); // handle negative values if (options.active < 0) { options.active += this.headers.length; } this._refresh(); }, _getCreateEventData: function () { return { header: this.active, panel: !this.active.length ? $() : this.active.next(), content: !this.active.length ? $() : this.active.next() }; }, _createIcons: function () { var icons = this.options.icons; if (icons) { $("") .addClass("ui-accordion-header-icon ui-icon " + icons.header) .prependTo(this.headers); this.active.children(".ui-accordion-header-icon") .removeClass(icons.header) .addClass(icons.activeHeader); this.headers.addClass("ui-accordion-icons"); } }, _destroyIcons: function () { this.headers .removeClass("ui-accordion-icons") .children(".ui-accordion-header-icon") .remove(); }, _destroy: function () { var contents; // clean up main element this.element .removeClass("ui-accordion ui-widget ui-helper-reset") .removeAttr("role"); // clean up headers this.headers .removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top") .removeAttr("role") .removeAttr("aria-expanded") .removeAttr("aria-selected") .removeAttr("aria-controls") .removeAttr("tabIndex") .each(function () { if (/^ui-accordion/.test(this.id)) { this.removeAttribute("id"); } }); this._destroyIcons(); // clean up content panels contents = this.headers.next() .css("display", "") .removeAttr("role") .removeAttr("aria-hidden") .removeAttr("aria-labelledby") .removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled") .each(function () { if (/^ui-accordion/.test(this.id)) { this.removeAttribute("id"); } }); if (this.options.heightStyle !== "content") { contents.css("height", ""); } }, _setOption: function (key, value) { if (key === "active") { // _activate() will handle invalid values and update this.options this._activate(value); return; } if (key === "event") { if (this.options.event) { this._off(this.headers, this.options.event); } this._setupEvents(value); } this._super(key, value); // setting collapsible: false while collapsed; open first panel if (key === "collapsible" && !value && this.options.active === false) { this._activate(0); } if (key === "icons") { this._destroyIcons(); if (value) { this._createIcons(); } } // #5332 - opacity doesn't cascade to positioned elements in IE // so we need to add the disabled class to the headers and panels if (key === "disabled") { this.headers.add(this.headers.next()) .toggleClass("ui-state-disabled", !!value); } }, _keydown: function (event) { if (event.altKey || event.ctrlKey) { return; } var keyCode = $.ui.keyCode, length = this.headers.length, currentIndex = this.headers.index(event.target), toFocus = false; switch (event.keyCode) { case keyCode.RIGHT: case keyCode.DOWN: toFocus = this.headers[(currentIndex + 1) % length]; break; case keyCode.LEFT: case keyCode.UP: toFocus = this.headers[(currentIndex - 1 + length) % length]; break; case keyCode.SPACE: case keyCode.ENTER: this._eventHandler(event); break; case keyCode.HOME: toFocus = this.headers[0]; break; case keyCode.END: toFocus = this.headers[length - 1]; break; } if (toFocus) { $(event.target).attr("tabIndex", -1); $(toFocus).attr("tabIndex", 0); toFocus.focus(); event.preventDefault(); } }, _panelKeyDown: function (event) { if (event.keyCode === $.ui.keyCode.UP && event.ctrlKey) { $(event.currentTarget).prev().focus(); } }, refresh: function () { var options = this.options; this._processPanels(); // was collapsed or no panel if ((options.active === false && options.collapsible === true) || !this.headers.length) { options.active = false; this.active = $(); // active false only when collapsible is true } else if (options.active === false) { this._activate(0); // was active, but active panel is gone } else if (this.active.length && !$.contains(this.element[0], this.active[0])) { // all remaining panel are disabled if (this.headers.length === this.headers.find(".ui-state-disabled").length) { options.active = false; this.active = $(); // activate previous panel } else { this._activate(Math.max(0, options.active - 1)); } // was active, active panel still exists } else { // make sure active index is correct options.active = this.headers.index(this.active); } this._destroyIcons(); this._refresh(); }, _processPanels: function () { this.headers = this.element.find(this.options.header) .addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"); this.headers.next() .addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom") .filter(":not(.ui-accordion-content-active)") .hide(); }, _refresh: function () { var maxHeight, options = this.options, heightStyle = options.heightStyle, parent = this.element.parent(), accordionId = this.accordionId = "ui-accordion-" + (this.element.attr("id") || ++uid); this.active = this._findActive(options.active) .addClass("ui-accordion-header-active ui-state-active ui-corner-top") .removeClass("ui-corner-all"); this.active.next() .addClass("ui-accordion-content-active") .show(); this.headers .attr("role", "tab") .each(function (i) { var header = $(this), headerId = header.attr("id"), panel = header.next(), panelId = panel.attr("id"); if (!headerId) { headerId = accordionId + "-header-" + i; header.attr("id", headerId); } if (!panelId) { panelId = accordionId + "-panel-" + i; panel.attr("id", panelId); } header.attr("aria-controls", panelId); panel.attr("aria-labelledby", headerId); }) .next() .attr("role", "tabpanel"); this.headers .not(this.active) .attr({ "aria-selected": "false", "aria-expanded": "false", tabIndex: -1 }) .next() .attr({ "aria-hidden": "true" }) .hide(); // make sure at least one header is in the tab order if (!this.active.length) { this.headers.eq(0).attr("tabIndex", 0); } else { this.active.attr({ "aria-selected": "true", "aria-expanded": "true", tabIndex: 0 }) .next() .attr({ "aria-hidden": "false" }); } this._createIcons(); this._setupEvents(options.event); if (heightStyle === "fill") { maxHeight = parent.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.headers.each(function () { maxHeight -= $(this).outerHeight(true); }); this.headers.next() .each(function () { $(this).height(Math.max(0, maxHeight - $(this).innerHeight() + $(this).height())); }) .css("overflow", "auto"); } else if (heightStyle === "auto") { maxHeight = 0; this.headers.next() .each(function () { maxHeight = Math.max(maxHeight, $(this).css("height", "").height()); }) .height(maxHeight); } }, _activate: function (index) { var active = this._findActive(index)[0]; // trying to activate the already active panel if (active === this.active[0]) { return; } // trying to collapse, simulate a click on the currently active header active = active || this.active[0]; this._eventHandler({ target: active, currentTarget: active, preventDefault: $.noop }); }, _findActive: function (selector) { return typeof selector === "number" ? this.headers.eq(selector) : $(); }, _setupEvents: function (event) { var events = { keydown: "_keydown" }; if (event) { $.each(event.split(" "), function (index, eventName) { events[eventName] = "_eventHandler"; }); } this._off(this.headers.add(this.headers.next())); this._on(this.headers, events); this._on(this.headers.next(), {keydown: "_panelKeyDown"}); this._hoverable(this.headers); this._focusable(this.headers); }, _eventHandler: function (event) { var options = this.options, active = this.active, clicked = $(event.currentTarget), clickedIsActive = clicked[0] === active[0], collapsing = clickedIsActive && options.collapsible, toShow = collapsing ? $() : clicked.next(), toHide = active.next(), eventData = { oldHeader: active, oldPanel: toHide, newHeader: collapsing ? $() : clicked, newPanel: toShow }; event.preventDefault(); if ( // 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.headers.index(clicked); // when the call to ._toggle() comes after the class changes // it causes a very odd bug in IE 8 (see #6720) this.active = clickedIsActive ? $() : clicked; this._toggle(eventData); // switch classes // corner classes on the previously active header stay after the animation active.removeClass("ui-accordion-header-active ui-state-active"); if (options.icons) { active.children(".ui-accordion-header-icon") .removeClass(options.icons.activeHeader) .addClass(options.icons.header); } if (!clickedIsActive) { clicked .removeClass("ui-corner-all") .addClass("ui-accordion-header-active ui-state-active ui-corner-top"); if (options.icons) { clicked.children(".ui-accordion-header-icon") .removeClass(options.icons.header) .addClass(options.icons.activeHeader); } clicked .next() .addClass("ui-accordion-content-active"); } }, _toggle: function (data) { var toShow = data.newPanel, toHide = this.prevShow.length ? this.prevShow : data.oldPanel; // handle activating a panel during the animation for another activation this.prevShow.add(this.prevHide).stop(true, true); this.prevShow = toShow; this.prevHide = toHide; if (this.options.animate) { this._animate(toShow, toHide, data); } else { toHide.hide(); toShow.show(); this._toggleComplete(data); } toHide.attr({ "aria-hidden": "true" }); toHide.prev().attr("aria-selected", "false"); // if we're switching panels, remove the old header from the tab order // if we're opening from collapsed state, remove the previous header from the tab order // if we're collapsing, then keep the collapsing header in the tab order if (toShow.length && toHide.length) { toHide.prev().attr({ "tabIndex": -1, "aria-expanded": "false" }); } else if (toShow.length) { this.headers.filter(function () { return $(this).attr("tabIndex") === 0; }) .attr("tabIndex", -1); } toShow .attr("aria-hidden", "false") .prev() .attr({ "aria-selected": "true", tabIndex: 0, "aria-expanded": "true" }); }, _animate: function (toShow, toHide, data) { var total, easing, duration, that = this, adjust = 0, down = toShow.length && (!toHide.length || (toShow.index() < toHide.index())), animate = this.options.animate || {}, options = down && animate.down || animate, complete = function () { that._toggleComplete(data); }; if (typeof options === "number") { duration = options; } if (typeof options === "string") { easing = options; } // fall back from options to animation in case of partial down settings easing = easing || options.easing || animate.easing; duration = duration || options.duration || animate.duration; if (!toHide.length) { return toShow.animate(showProps, duration, easing, complete); } if (!toShow.length) { return toHide.animate(hideProps, duration, easing, complete); } total = toShow.show().outerHeight(); toHide.animate(hideProps, { duration: duration, easing: easing, step: function (now, fx) { fx.now = Math.round(now); } }); toShow .hide() .animate(showProps, { duration: duration, easing: easing, complete: complete, step: function (now, fx) { fx.now = Math.round(now); if (fx.prop !== "height") { adjust += fx.now; } else if (that.options.heightStyle !== "content") { fx.now = Math.round(total - toHide.outerHeight() - adjust); adjust = 0; } } }); }, _toggleComplete: function (data) { var toHide = data.oldPanel; toHide .removeClass("ui-accordion-content-active") .prev() .removeClass("ui-corner-top") .addClass("ui-corner-all"); // Work around for rendering bug in IE (#5421) if (toHide.length) { toHide.parent()[0].className = toHide.parent()[0].className; } this._trigger("activate", null, data); } }); });