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

META-INF.resources.primefaces.columntoggler.columntoggler.js Maven / Gradle / Ivy

/**
 * __PrimeFaces ColumnToggler Widget__
 *
 * ColumnToggler is a helper component for the data table to toggle visibility of columns.
 *
 * @prop {JQuery} [closer] DOM element of the close button for closing the overlay with the available columns.
 * @prop {JQuery} [columns] DOM elements for the `TH` columns of the data table.
 * @prop {JQuery} [itemContainer] DOM elements for the `UL` items in the overlay with the available columns.
 * @prop {number} [frozenColumnCount] The number of frozen column of table to which this column toggle is
 * attached.
 * @prop {boolean} hasFrozenColumn Whether the table to which this column toggle is attached has got any frozen columns.
 * @prop {boolean} [hasPriorityColumns] Whether any prioritized columns exist. Used for responsive mode. 
 * @prop {boolean} hasStickyHeader Whether the table to which this column toggle is attached has got a sticky header.
 * @prop {JQuery} [panel] Overlay column toggler panel with the available columns.
 * @prop {JQuery} table Table to which this column toggle is attached.
 * @prop {string} tableId ID of the table to which this column toggle is attached.
 * @prop {JQuery} tbody The DOM element for the table body of the table to which this column toggle is attached.
 * @prop {JQuery} tfoot The DOM element for the table foot of the table to which this column toggle is attached.
 * @prop {JQuery} thead The DOM element for the table head of the table to which this column toggle is attached.
 * @prop {string[]} [togglerState] IDs of the columns that are selected.
 * @prop {JQuery} [togglerStateHolder] DOM element of the hidden input that contains the columns that are
 * selected. Used to preserve that state between AJAX updates.
 * @prop {JQuery} trigger Button that toggles this column toggler.
 * @prop {boolean} visible Whether this column toggler is currently displayed.
 * @prop {boolean} [widthAligned] Whether the width of the overlay panel with the available columns was
 * aligned with the width of the toggler.    
 *
 * @interface {PrimeFaces.widget.ColumnTogglerCfg} cfg The configuration for the
 * {@link  ColumnToggler| ColumnToggler 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.DeferredWidgetCfg} cfg
 *
 * @prop {string} cfg.trigger ID of the button that toggles this column toggler.
 * @prop {string} cfg.datasource ID of the component (table) to which this column toggler is attached.
 */
