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

/*
# cjt/directives/responsiveSortDirective.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/directives/responsiveSortInsertDirective",
        "cjt/directives/toggleSortDirective",
        "cjt/templates" // NOTE: Pre-load the template cache
    ],
    function(angular, CJT) {

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

        /**
         * This directive wraps a set of toggleSort directives and generates/inserts a cp-select-sort
         * directive into the wrapping element. See the documentation for the cp-responsive-sort-insert,
         * cp-select-sort, and toggleSort directives for more information. Note that the toggleSort
         *
         * @name cp-responsive-sort
         * @attribute {Attribute} defaultField  The default sort field for the selectSort.
         * @attribute {Attribute} defaultDir    The default sort direction for the selectSort.
         *
         * @example
         *
         * <li class="list-table-header row" cp-responsive-sort>
         *     <span class="visible-xs col-xs-8">
         *         <cp-responsive-sort-insert default-field="id" default-dir="desc"></cp-responsive-sort-insert>
         *     </span>
         *     <span class="hidden-xs col-sm-2">
         *          <toggle-sort id="sortVendor"
         *                       class="nowrap"
         *                       onsort="sortList"
         *                       sort-meta="meta"
         *                       sort-field="vendor_id">
         *          [% locale.maketext('Vendor') %]
         *          </toggle-sort>
         *      </span>
         *      <span class="hidden-xs col-sm-2">
         *          <toggle-sort id="sortID"
         *                       class="nowrap"
         *                       onsort="sortList"
         *                       sort-meta="meta"
         *                       sort-type="numeric"
         *                       sort-field="id">
         *              [% locale.maketext('ID') %]
         *          </toggle-sort>
         *      </span>
         *      <span class="hidden-xs col-sm-2">
         *          <toggle-sort id="sortMessage"
         *                       class="nowrap"
         *                       onsort="sortList"
         *                       sort-dir="meta"
         *                       sort-field="meta_msg">
         *              [% locale.maketext('Message') %]
         *          </toggle-sort>
         *      </span>
         * </li>
         *
         * In this example the cp-responsive-sort directive is wrapping 3 toggle-sort directives.
         * The generated selectSort directive will be inserted where the cp-responsive-sort-insert
         * element is placed.
         */
        module.directive("cpResponsiveSort", function() {
            return {
                restrict: "A",
                scope: true,

                // This controller is basically just here to enforce the parent-child relationship.
                controller: function() {},

                // The compile function is used because we need to access the DOM before the
                // toggleSort directives are processed. Otherwise, the transcluded text will
                // be missing and we cannot derive our option labels.
                compile: function(element, attrs) {

                    // This obj will eventually have consolidated sortBy, sortDir, and onsort keys
                    // for the selectSort directive. The sortFields key is an array of sortField
                    // objects which are consumed by the selectSort directive.
                    var parsed = {
                        sortFields: []
                    };

                    // Generate an array of objects from the toggleSort directives that are
                    // found within the element. These objects contain key/val pairs of the
                    // associated attributes.
                    var toggleSorts = Array.prototype.map.call(element.find("toggle-sort"), function(elem) {
                        elem = angular.element(elem);
                        return {
                            onsort: elem.attr("onsort"),
                            sortType: elem.attr("sort-type"),
                            sortReverse: angular.isDefined(elem.attr("sort-reverse")),
                            sortMeta: elem.attr("sort-meta"),
                            sortField: elem.attr("sort-field"),
                            sortLabel: elem.text().trim()
                        };
                    });

                    // Go through the list of bound attributes for each toggleSort found and
                    // ensure that they are uniform. Put all of the validated data into the
                    // "parsed" var.
                    toggleSorts.forEach(function(toggleSort) {
                        ["sortMeta", "onsort"].forEach(function(property) {

                            // Ignore omitted onsort attributes
                            if (!toggleSort.onsort) {
                                return;
                            }

                            if (!parsed[property]) { // For the first run-through
                                if (toggleSort[property]) {
                                    parsed[property] = toggleSort[property];
                                } else {
                                    throw new ReferenceError("Malformed/incomplete toggle-sort directive found in descendant tree. Responsive sort directive cannot proceed.");
                                }
                            } else if (toggleSort[property] !== parsed[property]) {
                                throw new Error("The responsive sort directive cannot handle more than one " + property + " property at a time.");
                            }
                        });

                        // Create the actual sortField object to be inserted into the array
                        if (toggleSort.sortField && toggleSort.sortLabel) {
                            parsed.sortFields.push({
                                label: toggleSort.sortLabel,
                                field: toggleSort.sortField,
                                sortType: toggleSort.sortType,
                                sortReverse: toggleSort.sortReverse
                            });
                        } else {
                            throw new ReferenceError("Malformed/incomplete toggle-sort directive found in descendant tree. Responsive sort directive cannot proceed.");
                        }
                    });

                    return {

                        // The scope needs to be set up in the pre-linking function because the
                        // post-linking order will start with the child directive and thus the
                        // scope wouldn't be ready.
                        pre: function link(scope, element, attrs) {

                            // Set up the view model for the selectSort
                            scope.selectSort = {
                                parsed: parsed,
                                attrs: {
                                    defaultField: attrs.defaultField,
                                    defaultDir: attrs.defaultDir
                                }
                            };
                        }
                    };
                }
            };
        });
    }
);
Back to Directory File Manager