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

META-INF.resources.primefaces.forms.forms.selectmanymenu.js Maven / Gradle / Ivy

There is a newer version: 7.0
Show newest version
/**
 * __PrimeFaces SelectManyMenu Widget__
 * 
 * SelectManyMenu is an extended version of the standard SelectManyMenu.
 * 
 * @interface {PrimeFaces.widget.SelectManyMenuCfg} cfg The configuration for the {@link  SelectManyMenu| SelectManyMenu widget}.
 * You can access this configuration via {@link PrimeFaces.widget.BaseWidget.cfg|BaseWidget.cfg}. Please note that this
 * configuration is usually meant to be read-only and should not be modified.
 * @extends {PrimeFaces.widget.SelectListboxCfg} cfg
 * 
 * @prop {JQuery} [cursorItem] The last clicked item, used for selecting a range by holding down the shift
 * key. 
 * @prop {boolean} [checkboxClick] Whether a checkbox of the select menu was clicked. Reset after the list
 * box was clicked.
 * @prop {JQuery} [checkboxes] DOM elements of the checkboxes, if checkboxes are enabled.
 * 
 * @prop {boolean} cfg.disabled Whether the select many menu is initially disabled.
 * @prop {boolean} cfg.metaKeySelection Whether the meta key (`SHIFT` or `CTRL`) must be held down to select multiple
 * items.
 * @prop {boolean} cfg.showCheckbox When set to `true`, a checkbox is displayed next to each item.
 */
