All Downloads are FREE. Search and download functionalities are using the official Maven repository.

template.js.base.jquery.ui.accordion.js Maven / Gradle / Ivy

There is a newer version: 5.0.3
Show newest version
/*!
 * jQuery UI Accordion 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/accordion/
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 */
(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);
        }
    });

})(jQuery);




© 2015 - 2024 Weber Informatics LLC | Privacy Policy