Viewing File: /usr/local/cpanel/base/sharedjs/zone_editor/models/dynamic_table.js

/*
# models/dynamic_table.js                         Copyright(c) 2020 cPanel, L.L.C# cpanel - base/sharedjs/zone_editor/models/dynamic_table.js
#                                                  Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
*/

/* global define: false */

define(
    [
        "lodash",
        "cjt/util/locale",
    ],
    function(_, LOCALE) {

        "use strict";

        var PAGE_SIZES = [10, 20, 50, 100, 500, 1000];
        var DEFAULT_PAGE_SIZE = 100;

        // sanity check
        if (!PAGE_SIZES.includes(DEFAULT_PAGE_SIZE)) {
            throw "default not in page sizes";
        }

        /**
         * Creates a Dynamic Table object
         *
         * @class
         */
        function DynamicTable() {
            this.items = [];
            this.filteredList = this.items;
            this.selected = [];
            this.allDisplayedRowsSelected = false;
            this.filterFunction = void 0;
            this.quickFilterFunction = void 0;

            this.meta = {
                sortBy: "",
                sortDirection: "asc",
                maxPages: 0,
                totalItems: this.items.length,
                pageNumber: 1,
                pageSize: DEFAULT_PAGE_SIZE,
                pageSizes: PAGE_SIZES,
                start: 0,
                limit: 0,
                filterValue: "",
                quickFilterValue: "",
            };
        }

        DynamicTable.PAGE_SIZES         = PAGE_SIZES;
        DynamicTable.DEFAULT_PAGE_SIZE  = DEFAULT_PAGE_SIZE;

        /**
         * Set the filter function to be used for searching the table
         *
         * @method loadData
         * @param {Array} data - an array of objects representing the data to display
         */
        DynamicTable.prototype.loadData = function(data) {
            if (!_.isArray(data)) {
                throw "Developer Exception: loadData requires an array";
            }

            this.items = data;

            for (var i = 0, len = this.items.length; i < len; i++) {
                if (!_.isObject(this.items[i])) {
                    throw "Developer Exception: loadData requires an array of objects";
                }

                // add a unique id to each piece of data
                this.items[i]._id = i.toString();

                // initialize the selected array with the ids of selected items
                if (this.items[i].selected) {
                    this.selected.push(this.items[i]._id);
                }
            }
        };

        /**
         * Set the filter function to be used for searching the table
         *
         * @method setFilterFunction
         * @param {Function} func - a function that can be used to search the data
         * @note The function passed to this function must
         * - return a boolean
         * - accept the following args: an item object and the search text
         */
        DynamicTable.prototype.setFilterFunction = function(func) {
            if (!_.isFunction(func)) {
                throw "Developer Error: setFilterFunction requires a function";
            }

            this.filterFunction = func;
        };

        /**
         * Set the quick filter function to be used with quick filters, which
         * are a predefined set of filter values
         *
         * @method setQuickFilterFunction
         * @param {Function} func - a function that can be used to filter data
         * @note The function passed to this function must
         * - return a boolean
         * - accept the following args: an item object and the search text
         */
        DynamicTable.prototype.setQuickFilterFunction = function(func) {
            if (!_.isFunction(func)) {
                throw "Developer Error: setQuickFilterFunction requires a function";
            }

            this.quickFilterFunction = func;
        };


        /**
         * Set the filter function to be used for searching the table
         *
         * @method setSort
         * @param {String} by - the field you want to sort on
         * @param {String} direction - the direction you want to sort, "asc" or "desc"
         */
        DynamicTable.prototype.setSort = function(by, direction) {
            if (!_.isUndefined(by)) {
                this.meta.sortBy = by;
            }

            if (!_.isUndefined(direction)) {
                this.meta.sortDirection = direction;
            }
        };

        /**
         * Get the table metadata
         *
         * @method getMetadata
         * @return {Object} The metadata for the table. We return a
         * reference here so that callers can update the object and
         * changes can easily be propagated.
         */
        DynamicTable.prototype.getMetadata = function() {
            return this.meta;
        };

        /**
         * Get the table data
         *
         * @method getList
         * @return {Array} The table data
         */
        DynamicTable.prototype.getList = function() {
            return this.filteredList;
        };

        /**
         * Get the table data that is selected
         *
         * @method getSelectedList
         * @return {Array} The table data that is selected
         */
        DynamicTable.prototype.getSelectedList = function() {
            return this.items.filter(function(item) {
                return item.selected;
            });
        };

        /**
         * Determine if all the filtered table rows are selected
         *
         * @method areAllDisplayedRowsSelected
         * @return {Boolean}
         */
        DynamicTable.prototype.areAllDisplayedRowsSelected = function() {
            return this.allDisplayedRowsSelected;
        };

        /**
         * Get the total selected rows in the table
         *
         * @method getTotalRowsSelected
         * @return {Number} total of selected rows in the table
         */
        DynamicTable.prototype.getTotalRowsSelected = function() {
            return this.selected.length;
        };

        /**
         * Select all items for a single page of data in the table
         *
         * @method selectAllDisplayed
         * @param {Boolean} toggle - determines whether to select or unselect all
         * displayed items
         */
        DynamicTable.prototype.selectAllDisplayed = function(toggle) {
            if (toggle) {

                // Select the rows if they were previously selected on this page.
                for (var i = 0, filteredLen = this.filteredList.length; i < filteredLen; i++) {
                    var item = this.filteredList[i];
                    item.selected = true;

                    // make sure this item is not already in the list
                    if (this.selected.indexOf(item._id) !== -1) {
                        continue;
                    }

                    this.selected.push(item._id);
                }
            } else {

                // Extract the unselected items and remove them from the selected collection.
                var unselected = this.filteredList.map(function(item) {
                    item.selected = false;
                    return item._id;
                });

                this.selected = _.difference(this.selected, unselected);
            }

            this.allDisplayedRowsSelected = toggle;
        };

        /**
         * Select an item on the current page.
         *
         * @method selectItem
         * @param {Object} item - the item that we want to mark as selected.
         * NOTE: the item must have the selected property set to true before
         * passing it to this function
         */
        DynamicTable.prototype.selectItem = function(item) {
            if (!_.isUndefined(item)) {
                if (item.selected) {

                    // make sure this item is not already in the list
                    if (this.selected.indexOf(item._id) !== -1) {
                        return;
                    }

                    this.selected.push(item._id);

                    // Sync 'Select All' checkbox status when a new selction/unselection is made.
                    this.allDisplayedRowsSelected = this.filteredList.every(function(thisitem) {
                        return thisitem.selected;
                    });
                } else {
                    this.selected = this.selected.filter(function(thisid) {
                        return thisid !== item._id;
                    });

                    // Unselect Select All checkbox.
                    this.allDisplayedRowsSelected = false;
                }
            }
        };

        /**
         * Clear all selections for all pages.
         *
         * @method clearAllSelections
         */
        DynamicTable.prototype.clearAllSelections = function() {
            this.selected = [];

            for (var i = 0, len = this.items.length; i < len; i++) {
                var item = this.items[i];
                item.selected = false;
            }

            this.allDisplayedRowsSelected = false;
        };

        /**
         * Clear the entire table.
         *
         * @method clear
         */
        DynamicTable.prototype.clear = function() {
            this.items = [];
            this.selected = [];
            this.allDisplayedRowsSelected = false;
            this.filteredList = this.populate();
        };

        function _isExisting(item) {
            return !item.is_new || (item.is_new === "0");
        }

        /**
         * Populate the table with data accounting for filtering, sorting, and paging
         *
         * @method populate
         * @return {Array} the table data
         */
        DynamicTable.prototype.populate = function() {
            var filtered = [];
            var self = this;

            // filter list based on search text
            if (this.meta.filterValue !== null &&
                this.meta.filterValue !== void 0 &&
                this.meta.filterValue !== "" &&
                _.isFunction(this.filterFunction)) {
                filtered = this.items.filter(function(item) {
                    return _isExisting(item) && self.filterFunction(item, self.meta.filterValue);
                });
            } else {
                filtered = this.items.filter(_isExisting);
            }

            // filter list based on the quick filter
            if (this.meta.quickFilterValue !== null &&
                this.meta.quickFilterValue !== void 0 &&
                this.meta.quickFilterValue !== "" &&
                _.isFunction(this.quickFilterFunction)) {
                filtered = filtered.filter(function(item) {
                    return self.quickFilterFunction(item, self.meta.quickFilterValue);
                });
            }

            // sort the filtered list
            if (this.meta.sortDirection !== "" && this.meta.sortBy !== "") {
                filtered = _.orderBy(filtered, [this.meta.sortBy], [this.meta.sortDirection]);
            }

            // update the total items after search
            this.meta.totalItems = filtered.length;

            // filter list based on page size and pagination and handle the case
            // where the page size is "ALL" (-1)
            if (this.meta.totalItems > _.min(this.meta.pageSizes) ) {
                var start = (this.meta.pageNumber - 1) * this.meta.pageSize;
                var limit = this.meta.pageNumber * this.meta.pageSize;

                filtered = _.slice(filtered, start, limit);

                this.meta.start = start + 1;
                this.meta.limit = start + filtered.length;
            } else {
                if (filtered.length === 0) {
                    this.meta.start = 0;
                } else {
                    this.meta.start = 1;
                }

                this.meta.limit = filtered.length;
            }

            var countNonSelected = 0;
            for (var i = 0, filteredLen = filtered.length; i < filteredLen; i++) {
                var item = filtered[i];

                // Select the rows if they were previously selected on this page.
                if (this.selected.indexOf(item._id) !== -1) {
                    item.selected = true;
                } else {
                    item.selected = false;
                    countNonSelected++;
                }
            }

            // Clear the 'Select All' checkbox if at least one row is not selected.
            this.allDisplayedRowsSelected = (filtered.length > 0) && (countNonSelected === 0);

            this.filteredList = this.items.filter(
                function(item) {
                    return !_isExisting(item);
                }
            ).concat(filtered);

            return this.filteredList;
        };

        /**
         * Create a localized message for the table stats
         *
         * @method paginationMessage
         * @return {String}
         */
        DynamicTable.prototype.paginationMessage = function() {
            return LOCALE.maketext("Displaying [numf,_1] to [numf,_2] out of [quant,_3,item,items]", this.meta.start, this.meta.limit, this.meta.totalItems);
        };

        return DynamicTable;
    }
);
Back to Directory File Manager