PrimeFaces.widget.SelectManyMenu = PrimeFaces.widget.SelectListbox.extend({

    /**
     * @override
     * @inheritdoc
     * @param {PrimeFaces.PartialWidgetCfg} cfg
     */
    init: function(cfg) {
        this._super(cfg);
        this.cfg.metaKeySelection = this.cfg.metaKeySelection != undefined ? this.cfg.metaKeySelection : true;

        this.allItems.filter('.ui-state-highlight').find('> .ui-chkbox > .ui-chkbox-box').addClass('ui-state-active');
        // Checkbox is inside TD element when using custom content
        this.allItems.filter('.ui-state-highlight').find('> td > .ui-chkbox > .ui-chkbox-box').addClass('ui-state-active');
    },

    /**
     * @override
     * @protected
     * @inheritdoc
     */
    bindEvents: function() {
        this._super();
        var $this = this;

        if (!this.cfg.disabled) {
            this.items.off().on('click.selectListbox', function(e) {
                //stop propagation
                if ($this.checkboxClick) {
                    $this.checkboxClick = false;
                    return;
                }

                var item = $(this),
                    metaKey = $this.cfg.metaKeySelection && (e.metaKey || e.ctrlKey);

                if (!e.shiftKey) {
                    if (!metaKey && !$this.cfg.showCheckbox) {
                        $this.unselectAll();
                    }

                    if ((metaKey || $this.cfg.showCheckbox) && item.hasClass('ui-state-highlight')) {
                        $this.unselectItem(item);
                    }
                    else {
                        $this.selectItem(item);
                        $this.cursorItem = item;
                    }
                }
                else {
                    //range selection
                    if ($this.cursorItem) {
                        $this.unselectAll();

                        var currentItemIndex = item.index(),
                            cursorItemIndex = $this.cursorItem.index(),
                            startIndex = (currentItemIndex > cursorItemIndex) ? cursorItemIndex : currentItemIndex,
                            endIndex = (currentItemIndex > cursorItemIndex) ? (currentItemIndex + 1) : (cursorItemIndex + 1);

                        for (var i = startIndex; i < endIndex; i++) {
                            var it = $this.allItems.eq(i);

                            if (it.is(':visible') && !it.hasClass('ui-state-disabled')) {
                                $this.selectItem(it);
                            }
                        }
                    }
                    else {
                        $this.selectItem(item);
                        $this.cursorItem = item;
                    }
                }

                $this.input.trigger('change');
                $this.input.trigger('click');
                PrimeFaces.clearSelection();
                e.preventDefault();
            }).on('keydown.selectListbox', function(event) {
                $this.onKeyDown(event);
            });

            if (this.cfg.showCheckbox) {
                this.checkboxes = this.jq.find('.ui-selectlistbox-item:not(.ui-state-disabled) div.ui-chkbox > div.ui-chkbox-box');

                this.checkboxes.on('mouseenter.selectManyMenu', function(e) {
                    $(this).addClass('ui-state-hover');
                })
                    .on('mouseleave.selectManyMenu', function(e) {
                        $(this).removeClass('ui-state-hover');
                    })
                    .on('click.selectManyMenu', function(e) {
                        $this.checkboxClick = true;

                        var item = $(this).closest('.ui-selectlistbox-item');
                        if (item.hasClass('ui-state-highlight'))
                            $this.unselectItem(item);
                        else
                            $this.selectItem(item);

                        $this.input.trigger('change');
                    });
            }
        }
    },

    /**
     * Handle keyboard events.
     * @param {Event} event the DOM onKeyDown event
     * @private
     */
    onKeyDown: function(event) {
        var $this = this,
            item = $(event.currentTarget),
            isMetaKey = (event.metaKey || event.ctrlKey),
            metaKey = this.cfg.metaKeySelection && isMetaKey;

        switch (event.code) {
            case 'Enter':
            case 'NumpadEnter':
            case 'Space':
                if (!metaKey && !$this.cfg.showCheckbox) {
                    $this.unselectAll();
                }

                if ((metaKey || $this.cfg.showCheckbox) && item.hasClass('ui-state-highlight')) {
                    $this.unselectItem(item);
                }
                else {
                    $this.selectItem(item);
                    $this.cursorItem = item;
                }
                event.preventDefault();
                break;
            case 'KeyA':
                if (metaKey) $this.selectAll();
                event.preventDefault();
                break;
            case 'KeyD':
                if (metaKey) $this.unselectAll();
                event.preventDefault();
                break;
            case 'ArrowUp':
            case 'ArrowDown':
                if (!event.shiftKey) {
                    var newItem = event.key === 'ArrowDown' ? item.next() : item.prev();
                    if (!newItem.hasClass('ui-selectlistbox-item')) {
                        return;
                    }
                    $this.focus(newItem);
                }
                event.preventDefault();
                break;
            case 'Home':
            case 'PageUp':
                $this.focus($this.items.first());
                event.preventDefault();
                break;
            case 'End':
            case 'PageDown':
                $this.focus($this.items.last());
                event.preventDefault();
                break;
        }
    },

    /**
     * Focus the item.
     * @param {JQuery} item The item to focus.
     */
    focus: function(item) {
        this.cursorItem = item;
        item.trigger('focus');
    },

    /**
     * Selects all available items of this select many menu.
     */
    selectAll: function() {
        // ~~~ PERF ~~~
        // See https://github.com/primefaces/primefaces/issues/2089
        //
        // 1) don't use jquery wrappers
        // 2) don't use existing methods like selectItem
        var filteredItems = this.items.filter(":visible");

        for (var i = 0; i < filteredItems.length; i++) {
            var item = filteredItems.eq(i);
            var itemNative = item[0];

            itemNative.classList.add('ui-state-highlight');
            itemNative.classList.remove('ui-state-hover');
            itemNative.setAttribute('aria-selected', 'true');

            if (this.cfg.showCheckbox) {
                var checkbox = item.find('div.ui-chkbox').children('div.ui-chkbox-box');

                var checkboxNative = checkbox[0];
                checkboxNative.classList.remove('ui-state-hover');
                checkboxNative.classList.add('ui-state-active');

                var checkboxIconNative = checkbox.children('span.ui-chkbox-icon')[0];
                checkboxIconNative.classList.remove('ui-icon-blank');
                checkboxIconNative.classList.add('ui-icon-check');
            }
        }

        for (var j = 0; j < this.options.length; j++) {
            this.options[j].selected = true;
        }
    },

    /**
     * @override
     * @inheritdoc
     */
    unselectAll: function() {
        // ~~~ PERF ~~~
        // See https://github.com/primefaces/primefaces/issues/2089
        //
        // 1) don't use jquery wrappers
        // 2) don't use existing methods like unselectItem
        var filteredItems = this.items.filter(":visible");

        for (var i = 0; i < filteredItems.length; i++) {
            var item = filteredItems.eq(i);
            var itemNative = item[0];

            itemNative.classList.remove('ui-state-highlight');
            itemNative.setAttribute('aria-selected', 'false');

            if (this.cfg.showCheckbox) {
                var checkbox = item.find('div.ui-chkbox').children('div.ui-chkbox-box');

                var checkboxNative = checkbox[0];
                checkboxNative.classList.remove('ui-state-active');

                var checkboxIconNative = checkbox.children('span.ui-chkbox-icon')[0];
                checkboxIconNative.classList.add('ui-icon-blank');
                checkboxIconNative.classList.remove('ui-icon-check');
            }
        }

        for (var j = 0; j < this.options.length; j++) {
            this.options[j].selected = false;
        }
    },

    /**
     * @override
     * @inheritdoc
     * @param {JQuery} item
     */
    selectItem: function(item) {
        this._super(item);

        if (this.cfg.showCheckbox) {
            this.selectCheckbox(item.find('div.ui-chkbox-box'));
        }
    },

    /**
     * @override
     * @inheritdoc
     * @param {JQuery} item
     */
    unselectItem: function(item) {
        this._super(item);

        if (this.cfg.showCheckbox) {
            this.unselectCheckbox(item.find('div.ui-chkbox-box'));
        }
    },

    /**
     * Select the given checkbox. Does not unselect any other checkboxes that are currently selected.
     * @param {JQuery} chkbox A CHECKBOX element to select.
     */
    selectCheckbox: function(chkbox) {
        chkbox.addClass('ui-state-active').children('span.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check');
    },

    /**
     * Unselects the given checkbox. Does not modify any other checkboxes.
     * @param {JQuery} chkbox A CHECKBOX element to unselect.
     */
    unselectCheckbox: function(chkbox) {
        chkbox.removeClass('ui-state-active').children('span.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check');
    }
});




© 2015 - 2025 Weber Informatics LLC | Privacy Policy