PrimeFaces.widget.ColumnToggler = PrimeFaces.widget.DeferredWidget.extend({

    /**
     * @override
     * @inheritdoc
     * @param {PrimeFaces.PartialWidgetCfg} cfg
     */
    init: function(cfg) {
        this._super(cfg);
        this.table = PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.datasource);
        this.trigger = PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.trigger);
        this.tableId = this.table.attr('id');
        this.hasFrozenColumn = this.table.hasClass('ui-datatable-frozencolumn');
        this.hasStickyHeader = this.table.hasClass('ui-datatable-sticky');
        var clientId = PrimeFaces.escapeClientId(this.tableId);

        if (this.hasFrozenColumn) {
            this.thead = $(clientId + '_frozenThead,' + clientId + '_scrollableThead');
            this.tbody = $(clientId + '_frozenTbody,' + clientId + '_scrollableTbody');
            this.tfoot = $(clientId + '_frozenTfoot,' + clientId + '_scrollableTfoot');
            this.frozenColumnCount = this.thead.eq(0).find('th').length;
        }
        else {
            this.thead = $(clientId + '_head');
            this.tbody = $(clientId + '_data');
            this.tfoot = $(clientId + '_foot');
        }
        this.visible = false;

        this.render();
        this.bindEvents();
    },

    /**
     * @override
     * @inheritdoc
     * @param {PrimeFaces.PartialWidgetCfg} cfg
     */
    refresh: function(cfg) {
        var jqs = $('[id=' + cfg.id.replace(/:/g, "\\:") + ']');
        if (jqs.length > 1) {
            $(document.body).children(this.jqId).remove();
        }

        this.widthAligned = false;

        this._super(cfg);
    },

    /**
     * @override
     * @inheritdoc
     */
    render: function() {
        this.columns = this.thead.find('> tr > th:not(.ui-static-column)');
        this.panel = $(PrimeFaces.escapeClientId(this.cfg.id)).attr('role', 'dialog').addClass('ui-columntoggler ui-widget ui-widget-content ui-shadow ui-corner-all')
            .append('
    ').appendTo(document.body); this.itemContainer = this.panel.children('ul'); var stateHolderId = this.tableId + "_columnTogglerState"; this.togglerStateHolder = $(''); this.table.append(this.togglerStateHolder); this.togglerState = []; //items for (var i = 0; i < this.columns.length; i++) { var column = this.columns.eq(i), hidden = column.hasClass('ui-helper-hidden'), boxClass = hidden ? 'ui-chkbox-box ui-widget ui-corner-all ui-state-default' : 'ui-chkbox-box ui-widget ui-corner-all ui-state-default ui-state-active', iconClass = (hidden) ? 'ui-chkbox-icon ui-icon ui-icon-blank' : 'ui-chkbox-icon ui-icon ui-icon-check', columnChildren = column.children('.ui-column-title').clone(), columnTogglerCheckboxId = this.tableId + "_columnTogglerChkbx" + i; columnChildren.find('script').remove(); // GitHub #9647 remove scripts columnChildren.find('.ui-tooltip-text').remove(); // GitHub #10740 remove tooltips var columnTitle = columnChildren.text(); var label = columnChildren.find('label'); if (label.length) { columnTitle = label.text(); } this.hasPriorityColumns = column.is('[class*="ui-column-p-"]'); var item = $('
  • ' + '
    ' + '
    ' + '
  • ').data('column', column.attr('id')); if (this.hasPriorityColumns) { var columnClasses = column.attr('class').split(' '); for (var j = 0; j < columnClasses.length; j++) { var columnClass = columnClasses[j], pindex = columnClass.indexOf('ui-column-p-'); if (pindex !== -1) { item.addClass(columnClass.substring(pindex, pindex + 13)); } } } item.appendTo(this.itemContainer); this.togglerState.push(column.attr('id') + '_' + !hidden); } this.togglerStateHolder.val(this.togglerState.join(',')); //close icon this.closer = $('') .attr('aria-label', PrimeFaces.getAriaLabel('columntoggler.CLOSE')).prependTo(this.panel); if (this.panel.outerHeight() > 200) { this.panel.height(200); } this.hide(); }, /** * Sets up all event listeners required by this widget. * @private */ bindEvents: function() { var $this = this; //trigger this.trigger.off('click.ui-columntoggler').on('click.ui-columntoggler', function(e) { if ($this.visible) $this.hide(); else $this.show(); }); //checkboxes this.itemContainer.find('> .ui-columntoggler-item > .ui-chkbox > .ui-chkbox-box').on('mouseenter.columnToggler', function() { $(this).addClass('ui-state-hover'); }) .on('mouseleave.columnToggler', function() { $(this).removeClass('ui-state-hover'); }) .on('click.columnToggler', function(e) { $this.toggle($(this)); e.preventDefault(); }); //labels this.itemContainer.find('> .ui-columntoggler-item > label').on('click.selectCheckboxMenu', function(e) { $this.toggle($(this).prev().children('.ui-chkbox-box')); PrimeFaces.clearSelection(); e.preventDefault(); }); //closer this.closer.on('click', function(e) { $this.hide(); $this.trigger.trigger('focus'); e.preventDefault(); }); this.bindKeyEvents(); PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.panel, function() { return $this.trigger; }, function(e, eventTarget) { if (!($this.panel.is(eventTarget) || $this.panel.has(eventTarget).length > 0)) { $this.hide(); } }); PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.panel, function() { $this.alignPanel(); }); }, /** * Sets up the event listners for keyboard interaction. * @private */ bindKeyEvents: function() { var $this = this, inputs = this.itemContainer.find('> li > div.ui-chkbox > div.ui-chkbox-box'); this.trigger.on('focus.columnToggler', function() { $(this).addClass('ui-state-focus'); }) .on('blur.columnToggler', function() { $(this).removeClass('ui-state-focus'); }) .on('keydown.columnToggler', function(e) { switch (e.key) { case 'Enter': if ($this.visible) $this.hide(); else $this.show(); e.preventDefault(); break; case 'Tab': if ($this.visible) { $this.itemContainer.children('li:not(.ui-state-disabled):first').find('div.ui-chkbox-box').trigger('focus'); e.preventDefault(); } break; }; }); inputs.on('focus.columnToggler', function() { $(this).addClass('ui-state-focus'); //PrimeFaces.scrollInView($this.panel, box); }) .on('blur.columnToggler', function(e) { $(this).removeClass('ui-state-focus'); }) .on('keydown.columnToggler', function(e) { switch (e.key) { case 'Tab': var index = $(this).closest('li').index(); if (e.shiftKey) { if (index === 0) $this.closer.trigger('focus'); else inputs.eq(index - 1).trigger('focus'); } else { if (index === ($this.columns.length - 1) && !e.shiftKey) $this.closer.trigger('focus'); else inputs.eq(index + 1).trigger('focus'); } e.preventDefault(); break; case 'Enter': case ' ': $this.toggle($(this)); e.preventDefault(); break; } }) .on('change.columnToggler', function(e) { if ($(this).attr('aria-checked') === "true") { $this.check(box); $(this).removeClass('ui-state-active'); } else { $this.uncheck(box); } }); this.closer.on('keydown.columnToggler', function(e) { switch (e.key) { case 'Enter': $this.hide(); $this.trigger.trigger('focus'); e.preventDefault(); break; case 'Tab': if (e.shiftKey) inputs.eq($this.columns.length - 1).trigger('focus'); else inputs.eq(0).trigger('focus'); e.preventDefault(); break; }; }); }, /** * Checks or unchecks the given checkbox for a column, depending on whether it is currently selected. Also shows or * hides the column of the table to which this column toggler is attached. * @param {JQuery} chkbox Checkbox (`.ui-chkbox-box`) of a column of this column toggler. */ toggle: function(chkbox) { if (chkbox.hasClass('ui-state-active')) { this.uncheck(chkbox); } else { this.check(chkbox); } }, /** * Checks the given checkbox for a column, so that the column is now selected. Also display the column of the table * to which this column toggler is attached. * @param {JQuery} chkbox Checkbox (`.ui-chkbox-box`) of a column of this column toggler. */ check: function(chkbox) { chkbox.addClass('ui-state-active').children('.ui-chkbox-icon').addClass('ui-icon-check').removeClass('ui-icon-blank'); var column = $(document.getElementById(chkbox.closest('li.ui-columntoggler-item').data('column'))), index = column.index() + 1, thead = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.thead.eq(0) : this.thead.eq(1)) : this.thead, tbody = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tbody.eq(0) : this.tbody.eq(1)) : this.tbody, tfoot = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tfoot.eq(0) : this.tfoot.eq(1)) : this.tfoot; var rowSelector = 'tr:not(.ui-expanded-row-content)'; var rowHeader = thead.children(rowSelector), columnHeader = rowHeader.find('th:nth-child(' + index + ')'); chkbox.attr('aria-checked', true); columnHeader.removeClass('ui-helper-hidden'); $(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).removeClass('ui-helper-hidden'); tbody.children(rowSelector).find('td:nth-child(' + index + ')').removeClass('ui-helper-hidden'); tfoot.children(rowSelector).find('td:nth-child(' + index + ')').removeClass('ui-helper-hidden'); if (this.hasFrozenColumn) { var headers = rowHeader.children('th'); if (headers.length !== headers.filter('.ui-helper-hidden').length) { thead.closest('td').removeClass('ui-helper-hidden'); } if (!column.hasClass('ui-frozen-column')) { index += this.frozenColumnCount; } } if (this.hasStickyHeader) { $(PrimeFaces.escapeClientId(columnHeader.attr('id'))).removeClass('ui-helper-hidden'); } this.changeTogglerState(column, true); this.fireToggleEvent(true, (index - 1)); this.updateColspan(); }, /** * Unchecks the given checkbox for a column, so that the column is now not selected. Also hides the column of the * table to which this column toggler is attached. * @param {JQuery} chkbox Checkbox (`.ui-chkbox-box`) of a column of this column toggler. */ uncheck: function(chkbox) { chkbox.removeClass('ui-state-active').children('.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); var column = $(document.getElementById(chkbox.closest('li.ui-columntoggler-item').data('column'))), index = column.index() + 1, thead = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.thead.eq(0) : this.thead.eq(1)) : this.thead, tbody = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tbody.eq(0) : this.tbody.eq(1)) : this.tbody, tfoot = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tfoot.eq(0) : this.tfoot.eq(1)) : this.tfoot; var rowSelector = 'tr:not(.ui-expanded-row-content)'; var rowHeader = thead.children(rowSelector), columnHeader = rowHeader.find('th:nth-child(' + index + ')'); chkbox.attr('aria-checked', false); columnHeader.addClass('ui-helper-hidden'); $(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).addClass('ui-helper-hidden'); tbody.children(rowSelector).find('td:nth-child(' + index + ')').addClass('ui-helper-hidden'); tfoot.children(rowSelector).find('td:nth-child(' + index + ')').addClass('ui-helper-hidden'); if (this.hasFrozenColumn) { var headers = rowHeader.children('th'); if (headers.length === headers.filter(':hidden').length) { thead.closest('td').addClass('ui-helper-hidden'); } if (!column.hasClass('ui-frozen-column')) { index += this.frozenColumnCount; } } if (this.hasStickyHeader) { $(PrimeFaces.escapeClientId(columnHeader.attr('id'))).addClass('ui-helper-hidden'); } this.changeTogglerState(column, false); this.fireToggleEvent(false, (index - 1)); this.updateColspan(); }, /** * Aligns the overlay panel of this column toggler according to the current widget configuration. */ alignPanel: function() { this.panel.css({ 'left': '', 'top': '', 'z-index': PrimeFaces.nextZindex() }).position({ my: 'left top' , at: 'left bottom' , of: this.trigger }); if (this.hasPriorityColumns) { if (this.panel.outerWidth() <= this.trigger.outerWidth()) { this.panel.css('width', 'auto'); } this.widthAligned = false; } if (!this.widthAligned && (this.panel.outerWidth() < this.trigger.outerWidth())) { this.panel.width(this.trigger.width()); this.widthAligned = true; } }, /** * Brings up this column toggler so that the user can which column to hide or show. */ show: function() { this.alignPanel(); this.panel.show(); this.visible = true; this.trigger.attr('aria-expanded', true); this.closer.trigger('focus'); }, /** * Hides this column toggler. */ hide: function() { // only fire event if columnToggler was really shown if (this.visible) { this.fireCloseEvent(); } this.panel.fadeOut('fast'); this.visible = false; this.trigger.attr('aria-expanded', false); }, /** * Triggers the events listeners and behaviors when a column was selected or unselected. * @param {boolean} visible `true` if the column was selected, `false` otherwise. * @param {number} index Index of the toggled column. * @private */ fireToggleEvent: function(visible, index) { if (this.hasBehavior('toggle')) { var ext = { params: [ { name: this.id + '_visibility', value: visible ? 'VISIBLE' : 'HIDDEN' }, { name: this.id + '_index', value: index } ] }; this.callBehavior('toggle', ext); } }, /** * Triggers the events listeners and behaviors when the popup is closed. * @private */ fireCloseEvent: function() { if (this.hasBehavior('close')) { var columnIds = ''; for (var i = 0; i < this.columns.length; i++) { var column = this.columns.eq(i); var parts = column.attr('id').split(':'); var columnId = parts[parts.length - 1]; hidden = column.hasClass('ui-helper-hidden') if (!hidden) { if (columnIds != '') { columnIds = columnIds + ','; } columnIds = columnIds + columnId; } } var ext = { params: [ { name: this.id + '_visibleColumnIds', value: columnIds } ] }; this.callBehavior('close', ext); } }, /** * Computes the required `colspan` for the rows. * @private * @return {number} The calculated `colspan` for the rows. */ calculateColspan: function() { return this.itemContainer.find('> .ui-columntoggler-item > .ui-chkbox > .ui-chkbox-box.ui-state-active').length; }, /** * Updates the `colspan` attribute fo the columns of the given row. * @private * @param {JQuery} row A row to update. * @param {string} colspanValue New value for the `colspan` attribute. */ updateRowColspan: function(row, colspanValue) { colspanValue = colspanValue || this.calculateColspan(); if (colspanValue) { row.children('td').removeClass('ui-helper-hidden').attr('colspan', colspanValue); } else { row.children('td').addClass('ui-helper-hidden'); } }, /** * Updates the colspan attributes of the target table of this column toggler. Called after a column was selected or * unselected, which resulted in a column of the data table to be shown or hidden. * @private */ updateColspan: function() { var emptyRow = this.tbody.children('tr:first'); if (emptyRow && emptyRow.hasClass('ui-datatable-empty-message')) { this.updateRowColspan(emptyRow); } else { var colspanValue = this.calculateColspan(), $this = this; this.tbody.children('.ui-expanded-row-content').each(function() { $this.updateRowColspan($(this), colspanValue); }); } }, /** * @include * @override * @protected * @inheritdoc */ _render: function() { throw new Error('Unsupported Operation'); }, /** * Selects or unselect a column of this column toggler. Also shows or hides the corresponding colum of the table * to which this column toggler is attached. * @param {JQuery} column A column element (`LI`) of this column toggler. * @param {boolean} isHidden `true` to unselect the column and hide the corresponding table column, or `true` * otherwise. * @private */ changeTogglerState: function(column, isHidden) { if (column && column.length) { var stateVal = this.togglerStateHolder.val(), columnId = column.attr('id'), oldColState = columnId + "_" + !isHidden, newColState = columnId + "_" + isHidden; this.togglerStateHolder.val(stateVal.replace(oldColState, newColState)); } } });




    © 2015 - 2024 Weber Informatics LLC | Privacy Policy