Viewing File: /usr/local/cpanel/share/libraries/cjt2/src/directives/selectSortDirective.js

/*
# cjt/directives/selectSortDirective.js           Copyright(c) 2020 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(
    [
        "angular",
        "cjt/core",
        "cjt/util/locale",
        "cjt/templates" // NOTE: Pre-load the template cache
    ],
    function(angular, CJT, LOCALE) {

        var ASCENDING  = "asc";
        var DESCENDING = "desc";
        var DEFAULT_ASCENDING_TITLE = LOCALE.maketext("Ascending");
        var DEFAULT_DESCENDING_TITLE = LOCALE.maketext("Descending");

        var module = angular.module("cjt2.directives.selectSort", [
            "cjt2.templates"
        ]);

        /**
         * Directive that provides a select box to sort a tabular dataset by a single column in ascending or descending order.
         *
         * @name cpSelectSort
         * @attribute {Binding}   sortMeta      Meta-Data Model where the sort properties are stored.
         *                                      Sort properties required are sortDirection, sortBy, and sortType.
         * @attribute {Binding}   sortFields    An array of sortField objects following the pattern:
         *                                      The field corresponds to the api.sort.a.field
         *                                      The sortType corresponds to api.sort.a.method, e.g. lexical, numeric, ipv4
         *                                      The sortReverse boolean will reverse the direction of the sortDirection
         *                                          property on the metadata object.
         *                                      The label is the text that will be shown on the select option.
         * @attribute {Attribute} defaultField  The default sort field.
         * @attribute {Attribute} defaultDir    The default sort direction.
         * @attribute {Attribute} idSuffix      The suffix for the IDs on the select and direction arrow.
         * @attribute {Attribute} label         The text for the label that precedes the select box.
         * @attribute {Function}  onsort        Function triggered when a sort operation happens.
         *                                      Can handle initiating the backend request or just be used as a callback.
         * @callback onsort
         * @param {Reference} sortMeta      Meta-Data Model where the sort properties are stored.
         *                                  Sort properties required are sortDirection, sortBy, and sortType.
         * @param {Boolean}   defaultSort   If true, this sort is being executed because the default sort attributes
         *                                  were set and not due to user action.
         *
         * @example
         *
         * <cp-select-sort sort-meta="meta"
         *                 onsort="sortList"
         *                 sort-fields="sortFields"
         *                 default-field="id"
         *                 default-dir="desc">
         * </cp-select-sort>
         *
         * Where:
         *
         * $scope.sortFields = [
         *     {
         *         field: "staged",
         *         label: LOCALE.maketext("Unpublished"),
         *         sortReverse: true
         *     },
         *     {
         *         field: "vendor_id",
         *         label: LOCALE.maketext("Vendor")
         *     },
         *     {
         *         field: "id",
         *         label: LOCALE.maketext("ID"),
         *         sortType: "numeric"
         *     }
         * ];
         */
        module.directive("cpSelectSort", function() {
            var suffixCount = 0;
            var RELATIVE_PATH = "libraries/cjt2/directives/selectSortDirective.phtml";

            return {
                templateUrl: CJT.config.debug ? CJT.buildFullPath(RELATIVE_PATH) : RELATIVE_PATH,
                restrict: "E",
                scope: {
                    sortFields: "=",
                    sortMeta: "=",
                    sortAscendingTitle: "@",
                    sortDescendingTitle: "@",
                    onsort: "&",
                    label: "@"
                },

                controller: ["$scope", "$attrs", function($scope, $attrs) {

                    /**
                     * Gets the sort direction, as seen by the end user.
                     *
                     * @method _getDir
                     * @private
                     * @return {String}   A string corresponding to the sort direction.
                     */
                    function _getDir() {

                        // If we're not reversing, just provide the direction as-is. Otherwise, provide the opposite.
                        return !$scope.fieldMap[$scope.sortMeta.sortBy].sortReverse ?
                            $scope.sortMeta.sortDirection : $scope.sortMeta.sortDirection === ASCENDING ?
                                DESCENDING : ASCENDING;
                    }
                    $scope.getDir = _getDir;

                    /**
                     * Sets the sort direction.
                     *
                     * @method _setDir
                     * @private
                     * @param {String} newdir   The new direction for the sorting.
                     */
                    function _setDir(newdir) {

                        // If we're not reversing, just set with the new direction. Otherwise, set with the opposite.
                        $scope.sortMeta.sortDirection = !$scope.fieldMap[$scope.sortMeta.sortBy].sortReverse ?
                            newdir : newdir === ASCENDING ?
                                DESCENDING : ASCENDING;

                        return _getDir();
                    }

                    /**
                     * Get the title text for the sort direction control.
                     *
                     * @method getTitle
                     */
                    $scope.getTitle = function() {
                        return _getDir() === ASCENDING ? $attrs["sortAscendingTitle"] : $attrs["sortDescendingTitle"];
                    };

                    /**
                     * Changes the sort direction and executes the onsort callback if defined.
                     *
                     * @method sort
                     * @param  {Boolean} changeDir      If true, the sort direction will flip.
                     * @param  {Boolean} defaultSort    If true, this is an initial sort triggered because of default
                     *                                  values passed in as attributes.
                     */
                    $scope.sort = function(changeDir, defaultSort) {
                        var meta = $scope.sortMeta;

                        // Update the sort direction
                        if (changeDir) {
                            meta.sortDirection = meta.sortDirection === ASCENDING ? DESCENDING : ASCENDING; // Just flipping this around, so no need to use the setter/getter
                        } else if (!defaultSort) {
                            _setDir(ASCENDING); // Changing sort fields, so go back to ascending
                        }

                        // Update the sortType
                        meta.sortType = $scope.fieldMap[meta.sortBy].sortType;

                        // Make sure onsort exists on the parent scope before executing it
                        var onsort = $scope.onsort();
                        if (angular.isFunction(onsort)) {
                            onsort(meta, defaultSort);
                        }
                    };

                    // Set up a map to easily access the sortField objects.
                    // The array of sortFields is necessary so that the order can be preserved in the select.
                    $scope.fieldMap = {};
                    $scope.sortFields.forEach(function(obj) {
                        $scope.fieldMap[obj.field] = obj;
                    });

                    // Set the suffix from the attribute or generic counter
                    $scope.idSuffix = $attrs.idSuffix || suffixCount++;

                    // Set the metadata object properties if defaults have been provided.
                    // Process the defaultField if it exists
                    if ($attrs.defaultField) {

                        // Check if the default sort field is valid
                        $scope.validDefaultProvided = $scope.sortFields.some(function(sortField) {
                            return sortField.field === $attrs.defaultField;
                        });

                        // If valid, set the default sort field
                        if ($scope.validDefaultProvided) {
                            $scope.sortMeta.sortBy = $attrs.defaultField;
                        }
                    }

                    // Set the sortBy to the first item in the sortFields array if it's not
                    // set in the metadata object and a default field wasn't provided.
                    if (!$scope.sortMeta.sortBy) {
                        $scope.sortMeta.sortBy = $scope.sortFields[0].field;
                    }

                    // Process the default sort direction if it exists
                    if ($attrs.defaultDir === DESCENDING || $attrs.defaultDir === ASCENDING) {
                        _setDir($attrs.defaultDir);
                        $scope.validDefaultProvided = true;
                    }

                    // If there's no defaultDir and the direction isn't set in the metadata, let's default to asc
                    else if ($scope.sortMeta.sortDirection !== DESCENDING && $scope.sortMeta.sortDirection !== ASCENDING) {
                        _setDir(ASCENDING);
                    }

                }],

                compile: function(element, attributes) {

                    // Set the asc/desc title attributes if they aren't set
                    if (!attributes["sortAscendingTitle"]) {
                        attributes["sortAscendingTitle"] = DEFAULT_ASCENDING_TITLE;
                    }

                    if (!attributes["sortDescendingTitle"]) {
                        attributes["sortDescendingTitle"] = DEFAULT_DESCENDING_TITLE;
                    }

                    // Set the label attribute if it isn't set
                    if (!attributes["label"]) {
                        attributes["label"] = LOCALE.maketext("Sort by");
                    }

                    return function(scope, element, attrs) {

                        // Once everything is set up, go ahead and fire the callback if
                        // valid defaults were provided.
                        if (scope.validDefaultProvided) {
                            scope.sort(false, true);
                        }
                    };
                },
            };
        });
    }
);
Back to Directory File Manager