File manager - Edit - /usr/local/cpanel/whostmgr/docroot/templates/transfer_tool/getacctlist.cmb.js
Back
/* # app/services/workerNodes.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 */ define( 'app/services/workerNodes',[ "angular", "lodash", "cjt/util/locale", ], function(angular, _, LOCALE) { "use strict"; var MODULE_NAMESPACE = "whm.transfers.services.workerNodes"; var SERVICE_NAME = "WorkerNodesService"; var MODULE_REQUIREMENTS = []; var SERVICE_INJECTABLES = ["LOCAL_WORKER_NODES", "REMOTE_WORKER_NODES", "DEFAULT_WORKER_OPTIONS"]; /** * Service for Handling Worker / Linked Nodes * * @param {object[]} LOCAL_WORKER_NODES local worker nodes possible to be used by accounts * @param {object[]} REMOTE_WORKER_NODES remote worker nodes that may or may not be used by individual accounts * @param {object} DEFAULT_WORKER_OPTIONS worker type keyed object representing the keys and defaults for the system * @returns instance of a workerNodesService */ var SERVICE_FACTORY = function(LOCAL_WORKER_NODES, REMOTE_WORKER_NODES, DEFAULT_WORKER_OPTIONS) { var Service = function() {}; Service.prototype = Object.create({}); _.assign(Service.prototype, { _localWorkerNodes: null, _remoteWorkerNodes: null, _workerOptionTypes: null, _defaultWorkerOptions: null, _accountWorkerNodeOptions: {}, _accountWorkerDefaultValues: {}, /** * Parse a raw worker node * * @private * * @param {object{alias:string,hostname:string,worker_capabilities:object}} rawWorkerNode raw worker node * @returns {object} parsed worker node */ _parseWorkerNode: function _parseWorkerNode(rawWorkerNode) { var workerNode = { alias: rawWorkerNode["alias"], hostname: rawWorkerNode["hostname"], workerCapabilities: Object.keys(rawWorkerNode.worker_capabilities), }; return workerNode; }, /** * Parse a set of raw worker nodes * * @private * * @param {object[]} rawWorkerNodes raw worker nodes to parse * @returns {object[]} parsed worker nodes */ _parseWorkerNodes: function _parseWorkerNodes(rawWorkerNodes) { return rawWorkerNodes.map(this._parseWorkerNode); }, /** * Get the listed of remote worker nodes * * @returns {object[]} parsed remote worker nodes */ getRemoteWorkerNodes: function getRemoteWorkerNodes() { if (_.isNull(this._remoteWorkerNodes)) { this._remoteWorkerNodes = this._parseWorkerNodes(REMOTE_WORKER_NODES); } return this._remoteWorkerNodes; }, /** * Get the list of local worker nodes * * @returns {object[]} parsed local worker nodes */ getLocalWorkerNodes: function getLocalWorkerNodes() { if (_.isNull(this._localWorkerNodes)) { this._localWorkerNodes = this._parseWorkerNodes(LOCAL_WORKER_NODES); } return this._localWorkerNodes; }, /** * Get the default worker options. * These are the settings that determine which workers, what defaults, and what the modelKey is * * @returns {object} worker type keyed object */ getDefaultWorkerOptions: function getDefaultWorkerOptions() { if ( _.isNull(this._defaultWorkerOptions) ) { this._defaultWorkerOptions = DEFAULT_WORKER_OPTIONS; // Check to ensure the default exists, if not, set it to local Object.keys(this._defaultWorkerOptions).filter(function(workerType) { return !this.getWorkerByAlias(this.getLocalWorkerNodes(), this._defaultWorkerOptions[workerType].value); }, this).forEach(function(workerType) { // These don't exist locally, so we should restore to controller this._defaultWorkerOptions[workerType].value = ".local"; }, this); } return this._defaultWorkerOptions; }, /** * Get a list of worker options that are supported * * @returns {string[]} array of strings representing the worker types supported * * @example * this.getWorkerOptionTypes(); // ['Mail', 'Web'] */ getWorkerOptionTypes: function getWorkerOptionTypes() { if (_.isNull(this._workerOptionTypes)) { this._workerOptionTypes = Object.keys(this.getDefaultWorkerOptions()); } return this._workerOptionTypes; }, /** * Look up a worker based on the hostname and type * * @param {object[]} workerList list of workers to search * @param {string} hostname hostname of the worker 'host.name.com' * @param {string} desiredWorkerType worker type 'Mail' etc * @returns {object|null} worker type if it matches the hostname and type */ getWorkerByHostname: function getWorkerByHostname(workerList, hostname, desiredWorkerType) { if (!workerList) { return; } return _.find(workerList, function(worker) { return worker.hostname === hostname && worker.workerCapabilities.indexOf(desiredWorkerType) > -1; }); }, /** * Get a worker from a worker list based on the alias * * @param {object[]} workerList list of workers to search * @param {string} alias alias for which to search * @returns {object|null} returns the worker object if it exists */ getWorkerByAlias: function getWorkerByAlias(workerList, alias) { if (!workerList) { return; } return _.find(workerList, function(worker) { return worker.alias === alias; }); }, /** * Build an item for a worker list of a specific type * * @private * * @param {string} label descriptive label of the item * @param {string} value specific key value for comparison * @param {string} type type of worker (Mail, etc) * @returns {object} worker item */ _createWorkerListTypeItem: function _createWorkerListTypeItem(label, value, type) { var defaultWorkerOptions = this.getDefaultWorkerOptions(); var workerOption = { label: label, value: value, modelKey: defaultWorkerOptions[type].modelKey, }; return workerOption; }, /** * Build an options list for a specific type of worker for a specific account * * @private * * @param {object} account account to base to list from * @param {string} workerType type of worker to build the list for * @returns {object[]} list of worker options for the account */ _createAccountWorkerListType: function _createAccountWorkerListType(account, workerType) { var defaultWorkerOptions = this.getDefaultWorkerOptions(); var remoteWorkerNodes = this.getRemoteWorkerNodes(); var localWorkerNodes = this.getLocalWorkerNodes(); var existingNodeFound; var workerTypeList = []; // Add local, should always be an option workerTypeList.push( this._createWorkerListTypeItem( LOCALE.maketext("Use only this server. Transfer or restore locally."), ".local", workerType) ); // Check for a local alias that matches the hostname and workertype of the remote user type if (account.workerNodes && account.workerNodes[workerType]) { var remoteWorker = this.getWorkerByAlias(remoteWorkerNodes, account.workerNodes[workerType]); var matchingLocalWorker = remoteWorker && this.getWorkerByHostname(localWorkerNodes, remoteWorker.hostname, workerType); if (matchingLocalWorker) { existingNodeFound = matchingLocalWorker.alias; workerTypeList.push(this._createWorkerListTypeItem( LOCALE.maketext("Use the [asis,cPanel] account’s package configuration.") + " (" + matchingLocalWorker.hostname + ")", existingNodeFound, workerType) ); } } // Add the rest localWorkerNodes.filter(function(workerNode) { return workerNode.alias !== existingNodeFound; }).forEach(function(workerNode) { workerTypeList.push( this._createWorkerListTypeItem(workerNode.alias + " (" + workerNode.hostname + ")", workerNode.alias, workerType) ); }, this); var defaultAlias = existingNodeFound ? existingNodeFound : defaultWorkerOptions[workerType].value; workerTypeList.filter(function(workerItem) { return workerItem.value === defaultAlias; }).forEach(function(workerItem) { workerItem.isDefault = true; }); return workerTypeList; }, /** * See <getAccountWorkerNodeOptions> * * @private */ _createAccountWorkerLists: function _createAccountWorkerLists(account) { var workerLists = {}; this.getWorkerOptionTypes().forEach(function(workerType) { workerLists[workerType] = this._createAccountWorkerListType(account, workerType); }, this); return workerLists; }, /** * Build all the worker options for all supported types for an account * * @private * * @param {object} account * @returns {object} object with lists based on specific type * * @example * this.getAccountWorkerNodeOptions(acccount); // {'Mail':[{label:"",value,"",modelKey:"",isDefault:false},{},{},...], 'Web':[], ...} */ getAccountWorkerNodeOptions: function getAccountWorkerNodeOptions(account) { var cacheKey = this._getAccountCacheKey(account); if (_.isUndefined(this._accountWorkerNodeOptions[cacheKey])) { this._accountWorkerNodeOptions[cacheKey] = this._createAccountWorkerLists(account); } return this._accountWorkerNodeOptions[cacheKey]; }, /** * Determine if any of the worker options for an account have been altered from the default * * @param {object} account account to check * @returns {boolean} has the account's worker options been altered */ checkWorkerOptionsAltered: function checkWorkerOptionsAltered(account) { return this.getAccountWorkerDefaultValues(account).some(function(workerDefaultObj) { var modelKey = workerDefaultObj.modelKey; var defaultValue = workerDefaultObj.value; if (account[modelKey] !== defaultValue) { return true; } return false; }); }, /** * Get the default worker values for an account. Used to establish initial values * * @param {object} account account to build the list from * @returns {object[]} returns a list of modelKey and values for an account * * @example * this.getAccountWorkerDefaultValues(account); // [{modelKey:"mail_location", value:'the_default_value"},...] */ getAccountWorkerDefaultValues: function getAccountWorkerDefaultValues(account) { var cacheKey = this._getAccountCacheKey(account); if (_.isUndefined(this._accountWorkerDefaultValues[cacheKey])) { var workerNodeOptions = this.getAccountWorkerNodeOptions(account); var defaultWorkerOptions = this.getDefaultWorkerOptions(); var accountDefaults = []; Object.keys(workerNodeOptions).forEach(function(workerType) { var accountDefault = { workerType: workerType, modelKey: defaultWorkerOptions[workerType].modelKey }; workerNodeOptions[workerType].forEach(function(workerOption) { if (workerOption.isDefault) { accountDefault.value = workerOption.value; } }); if (!accountDefault.value) { accountDefault.value = defaultWorkerOptions[workerType].value; } accountDefaults.push(accountDefault); }); this._accountWorkerDefaultValues[cacheKey] = accountDefaults; } return this._accountWorkerDefaultValues[cacheKey]; }, /** * Reset an account's worker settings to the defaults for that account * * @param {object} account */ resetAccountToDefaults: function resetAccountToDefaults(account) { // Get Worker Node Default Values (this is specific to the individual account) var defaultValues = this.getAccountWorkerDefaultValues(account); defaultValues.forEach(function(defaultValueObj) { account[defaultValueObj.modelKey] = defaultValueObj.value; }, this); }, /** * Build a key to use for caching account lists * * @private * * @param {object} account account for which to build the key * @returns {string} a string combination of the remote_user and domain, combined with a pipe */ _getAccountCacheKey: function _getAccountCacheKey(account) { // This is probably over-safe. remote_user _shouldn't_ change return account.remote_user + "|" + account.domain; } }); return new Service(); }; SERVICE_INJECTABLES.push(SERVICE_FACTORY); var app = angular.module(MODULE_NAMESPACE, MODULE_REQUIREMENTS); // This determines which options are revealed app.value("DEFAULT_WORKER_OPTIONS", { "Mail": { value: ".local", modelKey: "mail_location" } }); app.factory(SERVICE_NAME, SERVICE_INJECTABLES); return { "class": SERVICE_FACTORY, "serviceName": SERVICE_NAME, "namespace": MODULE_NAMESPACE }; } ); // Copyright 2025 WebPros International, LLC // All rights reserved. // copyright@cpanel.net http://cpanel.net // This code is subject to the cPanel license. Unauthorized copying is prohibited. /* # templates/transfer_tool/controllers/AccountTableController.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 */ /* jshint -W003 */ /* jshint -W098*/ define( 'app/directives/accountExpandPanel',[ "angular", "lodash", "cjt/util/locale", "app/services/workerNodes", ], function(angular, _, LOCALE, WorkerNodesService) { "use strict"; var MODULE_NAMESPACE = "whm.transfers.directives.accountExpandPanel"; var MODULE_INJECTABLES = [WorkerNodesService.namespace]; var DIRECTIVE_NAME = "accountExpandPanel"; /* embedded in getacctlist.tmpl so relative pathing is not necessary */ var DIRECTIVE_TEMPLATE = "directives/accountExpandPanel.ptt"; var CONTROLLER_INJECTABLES = ["$scope", WorkerNodesService.serviceName ]; var CONTROLLER = function AccountExpandPanelController($scope, $workerNodesService) { function _resetSkipOption(skipOption) { $scope.account[skipOption.modelKey] = skipOption.default; $scope.skipOptionChanged(skipOption); } function _resetWorkerType(workerDefaultValueObj) { var modelKey = workerDefaultValueObj.modelKey; var defaultValue = workerDefaultValueObj.value; var workerType = workerDefaultValueObj.workerType; $scope.account[modelKey] = defaultValue; $scope.workerNodeOption[workerType] = $scope.findWorkerOptionByValue(workerType, defaultValue); $scope.workerNodeOptionChanged(workerType); } /** * Function Called when reset button is clicked from the view * */ $scope.resetToDefaultClicked = function resetToDefaultClicked() { if ($scope.account.proxyOption) { $scope.account.proxyOption.value = $scope.account.proxyOption.default; } $scope.account.updateDNSZone = true; $scope.skipOptions.forEach(_resetSkipOption); $workerNodesService.getAccountWorkerDefaultValues($scope.account).forEach(_resetWorkerType); }; /** * Function called when 'apply to all' button is clicked from the view * */ $scope.applyToAllClicked = function allToAllClicked() { $scope.onApplyToAll({ updatedAccount: $scope.account, skipOptions: $scope.skipOptions, workerOptions: $scope.workerNodeOption, proxyOption: $scope.account.proxyOption, updateDNSZone: $scope.account.updateDNSZone }); }; /** * Function called on change of a specific option from the view * * @param {object} skipOption */ $scope.skipOptionChanged = function skipOptionChanged(skipOption) { $scope.onChange({ updatedAccount: $scope.account, modelKey: skipOption.modelKey, value: $scope.account[skipOption.modelKey] }); }; /** * Function called on change of proxying option froom view * @param {object} proxyOption */ $scope.proxyOptionChanged = function proxyOptionChanged(proxyOption) { $scope.onChange({ updatedAccount: $scope.account, modelKey: proxyOption.modelKey, value: !proxyOption.value }); }; /** * Function that toggles the value of some account param for the * scope. Don't call this if it isn't a bool-ish thing. * @param {string} accountKey */ $scope.acctBoolToggle = function acctBoolToggle(accountKey) { $scope.account[accountKey] = !$scope.account[accountKey]; $scope.onChange({ updatedAccount: $scope.account, modelKey: accountKey, value: $scope.account[accountKey] }); }; /** * Check if all options are set to default * * @returns {boolean} If all options match the default, this is true, else false */ $scope.isSetToDefault = function isSetToDefault() { return !$scope._skipOptionsAltered() && !$scope._workerOptionsAltered() && !$scope._proxyOptionAltered() && !$scope._updateDNSZoneAltered(); }; /** * Determine the number of accounts selected based on whether this account is selected or not * * @returns {number} Number of accounts selected */ $scope.getOtherSelectedAccountsCount = function getOtherSelectedAccountsCount() { var count = $scope.selectedAccountsCount; if ($scope.account.selected && count > 0) { count--; } return count; }; /** * Dispatches a close call to allow the closing of the expansion panel * */ $scope.applyAndClose = function applyAndClose() { $scope.onClose({ updatedAccount: $scope.account }); }; /** * Check to see if any skip options are altered * * @returns {boolean} returns true if any are altered */ $scope._skipOptionsAltered = function _skipOptionsAltered() { return $scope.skipOptions.some(function(skipOption) { if ($scope.account[skipOption.modelKey] !== skipOption.default) { return true; } return false; }); }; /** * Check to see if proxying option has been changed * @return {boolean} */ $scope._proxyOptionAltered = function _proxyOptionAltered() { if ($scope.account.proxyOption) { return $scope.account.proxyOption.value !== $scope.account.proxyOption.default; } return false; }; /** * Check to see if any worker options are altered * * @returns {boolean} returns true if any are altered */ $scope._workerOptionsAltered = function _workerOptionsAltered() { return $workerNodesService.checkWorkerOptionsAltered($scope.account); }; /** * Check to see if updateDNSZone option has been changed from default * @return {boolean} */ $scope._updateDNSZoneAltered = function _updateDNSZoneAltered() { return $scope.account.updateDNSZone !== true; }; /** * Get the label for a worker option menu * * @param {string} workerType string identifier of the node type (Mail) * @returns {string} localized label */ $scope.getWorkerConfigLabel = function getWorkerConfigLabel(workerType) { switch (workerType.toLowerCase()) { case "mail": return LOCALE.maketext("Mail"); } }; /** * Called when a worker node option changes * * @param {string} workerType the worker type that changed */ $scope.workerNodeOptionChanged = function workerNodeOptionChanged(workerType) { var worker = $workerNodesService.getDefaultWorkerOptions()[workerType]; $scope.onChange({ updatedAccount: $scope.account, modelKey: worker.modelKey, value: $scope.workerNodeOption[workerType].value }); }; /** * Find a specific worker option (object) by the .value property * * @param {string} workerType the worker type to search * @param {string} value the specific value to look for * @returns {object|null} returns the object if found */ $scope.findWorkerOptionByValue = function findWorkerOptionByValue(workerType, value) { return _.find($scope.workerNodeOptions[workerType], function(workerOption) { if (workerOption.value === value) { return true; } return false; }); }; /** * Set the current value of a worker type (done on intiation) * * @param {string} workerType worker type to set */ $scope.setCurrentWorkerTypeValue = function setCurrentWorkerTypeValue(workerType) { var modelKey = $workerNodesService.getDefaultWorkerOptions()[workerType].modelKey; $scope.workerNodeOption[workerType] = $scope.findWorkerOptionByValue(workerType, $scope.account[modelKey]); }; // Build Worker Option Sets $scope.workerNodeOptions = $workerNodesService.getAccountWorkerNodeOptions($scope.account); $scope.workerNodeOption = {}; $workerNodesService.getWorkerOptionTypes().forEach(function(workerType) { $scope.setCurrentWorkerTypeValue(workerType); var modelKey = $workerNodesService.getDefaultWorkerOptions()[workerType].modelKey; // Watch changes on the account $scope.$watch(function() { return $scope.account[modelKey]; }, function() { $scope.setCurrentWorkerTypeValue(workerType); }); }); // We should only show worker choices if there is greater than one thing to choose // because only one thing means that there is only .local $scope.showWorkerNodeOptions = $workerNodesService.getWorkerOptionTypes().some(function(typeKey) { if ($scope.workerNodeOptions[typeKey].length > 1) { return true; } return false; }); }; var LINK = function AccountExpandPanelLink($scope, element, attrs) { if ( _.isUndefined($scope.parentID) ) { throw new Error("“id” must be set for " + DIRECTIVE_NAME); } if ( _.isUndefined($scope.account) ) { throw new Error("“account” must be set for " + DIRECTIVE_NAME); } if ( _.isUndefined($scope.selectedAccountsCount) ) { throw new Error("“selectedAccountsCount” must be set for " + DIRECTIVE_NAME); } if (!$scope.skipOptions) { $scope.skipOptions = []; } $scope.selectedAccountsCount = parseInt($scope.selectedAccountsCount, 10); $scope.skipOptions.forEach(function validateSkipOption(skipOption) { var requiredParameters = ["label", "id", "modelKey", "default"]; requiredParameters.forEach(function(param) { if ( _.isUndefined(skipOption[param]) ) { throw new Error("[" + DIRECTIVE_NAME + "] all skip-options items must have the following parameters:\n" + requiredParameters.join(", ") + "\nInvalid item:\n" + JSON.stringify(skipOption)); } }); skipOption.id = $scope.parentID + "_" + skipOption.id; }); }; var DIRECTIVE_FACTORY = function DirectiveFactory() { return { restrict: "E", transclude: true, scope: { parentID: "@id", skipOptions: "=", proxyOption: "=", account: "=", selectedAccountsCount: "@", onApplyToAll: "&onApplyToAll", onChange: "&onChange", onClose: "&onClose", }, link: LINK, controller: CONTROLLER_INJECTABLES.concat(CONTROLLER), templateUrl: DIRECTIVE_TEMPLATE, }; }; var module = angular.module(MODULE_NAMESPACE, MODULE_INJECTABLES); module.directive(DIRECTIVE_NAME, DIRECTIVE_FACTORY); return { namespace: MODULE_NAMESPACE, class: CONTROLLER, factory: LINK, template: DIRECTIVE_TEMPLATE, }; } ); define( 'app/overwriteStates',[], function() { "use strict"; var OVERWRITE_STATES = { NO_OVERWRITE: "noOverwrite", OVERWRITE: "overwrite", OVERWRITE_WITH_DELETE: "overwriteWithDelete", }; return OVERWRITE_STATES; } ); define( 'app/overwriteOptions',[ "app/overwriteStates", "cjt/util/locale", ], function(OVERWRITE_STATES, LOCALE) { "use strict"; var OVERWRITE_OPTIONS = [ { label: LOCALE.maketext("Do Not Overwrite"), value: OVERWRITE_STATES.NO_OVERWRITE }, { label: LOCALE.maketext("Overwrite"), value: OVERWRITE_STATES.OVERWRITE }, { label: LOCALE.maketext("Overwrite with Delete"), value: OVERWRITE_STATES.OVERWRITE_WITH_DELETE }, ]; return OVERWRITE_OPTIONS; } ); (function(root) { define("jquery-chosen", ["jquery"], function() { return (function() { /*! Chosen, a Select Box Enhancer for jQuery and Prototype by Patrick Filler for Harvest, http://getharvest.com Version 1.5.1 Full source at https://github.com/harvesthq/chosen Copyright (c) 2011-2016 Harvest http://getharvest.com MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md This file is generated by `grunt build`, do not edit it by hand. */ (function() { var $, AbstractChosen, Chosen, SelectParser, _ref, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; SelectParser = (function() { function SelectParser() { this.options_index = 0; this.parsed = []; } SelectParser.prototype.add_node = function(child) { if (child.nodeName.toUpperCase() === "OPTGROUP") { return this.add_group(child); } else { return this.add_option(child); } }; SelectParser.prototype.add_group = function(group) { var group_position, option, _i, _len, _ref, _results; group_position = this.parsed.length; this.parsed.push({ array_index: group_position, group: true, label: this.escapeExpression(group.label), title: group.title ? group.title : void 0, children: 0, disabled: group.disabled, classes: group.className }); _ref = group.childNodes; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { option = _ref[_i]; _results.push(this.add_option(option, group_position, group.disabled)); } return _results; }; SelectParser.prototype.add_option = function(option, group_position, group_disabled) { if (option.nodeName.toUpperCase() === "OPTION") { if (option.text !== "") { if (group_position != null) { this.parsed[group_position].children += 1; } this.parsed.push({ array_index: this.parsed.length, options_index: this.options_index, value: option.value, text: option.text, html: option.innerHTML, title: option.title ? option.title : void 0, selected: option.selected, disabled: group_disabled === true ? group_disabled : option.disabled, group_array_index: group_position, group_label: group_position != null ? this.parsed[group_position].label : null, classes: option.className, style: option.style.cssText }); } else { this.parsed.push({ array_index: this.parsed.length, options_index: this.options_index, empty: true }); } return this.options_index += 1; } }; SelectParser.prototype.escapeExpression = function(text) { var map, unsafe_chars; if ((text == null) || text === false) { return ""; } if (!/[\&\<\>\"\'\`]/.test(text)) { return text; } map = { "<": "<", ">": ">", '"': """, "'": "'", "`": "`" }; unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g; return text.replace(unsafe_chars, function(chr) { return map[chr] || "&"; }); }; return SelectParser; })(); SelectParser.select_to_array = function(select) { var child, parser, _i, _len, _ref; parser = new SelectParser(); _ref = select.childNodes; for (_i = 0, _len = _ref.length; _i < _len; _i++) { child = _ref[_i]; parser.add_node(child); } return parser.parsed; }; AbstractChosen = (function() { function AbstractChosen(form_field, options) { this.form_field = form_field; this.options = options != null ? options : {}; if (!AbstractChosen.browser_is_supported()) { return; } this.is_multiple = this.form_field.multiple; this.set_default_text(); this.set_default_values(); this.setup(); this.set_up_html(); this.register_observers(); this.on_ready(); } AbstractChosen.prototype.set_default_values = function() { var _this = this; this.click_test_action = function(evt) { return _this.test_active_click(evt); }; this.activate_action = function(evt) { return _this.activate_field(evt); }; this.active_field = false; this.mouse_on_container = false; this.results_showing = false; this.result_highlighted = null; this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false; this.disable_search_threshold = this.options.disable_search_threshold || 0; this.disable_search = this.options.disable_search || false; this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true; this.group_search = this.options.group_search != null ? this.options.group_search : true; this.search_contains = this.options.search_contains || false; this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true; this.max_selected_options = this.options.max_selected_options || Infinity; this.inherit_select_classes = this.options.inherit_select_classes || false; this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true; this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true; this.include_group_label_in_selected = this.options.include_group_label_in_selected || false; return this.max_shown_results = this.options.max_shown_results || Number.POSITIVE_INFINITY; }; AbstractChosen.prototype.set_default_text = function() { if (this.form_field.getAttribute("data-placeholder")) { this.default_text = this.form_field.getAttribute("data-placeholder"); } else if (this.is_multiple) { this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text; } else { this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text; } return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text; }; AbstractChosen.prototype.choice_label = function(item) { if (this.include_group_label_in_selected && (item.group_label != null)) { return "<b class='group-name'>" + item.group_label + "</b>" + item.html; } else { return item.html; } }; AbstractChosen.prototype.mouse_enter = function() { return this.mouse_on_container = true; }; AbstractChosen.prototype.mouse_leave = function() { return this.mouse_on_container = false; }; AbstractChosen.prototype.input_focus = function(evt) { var _this = this; if (this.is_multiple) { if (!this.active_field) { return setTimeout((function() { return _this.container_mousedown(); }), 50); } } else { if (!this.active_field) { return this.activate_field(); } } }; AbstractChosen.prototype.input_blur = function(evt) { var _this = this; if (!this.mouse_on_container) { this.active_field = false; return setTimeout((function() { return _this.blur_test(); }), 100); } }; AbstractChosen.prototype.results_option_build = function(options) { var content, data, data_content, shown_results, _i, _len, _ref; content = ''; shown_results = 0; _ref = this.results_data; for (_i = 0, _len = _ref.length; _i < _len; _i++) { data = _ref[_i]; data_content = ''; if (data.group) { data_content = this.result_add_group(data); } else { data_content = this.result_add_option(data); } if (data_content !== '') { shown_results++; content += data_content; } if (options != null ? options.first : void 0) { if (data.selected && this.is_multiple) { this.choice_build(data); } else if (data.selected && !this.is_multiple) { this.single_set_selected_text(this.choice_label(data)); } } if (shown_results >= this.max_shown_results) { break; } } return content; }; AbstractChosen.prototype.result_add_option = function(option) { var classes, option_el; if (!option.search_match) { return ''; } if (!this.include_option_in_results(option)) { return ''; } classes = []; if (!option.disabled && !(option.selected && this.is_multiple)) { classes.push("active-result"); } if (option.disabled && !(option.selected && this.is_multiple)) { classes.push("disabled-result"); } if (option.selected) { classes.push("result-selected"); } if (option.group_array_index != null) { classes.push("group-option"); } if (option.classes !== "") { classes.push(option.classes); } option_el = document.createElement("li"); option_el.className = classes.join(" "); option_el.style.cssText = option.style; option_el.setAttribute("data-option-array-index", option.array_index); option_el.innerHTML = option.search_text; if (option.title) { option_el.title = option.title; } return this.outerHTML(option_el); }; AbstractChosen.prototype.result_add_group = function(group) { var classes, group_el; if (!(group.search_match || group.group_match)) { return ''; } if (!(group.active_options > 0)) { return ''; } classes = []; classes.push("group-result"); if (group.classes) { classes.push(group.classes); } group_el = document.createElement("li"); group_el.className = classes.join(" "); group_el.innerHTML = group.search_text; if (group.title) { group_el.title = group.title; } return this.outerHTML(group_el); }; AbstractChosen.prototype.results_update_field = function() { this.set_default_text(); if (!this.is_multiple) { this.results_reset_cleanup(); } this.result_clear_highlight(); this.results_build(); if (this.results_showing) { return this.winnow_results(); } }; AbstractChosen.prototype.reset_single_select_options = function() { var result, _i, _len, _ref, _results; _ref = this.results_data; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { result = _ref[_i]; if (result.selected) { _results.push(result.selected = false); } else { _results.push(void 0); } } return _results; }; AbstractChosen.prototype.results_toggle = function() { if (this.results_showing) { return this.results_hide(); } else { return this.results_show(); } }; AbstractChosen.prototype.results_search = function(evt) { if (this.results_showing) { return this.winnow_results(); } else { return this.results_show(); } }; AbstractChosen.prototype.winnow_results = function() { var escapedSearchText, option, regex, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref; this.no_results_clear(); results = 0; searchText = this.get_search_text(); escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); zregex = new RegExp(escapedSearchText, 'i'); regex = this.get_search_regex(escapedSearchText); _ref = this.results_data; for (_i = 0, _len = _ref.length; _i < _len; _i++) { option = _ref[_i]; option.search_match = false; results_group = null; if (this.include_option_in_results(option)) { if (option.group) { option.group_match = false; option.active_options = 0; } if ((option.group_array_index != null) && this.results_data[option.group_array_index]) { results_group = this.results_data[option.group_array_index]; if (results_group.active_options === 0 && results_group.search_match) { results += 1; } results_group.active_options += 1; } option.search_text = option.group ? option.label : option.html; if (!(option.group && !this.group_search)) { option.search_match = this.search_string_match(option.search_text, regex); if (option.search_match && !option.group) { results += 1; } if (option.search_match) { if (searchText.length) { startpos = option.search_text.search(zregex); text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length); option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos); } if (results_group != null) { results_group.group_match = true; } } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) { option.search_match = true; } } } } this.result_clear_highlight(); if (results < 1 && searchText.length) { this.update_results_content(""); return this.no_results(searchText); } else { this.update_results_content(this.results_option_build()); return this.winnow_results_set_highlight(); } }; AbstractChosen.prototype.get_search_regex = function(escaped_search_string) { var regex_anchor; regex_anchor = this.search_contains ? "" : "^"; return new RegExp(regex_anchor + escaped_search_string, 'i'); }; AbstractChosen.prototype.search_string_match = function(search_string, regex) { var part, parts, _i, _len; if (regex.test(search_string)) { return true; } else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) { parts = search_string.replace(/\[|\]/g, "").split(" "); if (parts.length) { for (_i = 0, _len = parts.length; _i < _len; _i++) { part = parts[_i]; if (regex.test(part)) { return true; } } } } }; AbstractChosen.prototype.choices_count = function() { var option, _i, _len, _ref; if (this.selected_option_count != null) { return this.selected_option_count; } this.selected_option_count = 0; _ref = this.form_field.options; for (_i = 0, _len = _ref.length; _i < _len; _i++) { option = _ref[_i]; if (option.selected) { this.selected_option_count += 1; } } return this.selected_option_count; }; AbstractChosen.prototype.choices_click = function(evt) { evt.preventDefault(); if (!(this.results_showing || this.is_disabled)) { return this.results_show(); } }; AbstractChosen.prototype.keyup_checker = function(evt) { var stroke, _ref; stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; this.search_field_scale(); switch (stroke) { case 8: if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) { return this.keydown_backstroke(); } else if (!this.pending_backstroke) { this.result_clear_highlight(); return this.results_search(); } break; case 13: evt.preventDefault(); if (this.results_showing) { return this.result_select(evt); } break; case 27: if (this.results_showing) { this.results_hide(); } return true; case 9: case 38: case 40: case 16: case 91: case 17: case 18: break; default: return this.results_search(); } }; AbstractChosen.prototype.clipboard_event_checker = function(evt) { var _this = this; return setTimeout((function() { return _this.results_search(); }), 50); }; AbstractChosen.prototype.container_width = function() { if (this.options.width != null) { return this.options.width; } else { return "" + this.form_field.offsetWidth + "px"; } }; AbstractChosen.prototype.include_option_in_results = function(option) { if (this.is_multiple && (!this.display_selected_options && option.selected)) { return false; } if (!this.display_disabled_options && option.disabled) { return false; } if (option.empty) { return false; } return true; }; AbstractChosen.prototype.search_results_touchstart = function(evt) { this.touch_started = true; return this.search_results_mouseover(evt); }; AbstractChosen.prototype.search_results_touchmove = function(evt) { this.touch_started = false; return this.search_results_mouseout(evt); }; AbstractChosen.prototype.search_results_touchend = function(evt) { if (this.touch_started) { return this.search_results_mouseup(evt); } }; AbstractChosen.prototype.outerHTML = function(element) { var tmp; if (element.outerHTML) { return element.outerHTML; } tmp = document.createElement("div"); tmp.appendChild(element); return tmp.innerHTML; }; AbstractChosen.browser_is_supported = function() { if (/iP(od|hone)/i.test(window.navigator.userAgent)) { return false; } if (/Android/i.test(window.navigator.userAgent)) { if (/Mobile/i.test(window.navigator.userAgent)) { return false; } } if (/IEMobile/i.test(window.navigator.userAgent)) { return false; } if (/Windows Phone/i.test(window.navigator.userAgent)) { return false; } if (/BlackBerry/i.test(window.navigator.userAgent)) { return false; } if (/BB10/i.test(window.navigator.userAgent)) { return false; } if (window.navigator.appName === "Microsoft Internet Explorer") { return document.documentMode >= 8; } return true; }; AbstractChosen.default_multiple_text = "Select Some Options"; AbstractChosen.default_single_text = "Select an Option"; AbstractChosen.default_no_result_text = "No results match"; return AbstractChosen; })(); $ = jQuery; $.fn.extend({ chosen: function(options) { if (!AbstractChosen.browser_is_supported()) { return this; } return this.each(function(input_field) { var $this, chosen; $this = $(this); chosen = $this.data('chosen'); if (options === 'destroy') { if (chosen instanceof Chosen) { chosen.destroy(); } return; } if (!(chosen instanceof Chosen)) { $this.data('chosen', new Chosen(this, options)); } }); } }); Chosen = (function(_super) { __extends(Chosen, _super); function Chosen() { _ref = Chosen.__super__.constructor.apply(this, arguments); return _ref; } Chosen.prototype.setup = function() { this.form_field_jq = $(this.form_field); this.current_selectedIndex = this.form_field.selectedIndex; return this.is_rtl = this.form_field_jq.hasClass("chosen-rtl"); }; Chosen.prototype.set_up_html = function() { var container_classes, container_props; container_classes = ["chosen-container"]; container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single")); if (this.inherit_select_classes && this.form_field.className) { container_classes.push(this.form_field.className); } if (this.is_rtl) { container_classes.push("chosen-rtl"); } container_props = { 'class': container_classes.join(' '), 'style': "width: " + (this.container_width()) + ";", 'title': this.form_field.title }; if (this.form_field.id.length) { container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen"; } this.container = $("<div />", container_props); if (this.is_multiple) { this.container.html('<ul class="chosen-choices"><li class="search-field"><input type="text" value="' + this.default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>'); } else { this.container.html('<a class="chosen-single chosen-default"><span>' + this.default_text + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>'); } this.form_field_jq.hide().after(this.container); this.dropdown = this.container.find('div.chosen-drop').first(); this.search_field = this.container.find('input').first(); this.search_results = this.container.find('ul.chosen-results').first(); this.search_field_scale(); this.search_no_results = this.container.find('li.no-results').first(); if (this.is_multiple) { this.search_choices = this.container.find('ul.chosen-choices').first(); this.search_container = this.container.find('li.search-field').first(); } else { this.search_container = this.container.find('div.chosen-search').first(); this.selected_item = this.container.find('.chosen-single').first(); } this.results_build(); this.set_tab_index(); return this.set_label_behavior(); }; Chosen.prototype.on_ready = function() { return this.form_field_jq.trigger("chosen:ready", { chosen: this }); }; Chosen.prototype.register_observers = function() { var _this = this; this.container.bind('touchstart.chosen', function(evt) { _this.container_mousedown(evt); return evt.preventDefault(); }); this.container.bind('touchend.chosen', function(evt) { _this.container_mouseup(evt); return evt.preventDefault(); }); this.container.bind('mousedown.chosen', function(evt) { _this.container_mousedown(evt); }); this.container.bind('mouseup.chosen', function(evt) { _this.container_mouseup(evt); }); this.container.bind('mouseenter.chosen', function(evt) { _this.mouse_enter(evt); }); this.container.bind('mouseleave.chosen', function(evt) { _this.mouse_leave(evt); }); this.search_results.bind('mouseup.chosen', function(evt) { _this.search_results_mouseup(evt); }); this.search_results.bind('mouseover.chosen', function(evt) { _this.search_results_mouseover(evt); }); this.search_results.bind('mouseout.chosen', function(evt) { _this.search_results_mouseout(evt); }); this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) { _this.search_results_mousewheel(evt); }); this.search_results.bind('touchstart.chosen', function(evt) { _this.search_results_touchstart(evt); }); this.search_results.bind('touchmove.chosen', function(evt) { _this.search_results_touchmove(evt); }); this.search_results.bind('touchend.chosen', function(evt) { _this.search_results_touchend(evt); }); this.form_field_jq.bind("chosen:updated.chosen", function(evt) { _this.results_update_field(evt); }); this.form_field_jq.bind("chosen:activate.chosen", function(evt) { _this.activate_field(evt); }); this.form_field_jq.bind("chosen:open.chosen", function(evt) { _this.container_mousedown(evt); }); this.form_field_jq.bind("chosen:close.chosen", function(evt) { _this.input_blur(evt); }); this.search_field.bind('blur.chosen', function(evt) { _this.input_blur(evt); }); this.search_field.bind('keyup.chosen', function(evt) { _this.keyup_checker(evt); }); this.search_field.bind('keydown.chosen', function(evt) { _this.keydown_checker(evt); }); this.search_field.bind('focus.chosen', function(evt) { _this.input_focus(evt); }); this.search_field.bind('cut.chosen', function(evt) { _this.clipboard_event_checker(evt); }); this.search_field.bind('paste.chosen', function(evt) { _this.clipboard_event_checker(evt); }); if (this.is_multiple) { return this.search_choices.bind('click.chosen', function(evt) { _this.choices_click(evt); }); } else { return this.container.bind('click.chosen', function(evt) { evt.preventDefault(); }); } }; Chosen.prototype.destroy = function() { $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action); if (this.search_field[0].tabIndex) { this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex; } this.container.remove(); this.form_field_jq.removeData('chosen'); return this.form_field_jq.show(); }; Chosen.prototype.search_field_disabled = function() { this.is_disabled = this.form_field_jq[0].disabled; if (this.is_disabled) { this.container.addClass('chosen-disabled'); this.search_field[0].disabled = true; if (!this.is_multiple) { this.selected_item.unbind("focus.chosen", this.activate_action); } return this.close_field(); } else { this.container.removeClass('chosen-disabled'); this.search_field[0].disabled = false; if (!this.is_multiple) { return this.selected_item.bind("focus.chosen", this.activate_action); } } }; Chosen.prototype.container_mousedown = function(evt) { if (!this.is_disabled) { if (evt && evt.type === "mousedown" && !this.results_showing) { evt.preventDefault(); } if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) { if (!this.active_field) { if (this.is_multiple) { this.search_field.val(""); } $(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action); this.results_show(); } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) { evt.preventDefault(); this.results_toggle(); } return this.activate_field(); } } }; Chosen.prototype.container_mouseup = function(evt) { if (evt.target.nodeName === "ABBR" && !this.is_disabled) { return this.results_reset(evt); } }; Chosen.prototype.search_results_mousewheel = function(evt) { var delta; if (evt.originalEvent) { delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail; } if (delta != null) { evt.preventDefault(); if (evt.type === 'DOMMouseScroll') { delta = delta * 40; } return this.search_results.scrollTop(delta + this.search_results.scrollTop()); } }; Chosen.prototype.blur_test = function(evt) { if (!this.active_field && this.container.hasClass("chosen-container-active")) { return this.close_field(); } }; Chosen.prototype.close_field = function() { $(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action); this.active_field = false; this.results_hide(); this.container.removeClass("chosen-container-active"); this.clear_backstroke(); this.show_search_field_default(); return this.search_field_scale(); }; Chosen.prototype.activate_field = function() { this.container.addClass("chosen-container-active"); this.active_field = true; this.search_field.val(this.search_field.val()); return this.search_field.focus(); }; Chosen.prototype.test_active_click = function(evt) { var active_container; active_container = $(evt.target).closest('.chosen-container'); if (active_container.length && this.container[0] === active_container[0]) { return this.active_field = true; } else { return this.close_field(); } }; Chosen.prototype.results_build = function() { this.parsing = true; this.selected_option_count = null; this.results_data = SelectParser.select_to_array(this.form_field); if (this.is_multiple) { this.search_choices.find("li.search-choice").remove(); } else if (!this.is_multiple) { this.single_set_selected_text(); if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) { this.search_field[0].readOnly = true; this.container.addClass("chosen-container-single-nosearch"); } else { this.search_field[0].readOnly = false; this.container.removeClass("chosen-container-single-nosearch"); } } this.update_results_content(this.results_option_build({ first: true })); this.search_field_disabled(); this.show_search_field_default(); this.search_field_scale(); return this.parsing = false; }; Chosen.prototype.result_do_highlight = function(el) { var high_bottom, high_top, maxHeight, visible_bottom, visible_top; if (el.length) { this.result_clear_highlight(); this.result_highlight = el; this.result_highlight.addClass("highlighted"); maxHeight = parseInt(this.search_results.css("maxHeight"), 10); visible_top = this.search_results.scrollTop(); visible_bottom = maxHeight + visible_top; high_top = this.result_highlight.position().top + this.search_results.scrollTop(); high_bottom = high_top + this.result_highlight.outerHeight(); if (high_bottom >= visible_bottom) { return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0); } else if (high_top < visible_top) { return this.search_results.scrollTop(high_top); } } }; Chosen.prototype.result_clear_highlight = function() { if (this.result_highlight) { this.result_highlight.removeClass("highlighted"); } return this.result_highlight = null; }; Chosen.prototype.results_show = function() { if (this.is_multiple && this.max_selected_options <= this.choices_count()) { this.form_field_jq.trigger("chosen:maxselected", { chosen: this }); return false; } this.container.addClass("chosen-with-drop"); this.results_showing = true; this.search_field.focus(); this.search_field.val(this.search_field.val()); this.winnow_results(); return this.form_field_jq.trigger("chosen:showing_dropdown", { chosen: this }); }; Chosen.prototype.update_results_content = function(content) { return this.search_results.html(content); }; Chosen.prototype.results_hide = function() { if (this.results_showing) { this.result_clear_highlight(); this.container.removeClass("chosen-with-drop"); this.form_field_jq.trigger("chosen:hiding_dropdown", { chosen: this }); } return this.results_showing = false; }; Chosen.prototype.set_tab_index = function(el) { var ti; if (this.form_field.tabIndex) { ti = this.form_field.tabIndex; this.form_field.tabIndex = -1; return this.search_field[0].tabIndex = ti; } }; Chosen.prototype.set_label_behavior = function() { var _this = this; this.form_field_label = this.form_field_jq.parents("label"); if (!this.form_field_label.length && this.form_field.id.length) { this.form_field_label = $("label[for='" + this.form_field.id + "']"); } if (this.form_field_label.length > 0) { return this.form_field_label.bind('click.chosen', function(evt) { if (_this.is_multiple) { return _this.container_mousedown(evt); } else { return _this.activate_field(); } }); } }; Chosen.prototype.show_search_field_default = function() { if (this.is_multiple && this.choices_count() < 1 && !this.active_field) { this.search_field.val(this.default_text); return this.search_field.addClass("default"); } else { this.search_field.val(""); return this.search_field.removeClass("default"); } }; Chosen.prototype.search_results_mouseup = function(evt) { var target; target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); if (target.length) { this.result_highlight = target; this.result_select(evt); return this.search_field.focus(); } }; Chosen.prototype.search_results_mouseover = function(evt) { var target; target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); if (target) { return this.result_do_highlight(target); } }; Chosen.prototype.search_results_mouseout = function(evt) { if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) { return this.result_clear_highlight(); } }; Chosen.prototype.choice_build = function(item) { var choice, close_link, _this = this; choice = $('<li />', { "class": "search-choice" }).html("<span>" + (this.choice_label(item)) + "</span>"); if (item.disabled) { choice.addClass('search-choice-disabled'); } else { close_link = $('<a />', { "class": 'search-choice-close', 'data-option-array-index': item.array_index }); close_link.bind('click.chosen', function(evt) { return _this.choice_destroy_link_click(evt); }); choice.append(close_link); } return this.search_container.before(choice); }; Chosen.prototype.choice_destroy_link_click = function(evt) { evt.preventDefault(); evt.stopPropagation(); if (!this.is_disabled) { return this.choice_destroy($(evt.target)); } }; Chosen.prototype.choice_destroy = function(link) { if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) { this.show_search_field_default(); if (this.is_multiple && this.choices_count() > 0 && this.search_field.val().length < 1) { this.results_hide(); } link.parents('li').first().remove(); return this.search_field_scale(); } }; Chosen.prototype.results_reset = function() { this.reset_single_select_options(); this.form_field.options[0].selected = true; this.single_set_selected_text(); this.show_search_field_default(); this.results_reset_cleanup(); this.form_field_jq.trigger("change"); if (this.active_field) { return this.results_hide(); } }; Chosen.prototype.results_reset_cleanup = function() { this.current_selectedIndex = this.form_field.selectedIndex; return this.selected_item.find("abbr").remove(); }; Chosen.prototype.result_select = function(evt) { var high, item; if (this.result_highlight) { high = this.result_highlight; this.result_clear_highlight(); if (this.is_multiple && this.max_selected_options <= this.choices_count()) { this.form_field_jq.trigger("chosen:maxselected", { chosen: this }); return false; } if (this.is_multiple) { high.removeClass("active-result"); } else { this.reset_single_select_options(); } high.addClass("result-selected"); item = this.results_data[high[0].getAttribute("data-option-array-index")]; item.selected = true; this.form_field.options[item.options_index].selected = true; this.selected_option_count = null; if (this.is_multiple) { this.choice_build(item); } else { this.single_set_selected_text(this.choice_label(item)); } if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) { this.results_hide(); } this.show_search_field_default(); if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) { this.form_field_jq.trigger("change", { 'selected': this.form_field.options[item.options_index].value }); } this.current_selectedIndex = this.form_field.selectedIndex; evt.preventDefault(); return this.search_field_scale(); } }; Chosen.prototype.single_set_selected_text = function(text) { if (text == null) { text = this.default_text; } if (text === this.default_text) { this.selected_item.addClass("chosen-default"); } else { this.single_deselect_control_build(); this.selected_item.removeClass("chosen-default"); } return this.selected_item.find("span").html(text); }; Chosen.prototype.result_deselect = function(pos) { var result_data; result_data = this.results_data[pos]; if (!this.form_field.options[result_data.options_index].disabled) { result_data.selected = false; this.form_field.options[result_data.options_index].selected = false; this.selected_option_count = null; this.result_clear_highlight(); if (this.results_showing) { this.winnow_results(); } this.form_field_jq.trigger("change", { deselected: this.form_field.options[result_data.options_index].value }); this.search_field_scale(); return true; } else { return false; } }; Chosen.prototype.single_deselect_control_build = function() { if (!this.allow_single_deselect) { return; } if (!this.selected_item.find("abbr").length) { this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>"); } return this.selected_item.addClass("chosen-single-with-deselect"); }; Chosen.prototype.get_search_text = function() { return $('<div/>').text($.trim(this.search_field.val())).html(); }; Chosen.prototype.winnow_results_set_highlight = function() { var do_high, selected_results; selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : []; do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first(); if (do_high != null) { return this.result_do_highlight(do_high); } }; Chosen.prototype.no_results = function(terms) { var no_results_html; no_results_html = $('<li class="no-results">' + this.results_none_found + ' "<span></span>"</li>'); no_results_html.find("span").first().html(terms); this.search_results.append(no_results_html); return this.form_field_jq.trigger("chosen:no_results", { chosen: this }); }; Chosen.prototype.no_results_clear = function() { return this.search_results.find(".no-results").remove(); }; Chosen.prototype.keydown_arrow = function() { var next_sib; if (this.results_showing && this.result_highlight) { next_sib = this.result_highlight.nextAll("li.active-result").first(); if (next_sib) { return this.result_do_highlight(next_sib); } } else { return this.results_show(); } }; Chosen.prototype.keyup_arrow = function() { var prev_sibs; if (!this.results_showing && !this.is_multiple) { return this.results_show(); } else if (this.result_highlight) { prev_sibs = this.result_highlight.prevAll("li.active-result"); if (prev_sibs.length) { return this.result_do_highlight(prev_sibs.first()); } else { if (this.choices_count() > 0) { this.results_hide(); } return this.result_clear_highlight(); } } }; Chosen.prototype.keydown_backstroke = function() { var next_available_destroy; if (this.pending_backstroke) { this.choice_destroy(this.pending_backstroke.find("a").first()); return this.clear_backstroke(); } else { next_available_destroy = this.search_container.siblings("li.search-choice").last(); if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) { this.pending_backstroke = next_available_destroy; if (this.single_backstroke_delete) { return this.keydown_backstroke(); } else { return this.pending_backstroke.addClass("search-choice-focus"); } } } }; Chosen.prototype.clear_backstroke = function() { if (this.pending_backstroke) { this.pending_backstroke.removeClass("search-choice-focus"); } return this.pending_backstroke = null; }; Chosen.prototype.keydown_checker = function(evt) { var stroke, _ref1; stroke = (_ref1 = evt.which) != null ? _ref1 : evt.keyCode; this.search_field_scale(); if (stroke !== 8 && this.pending_backstroke) { this.clear_backstroke(); } switch (stroke) { case 8: this.backstroke_length = this.search_field.val().length; break; case 9: if (this.results_showing && !this.is_multiple) { this.result_select(evt); } this.mouse_on_container = false; break; case 13: if (this.results_showing) { evt.preventDefault(); } break; case 32: if (this.disable_search) { evt.preventDefault(); } break; case 38: evt.preventDefault(); this.keyup_arrow(); break; case 40: evt.preventDefault(); this.keydown_arrow(); break; } }; Chosen.prototype.search_field_scale = function() { var div, f_width, h, style, style_block, styles, w, _i, _len; if (this.is_multiple) { h = 0; w = 0; style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"; styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing']; for (_i = 0, _len = styles.length; _i < _len; _i++) { style = styles[_i]; style_block += style + ":" + this.search_field.css(style) + ";"; } div = $('<div />', { 'style': style_block }); div.text(this.search_field.val()); $('body').append(div); w = div.width() + 25; div.remove(); f_width = this.container.outerWidth(); if (w > f_width - 10) { w = f_width - 10; } return this.search_field.css({ 'width': w + 'px' }); } }; return Chosen; })(AbstractChosen); }).call(this); }).apply(root, arguments); }); }(this)); (function(root) { define("angular-chosen", ["angular","jquery-chosen"], function() { return (function() { /** * angular-chosen-localytics - Angular Chosen directive is an AngularJS Directive that brings the Chosen jQuery in a Angular way * @version v1.3.0 * @link http://github.com/leocaseiro/angular-chosen * @license MIT */ (function() { var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; angular.module('localytics.directives', []); angular.module('localytics.directives').directive('chosen', [ '$timeout', function($timeout) { var CHOSEN_OPTION_WHITELIST, NG_OPTIONS_REGEXP, isEmpty, snakeCase; NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/; CHOSEN_OPTION_WHITELIST = ['persistentCreateOption', 'createOptionText', 'createOption', 'skipNoResults', 'noResultsText', 'allowSingleDeselect', 'disableSearchThreshold', 'disableSearch', 'enableSplitWordSearch', 'inheritSelectClasses', 'maxSelectedOptions', 'placeholderTextMultiple', 'placeholderTextSingle', 'searchContains', 'singleBackstrokeDelete', 'displayDisabledOptions', 'displaySelectedOptions', 'width', 'includeGroupLabelInSelected', 'maxShownResults']; snakeCase = function(input) { return input.replace(/[A-Z]/g, function($1) { return "_" + ($1.toLowerCase()); }); }; isEmpty = function(value) { var key; if (angular.isArray(value)) { return value.length === 0; } else if (angular.isObject(value)) { for (key in value) { if (value.hasOwnProperty(key)) { return false; } } } return true; }; return { restrict: 'A', require: '?ngModel', priority: 1, link: function(scope, element, attr, ngModel) { var chosen, empty, initOrUpdate, match, options, origRender, startLoading, stopLoading, updateMessage, valuesExpr, viewWatch; scope.disabledValuesHistory = scope.disabledValuesHistory ? scope.disabledValuesHistory : []; element = $(element); element.addClass('localytics-chosen'); options = scope.$eval(attr.chosen) || {}; angular.forEach(attr, function(value, key) { if (indexOf.call(CHOSEN_OPTION_WHITELIST, key) >= 0) { return attr.$observe(key, function(value) { options[snakeCase(key)] = String(element.attr(attr.$attr[key])).slice(0, 2) === '{{' ? value : scope.$eval(value); return updateMessage(); }); } }); startLoading = function() { return element.addClass('loading').attr('disabled', true).trigger('chosen:updated'); }; stopLoading = function() { element.removeClass('loading'); if (angular.isDefined(attr.disabled)) { element.attr('disabled', attr.disabled); } else { element.attr('disabled', false); } return element.trigger('chosen:updated'); }; chosen = null; empty = false; initOrUpdate = function() { var defaultText; if (chosen) { return element.trigger('chosen:updated'); } else { $timeout(function() { chosen = element.chosen(options).data('chosen'); }); if (angular.isObject(chosen)) { return defaultText = chosen.default_text; } } }; updateMessage = function() { if (empty) { element.attr('data-placeholder', chosen.results_none_found).attr('disabled', true); } else { element.removeAttr('data-placeholder'); } return element.trigger('chosen:updated'); }; if (ngModel) { origRender = ngModel.$render; ngModel.$render = function() { origRender(); return initOrUpdate(); }; element.on('chosen:hiding_dropdown', function() { return scope.$apply(function() { return ngModel.$setTouched(); }); }); if (attr.multiple) { viewWatch = function() { return ngModel.$viewValue; }; scope.$watch(viewWatch, ngModel.$render, true); } } else { initOrUpdate(); } attr.$observe('disabled', function() { return element.trigger('chosen:updated'); }); if (attr.ngOptions && ngModel) { match = attr.ngOptions.match(NG_OPTIONS_REGEXP); valuesExpr = match[7]; scope.$watchCollection(valuesExpr, function(newVal, oldVal) { var timer; return timer = $timeout(function() { if (angular.isUndefined(newVal)) { return startLoading(); } else { empty = isEmpty(newVal); stopLoading(); return updateMessage(); } }); }); return scope.$on('$destroy', function(event) { if (typeof timer !== "undefined" && timer !== null) { return $timeout.cancel(timer); } }); } } }; } ]); }).call(this); }).apply(root, arguments); }); }(this)); /* # templates/transfer_tool/filters/startFromFilter.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( 'app/filters/startFromFilter',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } /** * Angular filter which returns array started at position defined by start * @return {array} */ app.filter("startFrom", function() { return function(input, start) { if (input && angular.isArray(input)) { start = Number(start); // parse to int return input.slice(start); } }; }); } ); /* # templates/transfer_tool/filters/cpLimitToFilter.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( 'app/filters/cpLimitToFilter',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } // Main - reusable /** * Angular filter that limits arrays to a defined limit * @return {array} */ app.filter("cpLimitTo", function() { return function(input, limit) { return limit ? input.slice(0, limit) : input; }; }); } ); /* # cpanel - templates/transfer_tool/controllers/MainController.js # Copyright(c) 2021 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, PAGE */ /* jshint -W003 */ /** * @class Class constructor for the main controller * @param {object} $scope * @param {object} $filter */ define( 'app/controllers/MainController',[ "angular", "cjt/util/locale", "cjt/directives/pageSizeDirective", "../filters/startFromFilter", "../filters/cpLimitToFilter", ], function(angular, LOCALE) { "use strict"; var CONTROLLER_INJECTABLES = ["$scope", "$log", "$filter", "PAGE", "OVERWRITE_OPTIONS", "OVERWRITE_STATES"]; var MainController = function($scope, $log, $filter, PAGE, OVERWRITE_OPTIONS, OVERWRITE_STATES) { var _this = this; _this._log = $log; _this.PAGE = PAGE; _this.REMAINING_ACCOUNT_SLOTS = parseInt(PAGE.REMAINING_ACCOUNT_SLOTS, 10); _this.SERVER_MAX_USERS = parseInt(PAGE.SERVER_MAX_USERS, 10); _this.pkgTable = { currentPage: 1, pageSize: 10, reverse: false, order: "name", }; _this.overwriteStates = OVERWRITE_STATES; // Determine if cPanel version is less than 11.55. _this.olderRemote = parseInt(_this.PAGE.remote.version.split(".")[1]) < 55; var serverType = LOCALE.maketext("Unknown"); if (_this.PAGE.remote.server_type.match(/WHM/)) { serverType = "WHM " + _this.PAGE.remote.version; } else { serverType = _this.PAGE.remote.server_type + " " + _this.PAGE.remote.version; } var isCpanel = true; if ( !serverType.match(/WHM/) ) { isCpanel = false; } _this.meta = { server_type: serverType, is_cpanel: isCpanel, panel_name: _this.PAGE.remote.server_type, }; _this.LOCALE = LOCALE; // Set default values - this checks them _this.control_bwdata = true; _this.control_homedir = true; _this.control_databases = true; _this.control_reseller_privs = true; // Packages / Main angular.forEach(_this.PAGE.items.packages, function(val, key) { _this.PAGE.items.packages[key].selected = 0; }); _this.PAGE.domainsWithDedicatedIp = {}; angular.forEach(_this.PAGE.local.dedicated_ips, function(value, key) { this[value] = true; }, _this.PAGE.domainsWithDedicatedIp); var startFrom = $filter("startFrom"), orderBy = $filter("orderBy"), limitTo = $filter("cpLimitTo"), filter = $filter("filter"); _this.existingUsersFilter = $filter("existingUsers"); _this.selectedAccounts = filter(_this.PAGE.items.accounts, { selected: 1, }); _this.selectedPackages = filter(_this.PAGE.items.packages, { selected: 1, }); // To better understand what these assignments are look at updateFilteredPackages and updateViewablePackages _this.filteredPackages = filter(_this.PAGE.items.packages, _this.pkgsFilter); _this.viewablePackages = limitTo(startFrom(orderBy(_this.filteredPackages, _this.pkgTable.order, _this.pkgTable.reverse), (_this.pkgTable.currentPage - 1) * _this.pkgTable.pageSize), _this.pkgTable.pageSize); /** * Updates the selectedPackages array based on what packages are selected */ _this.updateSelectedPackages = function() { _this.selectedPackages = filter(this.PAGE.items.packages, { selected: 1, }); }; _this.updateSelectedConfigurations = function() { _this.selectedConfigurations = []; angular.forEach(_this.PAGE.configuration_modules, function(value, key) { if (value.selected) { var config = {}; config[key + "_enabled"] = 1; _this.selectedConfigurations.push( config ); } }); }; _this.updateSelectedConfigurations(); /** * Dispatches Event to be caught by AccountTableController */ _this.recheckUsers = function(dataset) { $scope.$broadcast("recheckUsersCalled", { dataset: dataset, }); }; /** * Updates the selectedAccounts array based on what packages are selected */ _this.updateSelectedAccounts = function() { _this.selectedAccounts = filter(this.PAGE.items.accounts, { selected: 1, }); }; /** * Reapplies filters for the filteredPackages array * Array -> Filtered by pkgsFilter * packages | filter:pkgsFilter */ _this.updateFilteredPackages = function() { _this.filteredPackages = filter(this.PAGE.items.packages, this.pkgsFilter); }; /** * Reapplies filteres for the viewablePackages array. * FilteredPackages -> Ordered by(reverse?) -> start at page# * pageSize -> limit to page size * filteredPackages | orderBy: acctTable.order:acctTable.reverse | startFrom:(acctTable.currentPage - 1 ) * acctTable.pageSize | limitTo: acctTable.pageSize */ _this.updateViewablePackages = function() { _this.viewablePackages = limitTo(startFrom(orderBy(_this.filteredPackages, _this.pkgTable.order, _this.pkgTable.reverse), (_this.pkgTable.currentPage - 1) * _this.pkgTable.pageSize), _this.pkgTable.pageSize); }; _this.getPossiblePageSizes = function() { return _this.PAGE.all_possible_page_sizes; }; /** * Returns true if the source account is being assigned a new dedicated ip. * @param {object} item Account object * @return {Boolean} */ _this.newDedicatedIpFilter = function(item) { if (!item.dedicated_ip) { return false; } return !_this.PAGE.domainsWithDedicatedIp[item.domain]; }; _this.toArray = function() { _this.configuration_modules = []; angular.forEach(_this.PAGE.configuration_modules, function(val, key) { var analysis = []; angular.forEach(val.analysis, function(analysisValue, analysisKey) { analysis.push({ analysis: analysisValue, analysisKey: analysisKey }); }); val.analysis = analysis; _this.configuration_modules.push({ key: key, value: val }); }); }; _this.overwriteIsDefault = function overwriteIsDefault(item) { return item.overwrite_type.value === _this.overwriteStates.NO_OVERWRITE; }; _this.overwriteOptions = OVERWRITE_OPTIONS; // If no viewable accounts are selected, make sure the checkbox is unchecked. $scope.$watch(function() { return _this.selectedAccounts.length; }, function(newVal) { if (!newVal) { $scope.$broadcast("selectedAccountsEmptied", {}); } }); $scope.$watch(function() { return _this.pkgTable; }, function() { _this.updateViewablePackages(); }, true); _this.toArray(); return _this; }; /** * Function that updates both filtered and viewable packages array results */ MainController.prototype.updatePackages = function() { this.updateFilteredPackages(); this.updateViewablePackages(); }; MainController.prototype.updateConfigurations = function() { this.updateSelectedConfigurations(); }; /** * Returns 'icon-arrow-up' or 'icon-arrow-down' if column is selected for ordering. The result is based on what order. Used to indicate sort order. * @param {objec} tableOptionsObj * @param {string} column * @return {string|Boolean} */ MainController.prototype.selectedHeaderClass = function(tableOptionsObj, column) { var className = "icon-arrow-" + (tableOptionsObj.reverse ? "down" : "up"); return column === tableOptionsObj.order && className; }; /** * Returns 'active' if column is selected for ordering. Used to highlight selected column. * @param {object} tableOptionsObj * @param {string} column * @return {string|Boolean} */ MainController.prototype.selectedColClass = function(tableOptionsObj, column) { return column === tableOptionsObj.order && "active"; }; /** * Takes in an array of accounts and sets the attr of each account to a value of 1 or 0 corresponding to isChecked. 1 or 0 for Perl parsing after form submit. * @param {array} dataset * @param {string} attr * @param {Boolean} isChecked */ MainController.prototype.toggleCheckAll = function(dataset, attr, isChecked) { var newValue; if (attr === "overwrite_type") { newValue = isChecked; } else { newValue = isChecked ? 1 : 0; } angular.forEach(dataset, function(o) { o[attr] = newValue; }); }; MainController.prototype.toggleCheckAllAndReValidate = function(dataset, attr, isChecked) { var _this = this; _this.toggleCheckAll.apply(_this, arguments); /* selected accounts list must be updated before validation can occur */ _this.updateSelectedAccounts(); _this.recheckUsers(dataset); }; /** * Sets the order and reverse attributes for tableOptions. Used for column sorting. * @param {object} tableOptionsObj * @param {string} fieldName */ MainController.prototype.toggleSort = function(tableOptionsObj, fieldName) { tableOptionsObj.reverse = (tableOptionsObj.order === fieldName ? !tableOptionsObj.reverse : 0); tableOptionsObj.order = fieldName; }; /** * Returns true if the account is selected and has an invalid user * @param {object} item * @return {Boolean} */ MainController.prototype.invalidUserFilter = function(item) { return item.selected && item.invalidUser; }; /** * Returns true if the account's local name has not changed from the remote name. * @param {object} item * @return {Boolean} */ MainController.prototype.noUsernameChange = function(item) { return item.localuser === item.remote_user; }; /** * Returns true if the account matches a reserved account name on the file system * @param {object} item * @return {Boolean} */ MainController.prototype.reservedUserFilter = function(item) { return item.selected && item.invalidUser && item.userCheckStates.reserved; }; /** * Returns true if the account username matches another name selected for importation * @param {object} item * @return {Boolean} */ MainController.prototype.duplicateUserFilter = function(item) { return item.selected && !!item.localuser && item.invalidUser && item.userCheckStates.duplicate; }; /** * Returns true if the account does not match the system regular expression requirements * @param {object} item * @return {Boolean} */ MainController.prototype.invalidUsernameFilter = function(item) { return item.selected && item.invalidUser && item.userCheckStates.invalid; }; /** * Returns true if the account is selected and has an invalid domain. * @param {object} item * @return {Boolean} */ MainController.prototype.invalidDomainFilter = function(item) { return item.selected && item.invalidDomain; }; /** * Returns true if the account is selected, the user is a reseller on the source server, * and the reseller privileges are not being transferred. * @param {object} item * @return {Boolean} */ MainController.prototype.resellerNoCopyFilter = function(item) { return item.selected && item.is_reseller && !item.copy_reseller_privs; }; MainController.prototype.canNotTransferTempDomainFilter = function(item) { return item.selected && item.isTempDomain && !item.serverSupportsTempDomains; }; /** * Revalidates all account usernames in provided array * @param {array} array */ MainController.prototype.reValidateDomainAndUsernameFor = function(array) { if (!array) { return; } for (var x = 0; x < array.length; x++) { var username = array[x].localuser || ""; if (!username.length) { username = array[x].remote_user; } array[x].invalidUser = this.PAGE.local.users[username] && !array[x].invalidDomain && array[x].overwrite_type === this.overwriteOptions[0] ? 1 : 0; } }; /** * Returns message based on the way in which an account matches a local account. * @param {object} acct * @return {String} */ MainController.prototype.getExistingUserMessage = function(acct) { var incomingLocal = acct.localuser; var matchedLocal = acct.similarLocalUser; if (incomingLocal === matchedLocal) { return this.LOCALE.maketext("The remote account “[_1]” cannot transfer because an account with the same username exists on the local server.", incomingLocal); } else { return this.LOCALE.maketext("The remote account “[_1]” cannot transfer because the first [quant,_3,non-special character matches,non-special characters match] the local username “[_2]”.", incomingLocal, matchedLocal, this.PAGE.USERNAME_UNIQUE_LENGTH); } }; MainController.prototype.existingAccountWarning = function(acctCount) { return LOCALE.maketext("[output,strong,Error]: You have selected [quant,_1,account transfer,account transfers] that will not complete properly because the [numerate,_1,username,usernames] already [numerate,_1,exists,exist] on the local server.", acctCount) + " " + LOCALE.maketext("To resolve this, you can overwrite the local [numerate,_1,account,accounts], rename the incoming [numerate,_1,account,accounts], or deselect the [numerate,_1,account,accounts].", acctCount); }; MainController.prototype.existingDomainWarning = function(domainCount) { return LOCALE.maketext("[output,strong,Error]: You have selected [quant,_1,account transfer,account transfers] that will not complete properly because of [numerate,_1,a domain conflict,domain conflicts].", domainCount) + " " + LOCALE.maketext("This is due to [numerate,_1,an existing domain,existing domains] that [numerate,_1,matches an incoming domain,match incoming domains] but [numerate,_1,does,do] not match the local [numerate,_1,username,usernames].", domainCount) + " " + LOCALE.maketext("To resolve this, remove the matching [numerate,_1,domain,domains] from the local machine for any [numerate,_1,account,accounts] that you wish to transfer.", domainCount); }; MainController.prototype.dedicatedIpAddrWarning = function(ipsToAdd, availableIps) { return LOCALE.maketext("[output,strong,Error]: You have selected [numf,_1] of [quant,_2,available IP address,available IP addresses]. Either deselect an account to transfer, or deselect its corresponding “[_3]” field.", ipsToAdd, availableIps, LOCALE.maketext("Dedicated IP Address")); }; MainController.prototype.frontPageWarning = function(fpAccts) { return LOCALE.maketext("[output,strong,Warning]: You selected [quant,_1,account,accounts] that use [asis,Microsoft® FrontPage Extensions] on the source server. The local server does not support [asis,FrontPage]. To resolve this issue, disable [asis,FrontPage] for each account before you attempt the transfer.", fpAccts); }; MainController.prototype.unusedDedicatedIpWarning = function(unusedDedIpAcctCount) { return LOCALE.maketext("[output,strong,Warning]: You have selected [quant,_1,account,accounts] which previously had a dedicated [asis,IP] address but you have chosen not to assign one after transfer.", unusedDedIpAcctCount); }; MainController.prototype.packageFilterMessage = function() { return (this.pkgsFilter) ? LOCALE.maketext("Your search matched [numf,_1] of [quant,_2,record,records].", this.filteredPackages.length, this.PAGE.items.packages.length) : LOCALE.maketext("There [numerate,_1,is,are] [quant,_1,record,records].", this.PAGE.items.packages.length); }; MainController.prototype.packageSelectedMessage = function() { return LOCALE.maketext("[_1] selected", this.selectedPackages.length || 0);// this.PAGE.items.packages | filter:{selected: 1}).length); }; MainController.prototype.accountFilterMessage = function(acctCount) { return (acctCount !== this.PAGE.items.accounts.length) ? LOCALE.maketext("Your search matched [numf,_1] of [quant,_2,record,records].", acctCount || 0, this.PAGE.items.accounts.length) : LOCALE.maketext("There [numerate,_1,is,are] [quant,_1,record,records].", this.PAGE.items.accounts.length); }; MainController.prototype.accountSelectedMessage = function(acctCount) { return LOCALE.maketext("[quant,_1,account,accounts] selected.", acctCount || 0); }; MainController.prototype.accountConflictSelectedMessage = function(count) { return LOCALE.maketext("You have selected [quant,_1,account,accounts] that cannot transfer properly because [numerate,_1,its username conflicts,their usernames conflict] with [numerate,_1,a username,usernames] on the local server.", count); }; MainController.prototype.licenseOverloadMessage = function() { if (this.REMAINING_ACCOUNT_SLOTS === 0) { return LOCALE.maketext("Because the destination server’s license is limited to [quant,_1,account,accounts], you can only overwrite existing accounts.", this.SERVER_MAX_USERS); } else { return LOCALE.maketext("Because the destination server’s license is limited to [quant,_1,account,accounts], you can only transfer [quant,_2,account,accounts].", this.SERVER_MAX_USERS, this.REMAINING_ACCOUNT_SLOTS); } }; MainController.prototype.licenseOverloadCancelMessage = function(count) { return LOCALE.maketext("Deselect [quant,_1,account,accounts] to continue.", count); }; MainController.prototype.accountOverwriteResolveMessage = function(count) { return LOCALE.maketext("To resolve this issue, you can overwrite the local [numerate,_1,account,accounts], rename the incoming [numerate,_1,account,accounts] so that the first [quant,_2,alphanumeric character,alphanumeric characters] do not match those of any local accounts, or deselect the [numerate,_1,account,accounts]. These options are mutually exclusive.", count, this.PAGE.USERNAME_UNIQUE_LENGTH); }; MainController.prototype.accountOverwriteConfirmMessage = function(count) { return LOCALE.maketext("Overwrite conflicted [numerate,_1,account,accounts]", count); }; MainController.prototype.accountConflictCancelMessage = function(count) { return LOCALE.maketext("Deselect conflicted [numerate,_1,account,accounts]", count); }; MainController.prototype.accountConflictResolveMessage = function(count) { return LOCALE.maketext("To resolve this issue, you can rename the incoming [numerate,_1,account,accounts] so that the first [quant,_2,alphanumeric character,alphanumeric characters] do not match those of any local accounts, or deselect the [numerate,_1,account,accounts].", count, this.PAGE.USERNAME_UNIQUE_LENGTH); }; MainController.prototype.accountConflictSelectedResolveMessage = function(count) { return LOCALE.maketext("You have selected [quant,_1,account transfer,account transfers] that will not complete properly because the [numerate,_1,username is,usernames are] reserved on the local server. To resolve this, you can either rename the incoming [numerate,_1,account,accounts] or deselect the [numerate,_1,account,accounts].", count); }; MainController.prototype.accountConflictNameResolveMessage = function(count) { return LOCALE.maketext("The following [quant,_1,remote user is set,remote users are set] to migrate with [numerate,_1,a new name,new names] whose first [quant,_2,character conflicts,characters conflict] with one or more other proposed new usernames. To resolve this, you can either rename the incoming [numerate,_1,account,accounts] or deselect [numerate,_1,it,them].", count, this.PAGE.USERNAME_UNIQUE_LENGTH); }; MainController.prototype.accountRenameMessage = function(to, from) { return LOCALE.maketext("“[_1]” is set to be renamed “[_2]”.", to, from); }; MainController.prototype.usernameValidationTitle = function(count) { return LOCALE.maketext("You have entered [quant,_1,username that does,usernames that do] not meet this server’s username requirements:", count); }; MainController.prototype.usernameValidationMessage = function(count) { return LOCALE.maketext("Usernames must be no longer than [quant,_1,character,characters] and must contain only lowercase letters and numerals. They may not begin with a numeral. To resolve this, you can either fix the [numerate,_2,username,usernames] or deselect the [numerate,_1,account,accounts].", this.PAGE.MAX_USERNAME_LENGTH, count); }; MainController.prototype.usernameValidationAction = function(count) { return LOCALE.maketext("Deselect the [numerate,_1,account,accounts] with [numerate,_1,the invalid username,invalid usernames].", count); }; MainController.prototype.dedicatedIPDeselectAction = function(count) { return LOCALE.maketext("Deselect “Dedicated IP Address” for conflicted [numerate,_1,account,accounts]", count); }; MainController.prototype.dedicatedIPReselectAction = function(count) { return LOCALE.maketext("Reselect “[_1]” for [numerate,_2,account,accounts]", LOCALE.maketext("Dedicated IP Address"), count); }; MainController.prototype.domainsWithFrontpageMessage = function(count) { return LOCALE.maketext("The following domains use [asis,FrontPage] on the source server:"); }; MainController.prototype.resellerNoCopyTitle = function(count) { return LOCALE.maketext("You have selected [quant,_1,user,users] that will be transferred with no reseller privileges.", count); }; MainController.prototype.resellerNoCopyMessage = function(count) { if (this.PAGE.restricted_restore) { return LOCALE.maketext("[numerate,_1,This user is a reseller,These users are resellers] on the source server. Restricted Restore does not allow the transfer of reseller privileges. After the system restores the [numerate,_1,user,users], you can assign reseller privileges in WHM’s Reseller Center interface ([output,em,WHM » Home » Resellers » Reseller Center]).", count); } else { return LOCALE.maketext("[numerate,_1,This user is a reseller,These users are resellers] on the source server. To transfer an account’s reseller privileges from the source server, edit the [output,strong,Transfer Configuration] for the desired [numerate,_1,account,accounts] above. Be aware that reseller privileges can give users special permissions, including full root access, to your server.", count); } }; MainController.prototype.resellerNoCopyFixMessage = function(count) { return LOCALE.maketext("Transfer reseller privileges for the selected [numerate,_1,account,accounts].", count); }; MainController.prototype.canNotTransferTempDomainTitle = function(count) { return LOCALE.maketext("You have selected [numerate,_1,a temporary domain,temporary domains] for transfer. This server does not support temporary domains.", count); }; MainController.prototype.canNotTransferTempDomainMessage = function(count) { return LOCALE.maketext("The following [numerate,_1,domain is,domains are] temporary:", count); }; MainController.prototype.canSubmitForm = function(warningLists, dedicatedIPAccounts, newSelectedUserList, canNotTransferTempDomainList) { // Do warnings exists for any of these view lists for (var i = 0; i < warningLists.length; i++) { if (warningLists[i].length) { return false; } } // Block temp domain transfer if ( canNotTransferTempDomainList > 0 ) { return false; } // Check for selected items if (!this.selectedPackages.length && !this.selectedAccounts.length && !this.selectedConfigurations.length) { return false; } // Check for dedicated IP overages if (dedicatedIPAccounts.length > this.PAGE.local.available_ips.length) { return false; } // Check for Empty Slots if (this.SERVER_MAX_USERS && newSelectedUserList.length > this.REMAINING_ACCOUNT_SLOTS) { return false; } return true; }; MainController.prototype.getCopyButtonLabel = function getCopyButtonLabel() { return LOCALE.maketext("Copy"); }; MainController.prototype.submitSummaryMessage = function() { var summaryItems = []; if (this.selectedAccounts.length) { summaryItems.push(LOCALE.maketext("[quant,_1,Account,Accounts]", this.selectedAccounts.length)); } if (this.selectedPackages.length) { summaryItems.push(LOCALE.maketext("[quant,_1,Package,Packages]", this.selectedPackages.length)); } if (this.selectedConfigurations.length) { summaryItems.push(LOCALE.maketext("[quant,_1,Server Configuration,Server Configurations]", this.selectedConfigurations.length)); } return LOCALE.maketext("When you click [output,em,_1], you will start the transfer process for the following: [list_and,_2]", this.getCopyButtonLabel(), summaryItems); }; var app; try { app = angular.module("App"); // For runtime app.value("PAGE", PAGE); } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } /** * Returns true if the account does not exist locally on the server * @param {object} item * @return {Boolean} */ app.filter("existingUsers", function() { return function(items, exactMatchesOnly) { var matched = []; angular.forEach(items, function(item, index) { if (exactMatchesOnly && item.localuser !== item.similarLocalUser) { /* if exactMatchOnly is set, it will not return n character matches */ /* this is to allow filtering items to show only overwritable ones (exact matches) */ return false; } else if (!exactMatchesOnly && item.localuser === item.similarLocalUser) { return false; } /* will not return if user is also reserved because a reserved name overrides an existing name in transfers */ if (item.selected && item.invalidUser && item.userCheckStates.existing && !item.userCheckStates.reserved) { matched.push(item); } }); return matched; }; }); MainController.$inject = CONTROLLER_INJECTABLES; var controller = app.controller("MainController", MainController); return controller; } ); /* # templates/transfer_tool/filters/accountFilter.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( 'app/filters/accountFilter',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } /** * Filter that filters only on specific field based on $scope.acctsFilter. Will return true if the account passes the filter. Necessary for performance optimization. * @param {onject} item * @return {array} */ app.filter("accountFilter", function() { return function(accounts, filterText) { if (!filterText) { return accounts; } var filteredAccounts = []; angular.forEach(accounts, function(account) { /* isUser */ if (account.user.indexOf(filterText) !== -1) { filteredAccounts.push(account); } else if (account.domain.indexOf(filterText) !== -1) { /* isDomain */ filteredAccounts.push(account); } else if (account.owner.indexOf(filterText) !== -1) { /* isOwner */ filteredAccounts.push(account); } }); return filteredAccounts; }; }); } ); /* # templates/transfer_tool/filters/advanceAccountFilter.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( 'app/filters/advanceAccountFilter',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } /** * Filter that uses the options set in the advance filter form to further filter accounts. Will return true if the account passes the filter. * @param {object} item * @return {?array} */ app.filter("advanceAccountFilter", function() { return function(accounts, advanceFilter) { if (!advanceFilter) { return accounts; } var filteredAccounts = []; angular.forEach(accounts, function(account) { if (account.remote_user.indexOf(advanceFilter.user) === -1) { return; } if (account.domain.indexOf(advanceFilter.domain) === -1) { return; } if (advanceFilter.owner && advanceFilter.owner.length && advanceFilter.owner.indexOf(account.owner) === -1) { return; } if (advanceFilter.dedicated_ip >= 0 && account.dedicated_ip !== advanceFilter.dedicated_ip) { return; } filteredAccounts.push(account); }); return filteredAccounts; }; }); } ); // Copyright 2025 WebPros International, LLC // All rights reserved. // copyright@cpanel.net http://cpanel.net // This code is subject to the cPanel license. Unauthorized copying is prohibited. /* # templates/transfer_tool/controllers/AccountTableController.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, PAGE */ /* jshint -W003 */ /* jshint -W098*/ define( 'app/controllers/AccountTableController',[ "angular", "cjt/util/locale", "cjt/util/parse", "app/services/workerNodes", "app/filters/startFromFilter", "app/filters/cpLimitToFilter", "app/filters/accountFilter", "app/filters/advanceAccountFilter", "cjt/services/whm/nvDataService", ], function(angular, LOCALE, PARSE, WorkerNodesService) { "use strict"; var DEFAULT_CUSTOMIZED_LABEL = LOCALE.maketext("Default"); var CUSTOM_CUSTOMIZED_LABEL = LOCALE.maketext("Custom"); var SKIP_FLAG_DEFAULTS = { "copy_homedir": 1, "copy_databases": 1, "copy_bwdata": 1, "copy_reseller_privs": 0, "copy_integration_links": 0, }; var CONTROLLER_INJECTABLES = ["$scope", "$rootScope", WorkerNodesService.serviceName, "$filter", "$uibModal", "PAGE", "nvDataService", "OVERWRITE_OPTIONS", "OVERWRITE_STATES", "OVERWRITE_DESCRIPTION_TEMPLATE"]; /** * @class Controller class for the account table. Used in the angular app with 'controller as'. This contains most logic pertaining to accounts. * @param {object} $scope * @param {object} $filter */ var AccountTableController = function($scope, $rootScope, $workerNodesService, $filter, $uibModal, PAGE, nvDataService, OVERWRITE_OPTIONS, OVERWRITE_STATES, OVERWRITE_DESCRIPTION_TEMPLATE) { var _this = this; _this.PAGE = PAGE; _this.disableLiveTransfers = _this.PAGE.disable_live_transfers; _this.isRestrictedRestore = _this.PAGE.restricted_restore; _this.isRTL = PAGE.locale_is_rtl.toString() === "1"; _this.overwriteOptions = OVERWRITE_OPTIONS; _this.reservedUsernamePatterns = _this.PAGE.local.reserved_username_patterns; _this.localUserHash = Object.create(null); _this.reservedUsernames = {}; _this.localPartialUsernames = {}; _this.defaultWorkerOptions = $workerNodesService.getDefaultWorkerOptions(); _this.workerOptionTypes = $workerNodesService.getWorkerOptionTypes(); _this.control_overwrite = _this.overwriteOptions[0]; _this.overwriteStates = OVERWRITE_STATES; _this.accountFilterText = ""; _this.acctTable = { currentPage: 1, pageSize: 10, reverse: false, order: "remote_user", advSearchOptions: { domain: "", user: "", owner: [], dedicated_ip: -1, }, activeAdvFilter: null, }; _this.getDedicatedIPDomains = function() { return _this.PAGE.domainsWithDedicatedIp; }; // This will require more logic as the banner messages that can reset dedicated // IP addresses so for now we are returning the status // quo of always displaying the column. _this.showDedicatedIPColumn = true; var supportsExpressTransfers = PAGE.remote ? PARSE.parsePerlBoolean(PAGE.remote.supports_express_transfers) : false; var supportsLiveTransfers = PAGE.remote ? PARSE.parsePerlBoolean(PAGE.remote.supports_live_transfers) : false; $scope.supportsTempDomains = PAGE.local ? PARSE.parsePerlBoolean(PAGE.local.supports_temp_domains) : false; // If we support live transfers, it defaults to on // Unless it has been disabled var PROXY_FLAG_DEFAULT = supportsLiveTransfers && !_this.disableLiveTransfers; $scope.supportsLiveTransfers = supportsLiveTransfers; $scope.liveTransfersNoticeIsDismissed = PAGE.liveTransfersNoticeIsDismissed; $scope.liveTransfersPre90NoticeIsDismissed = PAGE.liveTransfersPre90NoticeIsDismissed; $scope.isAcctTabActive = true; // Overload the live transfer support. This gets set when the hostname is invalid. // We also need to overload and hide the notifications for live transfers if (_this.disableLiveTransfers) { $scope.liveTransfersNoticeIsDismissed = true; } $scope.dismissLiveTransfersNotice = function dismissLiveTransfersNotice() { $scope.liveTransfersNoticeIsDismissed = true; nvDataService.set("live_transfers_notice_is_dismissed", 1); }; $scope.dismissLiveTransfersPre90Notice = function dismissLiveTransfersPre90Notice() { $scope.liveTransfersPre90NoticeIsDismissed = true; $scope.liveTransfersNoticeIsDismissed = true; nvDataService.set("live_transfers_pre_90_notice_is_dismissed", 1); }; $rootScope.showTable = function showTable() { return !$scope.isAcctTabActive || (!$scope.supportsLiveTransfers || ($scope.supportsLiveTransfers && $scope.liveTransfersNoticeIsDismissed)); }; $rootScope.setAcctTabActive = function(isAcctTabActive) { $scope.isAcctTabActive = isAcctTabActive; }; _this.createUser = function(obj, index) { obj.initialindex = index; obj.copy_homedir = SKIP_FLAG_DEFAULTS["copy_homedir"]; obj.copy_databases = SKIP_FLAG_DEFAULTS["copy_databases"]; obj.copy_bwdata = SKIP_FLAG_DEFAULTS["copy_bwdata"]; obj.copy_reseller_privs = SKIP_FLAG_DEFAULTS["copy_reseller_privs"]; obj.copy_integration_links = SKIP_FLAG_DEFAULTS["copy_integration_links"]; obj.copy_proxy_option = PROXY_FLAG_DEFAULT; obj.proxyOption = { id: "proxy_option", modelKey: "copy_proxy_option", value: PROXY_FLAG_DEFAULT, default: PROXY_FLAG_DEFAULT, supports_live_transfers: PROXY_FLAG_DEFAULT, supports_express_transfers: supportsExpressTransfers, }; obj.selected = 0; obj.overwrite_type = _this.overwriteOptions[0]; obj.overwrite_account = 0; obj.overwrite_with_delete = 0; obj.updateDNSZone = true; obj.userCheckStates = { duplicate: false, reserved: false, existing: false, }; obj.dedicated_ip = (obj.dedicated_ip || _this.getDedicatedIPDomains()[obj.domain]) ? 1 : 0; obj.existing_dedicated_ip = obj.dedicated_ip; obj.oldlocaluser = obj.user; obj.localuser = obj.user; obj.invalidDomain = _this.PAGE.local.domains[obj.domain] && _this.PAGE.local.domains[obj.domain] !== obj.user ? 1 : 0; obj.is_reseller = _this.PAGE.remote.resellers && _this.PAGE.remote.resellers[obj.remote_user] ? 1 : 0; obj.invalidUser = _this.PAGE.local.users[obj.remote_user] ? 1 : 0; obj.isCustomized = false; obj.workerNodes = obj.worker_nodes || {}; obj.isTempDomain = obj.is_temp_domain || 0; obj.serverSupportsTempDomains = $scope.supportsTempDomains; // This is done in the service because it's done in multiple controllers $workerNodesService.resetAccountToDefaults(obj); }; _this.expandedAccount = false; _this.PAGE.items.accounts.forEach(_this.createUser); var accountFilter = $filter("accountFilter"), advanceAccountFilter = $filter("advanceAccountFilter"), startFrom = $filter("startFrom"), orderBy = $filter("orderBy"), limitTo = $filter("cpLimitTo"); // To better understand what these assignments are look at updateFilteredAccounts and updateViewableAccounts _this.filteredAccounts = accountFilter(advanceAccountFilter(this.PAGE.items.accounts, _this.acctTable.activeAdvFilter), _this.accountFilterText); _this.viewableAccounts = limitTo(startFrom(orderBy(_this.filteredAccounts, _this.acctTable.order, _this.acctTable.reverse), (_this.acctTable.currentPage - 1) * _this.acctTable.pageSize), _this.acctTable.pageSize); /** * Reapplies filters for the filteredAccounts array * Array -> Filtered by advanced -> filtered by basic * accounts | advanceAccountFilter:activeAdvFilter | accountFilter:accountFilterText */ _this.updateFilteredAccounts = function() { _this.filteredAccounts = accountFilter( advanceAccountFilter(this.PAGE.items.accounts, _this.acctTable.activeAdvFilter), _this.accountFilterText); }; /** * Reapplies filteres for the viewableAccounts array. * FilteredArray -> Ordered by(reverse?) -> start based on page # -> limit to page size * filteredAccounts | orderBy: acctTable.order:acctTable.reverse | startFrom:(acctTable.currentPage - 1 ) * acctTable.pageSize | limitTo: acctTable.pageSize */ _this.updateViewableAccounts = function() { var pageSize = _this.acctTable.pageSize; var accounts = orderBy(_this.filteredAccounts, _this.acctTable.order, _this.acctTable.reverse); accounts = limitTo(startFrom(accounts, (_this.acctTable.currentPage - 1) * pageSize), pageSize); _this.viewableAccounts = accounts; }; _this.getUsernamePattern = function(key) { if (key === "TRIM_PATTERN") { return new RegExp(_this.PAGE.UN_TRIM_REG_EXP); } else if (key === "TRANSFER_USER_RESTRICT") { return new RegExp(_this.PAGE.USERNAME_TRANSFER_REGEXP); } else if (key === "NONTRANSFER_USER_RESTRICT") { return new RegExp(_this.PAGE.USERNAME_REGEXP); } else { return null; } }; $scope.$on("recheckUsersCalled", function(eo, args) { angular.forEach(args.dataset, function(acct) { // Always skip forcing selection, since "Select None" will cause this to just get re-selected _this.updateOverwriteFlags(acct, false, true); _this.updateUserCheckStates(acct); _this.checkAccountForDuplicateLocals(acct); _this.updateAccountsControlRow(); }); }); $scope.$on("selectedAccountsEmptied", function() { _this.acct_checkbox_control = false; _this.updateAccountsControlRow(); }); $scope.$watch(function() { return _this.acctTable; }, function() { _this.updateViewableAccounts(); }, true); $scope.$watch(function() { return _this.viewableAccounts; }, function() { _this.updateAccountsControlRow(); }, true); for (var rUi = 0; rUi < _this.PAGE.local.reserved_usernames.length; rUi++) { var reservedUsername = _this.PAGE.local.reserved_usernames[rUi].toLowerCase(); _this.reservedUsernames[reservedUsername] = 1; } /* used to check the eight v 16 restrictions of (no same first USERNAME_UNIQUE_LENGTH characters) */ /* pre processed for big lists */ angular.forEach(_this.PAGE.local.users, function(value, lUsername) { var plUsername = _this.makeUsernamePartial(lUsername, true); this[plUsername] = lUsername; }, _this.localPartialUsernames); angular.forEach(_this.PAGE.items.accounts, function(acct, key) { /* store local user hash */ _this.storeLocalUserHash(acct.initialindex, acct.oldlocaluser, acct.localuser); }); // Set the columnWidth _this.numberOfColumns = 9; ["bytesused", "owner", "dedicated_ip"].forEach(function(key) { if (!_this.showColumn(key)) { _this.numberOfColumns--; } }); _this.skipOptions = [ { id: "copy_homedir_for", label: LOCALE.maketext("Home Directory"), modelKey: "copy_homedir", default: SKIP_FLAG_DEFAULTS["copy_homedir"] }, // Disable reseller privileges skipOption for restricted restores { id: "reseller_privs_for", label: LOCALE.maketext("Reseller Privileges"), modelKey: "copy_reseller_privs", default: SKIP_FLAG_DEFAULTS["copy_reseller_privs"], disabled: _this.isRestrictedRestore }, { id: "copy_acctdb_for", label: LOCALE.maketext("Databases"), modelKey: "copy_databases", default: SKIP_FLAG_DEFAULTS["copy_databases"] }, { id: "copy_bwdata_for", label: LOCALE.maketext("Bandwidth Data"), modelKey: "copy_bwdata", default: SKIP_FLAG_DEFAULTS["copy_bwdata"] }, { id: "integration_links_for", label: LOCALE.maketext("Integration Links"), modelKey: "copy_integration_links", default: SKIP_FLAG_DEFAULTS["copy_integration_links"] }, ]; _this.openModal = $uibModal.open.bind($uibModal); _this.overwriteDescriptionTemplate = OVERWRITE_DESCRIPTION_TEMPLATE; this._workerOptionAltered = $workerNodesService.checkWorkerOptionsAltered.bind($workerNodesService); return _this; }; angular.extend(AccountTableController.prototype, { /** * Stores hashed usernames for duplication checks on large amounts of usernames */ storeLocalUserHash: function storeLocalUserHash(index, oldValue, newValue) { var _this = this; var newValuePartial = this.makeUsernamePartial(newValue, true); var oldValuePartial = this.makeUsernamePartial(oldValue, true); _this.localUserHash[oldValuePartial] = _this.localUserHash[oldValuePartial] || []; angular.forEach(_this.localUserHash[oldValuePartial], function(value, key) { if (value === index) { _this.localUserHash[oldValuePartial].splice(key, 1); } }); _this.localUserHash[newValuePartial] = _this.localUserHash[newValuePartial] || []; _this.localUserHash[newValuePartial].push(index); }, /** * Calls functions that update filtered and viewable accounts */ updateAccounts: function updateAccounts() { this.updateFilteredAccounts(); this.updateViewableAccounts(); }, /** * Returns class corresponding to glyph for account. Account must be selected and not have a domain conflict. * @param {object} acct * @return {?string} */ getGlyphClass: function getGlyphClass(acct) { if (!acct.selected || acct.domainConflict) { return; } if (acct.invalidUser) { return "glyphicon-exclamation-sign"; } else { return "glyphicon-ok"; } }, /** * Returns class for button that corresponds to what choice for dedicated ip was selected. Used in advance search form to indicate selection similar to radio button. * @param {int} thisVal * @return {string|Boolean} */ dedicatedIpClass: function dedicatedIpClass(thisVal) { return thisVal === this.acctTable.advSearchOptions.dedicated_ip ? "btn-primary" : "btn-default"; }, /** * Check the state of the various control columns * * @param {object[]} accounts list of accounts to build the value based on * @param {string} param parameter on account to check * @returns {*} current value of control column. Various values possible. */ _getColumnControlState: function _getColumnControlState(accounts, param) { // If there are no accounts, return false if (!accounts.length) { return false; } // If any are not checked, return false for (var i = 0; i < accounts.length; i++) { var account = accounts[i]; if (!account[param]) { return false; } } // If all are checked, return true return true; }, /** * Check the state of the overwrite control column * * @param {object[]} accounts list of accounts to build the value based on * @param {string} param parameter on account to check * @returns {object|null} value of the parameter for accounts if the same. Undefined otherwise. */ _getOverwriteColumnControlState: function _getOverwriteColumnControlState(accounts, param) { // Update only based on selected accounts in list // If there are no accounts, return false if (!accounts.length) { return this.overwriteOptions[0]; } var currentValue; for (var i = 0; i < accounts.length; i++) { var account = accounts[i]; if (!this.canNeedOverwrite(account)) { // Only ones that might need overwrite should be considered continue; } // Store the first value as a baseline if (!currentValue) { currentValue = account[param]; } // If any are different from one another, default to undef (to allow setting it) if (account[param].value !== currentValue.value) { return; } } // If all are one of the two overwrite values [1,2], use that value // If no value was determined, then no overwrite-capable items were found, use the zero option return currentValue ? currentValue : this.overwriteOptions[0]; }, /** * Called to check and adjust control row check boxes based on viewable account params */ updateAccountsControlRow: function updateAccountsControlRow() { var checks = [{ param: "selected", controlModel: "acct_checkbox_control", checkFunction: this._getColumnControlState.bind(this), }, { param: "dedicated_ip", controlModel: "control_dedicated_ip", onlySelected: true, checkFunction: this._getColumnControlState.bind(this), }, { param: "overwrite_type", controlModel: "control_overwrite", onlySelected: true, checkFunction: this._getOverwriteColumnControlState.bind(this), }]; var selectedAccounts = this.viewableAccounts.filter(function(account) { return !!account.selected; }); angular.forEach(checks, function(check) { var accounts = check.onlySelected ? selectedAccounts : this.viewableAccounts; this[check.controlModel] = check.checkFunction(accounts, check.param); }, this); }, /** * Sets the advance search($scope.acctTable.advSearchOptions) to either be a copy of the object passed in or if no object, to the default value. We set it this way * because otherwise Angular will bind the object directily causing any updates to be instantaneous, breaking the experience. * @param {object} obj */ setAdvanceSearch: function setAdvanceSearch(obj) { this.acctTable.activeAdvFilter = angular.copy(obj); this.updateAccounts(); if (!obj) { this.acctTable.advSearchOptions = { domain: "", user: "", owner: [], dedicated_ip: -1, }; } }, /** * Goes over array of accounts and sets the dedicated_ip flag if the destination domain already has a dedicated ip. * @param {array} dataset */ handleDedicatedIpForArray: function handleDedicatedIpForArray(dataset) { var _self = this; angular.forEach(dataset, function(acct) { if (_self.getDedicatedIPDomains()[acct.domain]) { acct.dedicated_ip = 1; } }); }, /** * Returns true if the account has a destination domain with a dedicated ip already or if there are no available IP addresses. * @param {object} acct * @return {Boolean} */ isDedicatedIpDisabled: function isDedicatedIpDisabled(acct) { return this.getDedicatedIPDomains()[acct.domain] ? true : !this.PAGE.local.available_ips.length; }, /** * Returns true for account that can be overwritten * @param {object} item * @return {Boolean} */ overwriteFilter: function overwriteFilter(item) { return this.PAGE.local.users[item.user] || this.PAGE.local.users[item.localuser] || (this.PAGE.local.domains[item.domain] === item.localuser); }, /** * Updates account username checks and stores then on acct.userCheckStates * then updates calls updateLocalUserStatus() to reset acct.invalidUser * * @method validateAccount * @param acct {Object} angular user account object */ validateAccount: function validateAccount(acct) { // update account localuser hash for duplicate validation /* which large accounts this was the only feasible option. */ /* deep watch expressions were far too cumbersome. */ this.storeLocalUserHash(acct.initialindex, acct.oldlocaluser, acct.localuser); /* must be called before oldusername is reset to reset duplication on old set */ this.checkAccountForDuplicateLocals(acct); acct.oldlocaluser = acct.localuser; this.updateUserCheckStates(acct); }, /** * Seperate function allows independent updates to userCheckStates * used in ToggleCheckAll * * @method updateuserCheckStatus * @param acct {Object} angular user account object */ updateUserCheckStates: function updateUserCheckStates(acct) { /* response is now in the form of false, or failure object */ acct.userCheckStates.reserved = this.isReservedUsername(acct); acct.userCheckStates.existing = this.isExistingLocalUser(acct); /* refers to the specific makeup of the new username (does it match the regexp) */ acct.userCheckStates.invalid = !this.isLocalUsernameValid(acct); acct.overwrite_type = acct.selected ? acct.overwrite_type : this.overwriteOptions[0]; this.updateLocalUserStatus(acct); }, /** * updates 'invalidUser' based on state check flags * * @method updateLocalUserStatus * @param acct {Object} angular user account object */ updateLocalUserStatus: function updateLocalUserStatus(acct) { if ((acct.userCheckStates.existing !== false && acct.overwrite_type.value === this.overwriteStates.NO_OVERWRITE ) || acct.userCheckStates.duplicate !== false || acct.userCheckStates.invalid !== false || acct.userCheckStates.reserved !== false) { acct.invalidUser = true; } else { acct.invalidUser = false; } }, /** * Returns the class to be used for input field highlighting. * @param {object} acct * @return {?string} */ getInputClass: function getInputClass(acct) { if (!acct.selected || acct.domainConflict) { return; } if (acct.invalidUser) { return "has-error"; } else { return "has-success"; } }, /** * Returns username converted from account as as string * * @method getUserNameFromAcct * @param acct {Object} angular user account object * @return {String} value of username */ getUserNameFromAcct: function getUserNameFromAcct(acct) { var username = acct.localuser || ""; if (!username.length) { username = acct.remote_user; } return username; }, /** * Returns Array of accounts that the username matches (can be partial match). * * @method findAccountsByUsername * @param username {String} angular user account object * @param matchFirstNChars {int} number of matching characters defaults to all * passing -1 will be treated as a 'match all characters' * @param startingIndex {int} which account to begin the interation from (faster) * @return {Array} of acct indexes that match */ findAccountsByUsername: function findAccountsByUsername(username, matchFirstNChars, startingIndex) { /* if matchFirstNChars > 0 use matchFirstNChars | else use -1 (interpretted as all) */ matchFirstNChars = Number(matchFirstNChars) || -1; startingIndex = Number(startingIndex) || 0; if (matchFirstNChars !== -1) { username = username.substr(0, matchFirstNChars); } var matchedAccounts = []; var otherAccount; for (var i = startingIndex; i < this.PAGE.items.accounts.length; i++) { otherAccount = this.PAGE.items.accounts[i]; if (otherAccount.localuser.toLowerCase().indexOf(username) === 0) { if (username.length < matchFirstNChars && otherAccount.localuser.length > username.length) { /* this means that the otherAccount has additional characters in the NChars range so it is no longer enough matching characters */ continue; } /* username was found in it */ if (matchFirstNChars === -1 && username.length !== otherAccount.localuser.length) { /* matchFirstNChars is set to default (match all), but lengths of the usernames */ continue; } /* good length, good first n chars */ matchedAccounts.push(i); } } return matchedAccounts; }, /** * finds accounts by username, then returns selected accounts * * @method findSelectedAccountsByUsername * see: findAccountsByUsername for @params */ findSelectedAccountsByUsername: function findSelectedAccountsByUsername( /* inherit from findAccountsByUsername */ ) { var usernames = this.findAccountsByUsername.apply(this, arguments); var selected = []; if (usernames === false) { return selected; } var uIndex; for (var i = 0; i < usernames.length; i++) { uIndex = usernames[i]; if (this.PAGE.items.accounts[uIndex].selected) { selected.push(uIndex); } } return selected; }, /** * Checks one local account for duplicates and marks userCheckStates.duplicate accordingly * * @method checkAccountForDuplicateLocals */ checkAccountForDuplicateLocals: function checkAccountForDuplicateLocals(acct) { /* clear status flag */ acct.userCheckStates.duplicate = false; /* get oldlocaluser and reset old duplicates */ var oldUsernamePartial = this.makeUsernamePartial(acct.oldlocaluser, true); /* recheck old username set to update their duplicate flag */ if (this.localUserHash[oldUsernamePartial] && this.localUserHash[oldUsernamePartial].length === 1) { var previousDuplicateUser = this.localUserHash[oldUsernamePartial][0]; this.PAGE.items.accounts[previousDuplicateUser].userCheckStates.duplicate = false; this.updateLocalUserStatus(this.PAGE.items.accounts[previousDuplicateUser]); } /* no local username entered? Ignore it! */ if (!acct.localuser) { return; } var username = acct.localuser; var trimmedUsername = this.makeUsernamePartial(username, true); var accountIndexOrObject; var accountIndex; var selectedOthers = []; /* reset all, store still selected items for next loop */ for (var i = 0; i < this.localUserHash[trimmedUsername].length; i++) { accountIndex = this.localUserHash[trimmedUsername][i]; accountIndexOrObject = this.PAGE.items.accounts[accountIndex]; accountIndexOrObject.userCheckStates.duplicate = false; this.updateLocalUserStatus(accountIndexOrObject); /* items that aren't selected are ignored */ if (!accountIndexOrObject.selected) { continue; } selectedOthers.push(accountIndexOrObject); } /* if multiple items remain selected in this hash, set them as duplicates */ if (selectedOthers.length > 1) { for (i = 0; i < selectedOthers.length; i++) { accountIndexOrObject = selectedOthers[i]; accountIndexOrObject.userCheckStates.duplicate = true; this.updateLocalUserStatus(accountIndexOrObject); } } }, /** * Checks all local accounts for duplicates and marks userCheckStates.duplicate accordingly * * @method checkForDuplicateLocals */ checkForDuplicateLocals: function checkForDuplicateLocals() { /* check this username against other usernames that have been checked for transfer */ var i, otherAccount; /* reset all initially to allow faster parsing later in function*/ for (i = 0; i < this.PAGE.items.accounts.length; i++) { otherAccount = this.PAGE.items.accounts[i]; otherAccount.userCheckStates.duplicate = false; this.updateLocalUserStatus(otherAccount); } /* iterate through all, skip already set duplicates, */ for (i = 0; i < this.PAGE.items.accounts.length; i++) { otherAccount = this.PAGE.items.accounts[i]; if (otherAccount.userCheckStates.duplicate) { /* because of forward iteration nature of this, this has been cleared and marked as a set for another item */ continue; } this.checkAccountForDuplicateLocals(otherAccount); } }, /** * Returns Boolean defining whether account username is considered reserved. * * @method isReservedUsername * @param acct {Object} angular user account object * @return {Boolean} true if username is reserved */ isReservedUsername: function isReservedUsername(acct) { var username = this.getUserNameFromAcct(acct); /* trim spaces from ends of username */ var trimmedUsername = username.replace(/^\s*(.+)\s*$/i, "$1"); /* check against reserved system names to see if this on exists */ if (trimmedUsername in this.reservedUsernames) { return true; } /* interim list of restricted partial names (reg ex patterns) */ /* list cannot contain these specific parts */ /* matches names, or parts of names dependent on need <[name]>$ matches a <[name]> at the end of a username ^<[name]> matches a <[name]> at the beginning of the username ^<[name]>$ matches exactly that <[name]> with no trailing or begining characters */ var currentRegExp, reservedNamePattern; for (var i = 0; i < this.reservedUsernamePatterns.length; i++) { reservedNamePattern = this.reservedUsernamePatterns[i]; /* build dynamic regular expression */ currentRegExp = new RegExp(reservedNamePattern, "gi"); if (trimmedUsername.match(currentRegExp) !== null) { return true; } } return false; }, /** * Returns Boolean representing whether acct.username exists on local machine * in part or fully (only first USERNAME_UNIQUE_LENGTH characters need to match) * * @method isExistingLocalUser * @param acct {Object} angular user account object * @return {Boolean} dependent on user existing on local server */ isExistingLocalUser: function isExistingLocalUser(acct) { var username = this.getUserNameFromAcct(acct); var trimmedUsername = this.makeUsernamePartial(username, true); if (trimmedUsername in this.localPartialUsernames) { acct.similarLocalUser = this.localPartialUsernames[trimmedUsername]; return true; } return false; }, /** * Tests username against globally established regexp * uses the transfer specific regexp if remote_user === localuser * uses the non-transfer regexp otherwise * * @method isLocalUsernameValid * @param acct {Object} angular user account object * @return {Boolean} true or false based on regexp.test */ isLocalUsernameValid: function isLocalUsernameValid(acct) { var re = this.getUsernamePattern("TRANSFER_USER_RESTRICT"); var partial = this.makeUsernamePartial(acct.localuser, true); if (!partial.replace(/\-/gi, "").length) { return false; } return re.test(acct.localuser); }, makeUsernamePartial: function makeUsernamePartial(username, removeSpecialCharacters) { if (removeSpecialCharacters) { username = username.replace(/[\_\.]/gi, ""); } return username.replace(this.getUsernamePattern("TRIM_PATTERN"), "$1").toLowerCase(); }, /** * Get the classes for each account row * * @param {object} account user account to check against * @returns {string} if the item is selected, and either the domain or user is invalid, else nothing */ getAccountRowClasses: function getAccountRowClasses(account) { if (!account.selected) { return ""; } if (!account.invalidUser && !account.invalidDomain) { return "success"; } return "danger"; }, /** * Determine whether a column should show based on the key * * @param {string} columnName account key to check * @returns {boolean} qwhether to show the column * */ showColumn: function showColumn(columnName) { switch (columnName) { case "bytesused": return !!this.PAGE.remote.has_disk_used; case "owner": return !!this.PAGE.remote.has_owners; case "dedicated_ip": return !!this.showDedicatedIPColumn; default: return true; } }, /** * For Each account, determine the current chevron icon state * * @param {*} account account to check * @returns {string} if the account is expanded, 'fa-chevron-down', else a left or right based on the RTL settings of LOCALE */ getChevronClasses: function getChevronClasses(account) { var collapsedClass = this.isRTL ? "fa-chevron-left" : "fa-chevron-right"; return this.isAccountExpanded(account) ? "fa-chevron-down" : collapsedClass; }, /** * Update the isCustomized value for an account based on skipOptions states * * @param {object} account account to check */ updateCustomizedFlag: function updateCustomizedFlag(account) { account.isCustomized = this._skipOptionsAltered(account) || this._workerOptionAltered(account) || this._proxyOptionAltered(account) || this._updateDNSZoneAltered(account); }, _skipOptionsAltered: function _skipOptionsAltered(account) { var skipKeys = Object.keys(SKIP_FLAG_DEFAULTS); for (var i = 0; i < skipKeys.length; i++) { var skipKey = skipKeys[i]; if (account[skipKey] !== SKIP_FLAG_DEFAULTS[skipKey]) { return true; } } return false; }, /** * Check if Live Transfer option has be altered * * @param {object} account account to check */ _proxyOptionAltered: function _proxyOptionAltered(account) { if (account.proxyOption.value !== account.proxyOption.default) { return true; } return false; }, /** * Check if updateDNSZone option has been altered from default * * @param {object} account account to check * @returns {boolean} true if altered, false if default */ _updateDNSZoneAltered: function _updateDNSZoneAltered(account) { return account.updateDNSZone !== true; }, /** * Check if the account is expanded * * @param {object} account account to check * @returns {boolean} true|false state of account expansion */ isAccountExpanded: function isAccountExpanded(account) { return this.expandedAccount === account; }, /** * Expand the account * * @param {object} account account to expand */ expandAccount: function expandAccount(account) { if (this.expandedAccount) { this.collapseAccount(this.expandedAccount); } this.expandedAccount = account; this.accountSettingUpdated(account, true); }, /** * Collapse the account * * @param {object} account account to collapse */ collapseAccount: function collapseAccount(account) { this.expandedAccount = false; }, /** * Toggle the expanded state of an account * * @param {object} account account to toggle */ toggleAccountExpansion: function toggleAccountExpansion(account) { if ( this.isAccountExpanded(account) ) { this.collapseAccount(account); } else { this.expandAccount(account); } }, /** * Get the label based on the isCustomized value of the account * * @param {object} account account to check */ getCustomizeLabel: function getCustomizeLabel(account) { return account.isCustomized ? CUSTOM_CUSTOMIZED_LABEL : DEFAULT_CUSTOMIZED_LABEL; }, /** * Called from the view when the expanded panel of an account change * * @param {object} account that changed * @param {string} key what option changed * @param {*} value what is the new value of that option */ onExpandPanelOptionChanged: function onExpandPanelOptionChanged(account, key, value) { this.updateAccountSetting(account, key, value); }, /** * Called from the view when "apply to all" is emmitted * * @param {object} fromAccount source account to copy from * @param {object[]} toAccounts destination accounts to copy to * @param {object[]} skipOptions which skip options to update * @param {object} workerOptions which worker options to update * @param {object} proxyOption proxy option to update * @param {boolean} updateDNSZone update DNS zone setting to copy */ onExpandPanelApplyToAll: function onExpandPanelApplyToAll(fromAccount, toAccounts, skipOptions, workerOptions, proxyOption, updateDNSZone) { // Get Skip Model Keys Once var skipModelKeys = skipOptions.map(function(skipOption) { return skipOption.modelKey; }, this); // Get Worker Model Keys Once var workerModelKeys = workerOptions && Object.keys(workerOptions).map(function(workerOptionType) { return workerOptions[workerOptionType].modelKey; }, this) || []; // Include other options var modelKeys = ["dedicated_ip", "copy_proxy_option", "updateDNSZone"].concat(skipModelKeys, workerModelKeys); var copyOverwrite = this.canNeedOverwrite(fromAccount); // Update extra items and validate toAccounts.filter(function(toAccount) { if (toAccount === fromAccount) { return false; } return true; }).forEach(function(toAccount) { var myCopyOverwrite = copyOverwrite && this.canNeedOverwrite(toAccount); var myModelKeys = modelKeys.slice(); if (myCopyOverwrite) { myModelKeys.push("overwrite_type"); } myModelKeys.forEach(function(modelKey) { this.updateAccountSetting(toAccount, modelKey, fromAccount[modelKey], false); }, this); // If, but only if, both accounts are need-overwrite // we should copy the overwrite setting. if (myCopyOverwrite) { this.updateOverwriteFlags(toAccount, false); } this.validateAccount(toAccount); }, this); }, /** * Update an account setting and update settings based on it. * * @param {object} account account on which to update the setting * @param {string} key setting to update * @param {*} value new value * @param {boolean} validate validate after update */ updateAccountSetting: function updateAccountSetting(account, key, value, validate) { if (!validate && key === "copy_proxy_option") { account.proxyOption.value = value; } account[key] = value; this.accountSettingUpdated(account, validate); }, /** * Called when any account setting is updated. Optionally validates the account based on state. * * @param {object} account account that had the update occur * @param {boolean} validate when true, validateAccount() will be called */ accountSettingUpdated: function accountSettingUpdated(account, validate, skipForceSelect) { var callUpdate; if (!skipForceSelect && !account.selected) { account.selected = 1; callUpdate = true; } this.updateCustomizedFlag(account); if (validate) { this.validateAccount(account); } if (callUpdate) { this.updateSelectedAccounts(); } }, /** * Set a function to call when the selected accounts change * * @param {function} func function to call when the selected accounts change */ setUpdateSelectedAccountsFunction: function setUpdateSelectedAccountsFunction(func) { this._updateSelectedAccounts = func; }, /** * Called when selected accounts change, if set by setUpdateSelectedAccountsFunction() a callback function will be called too * */ updateSelectedAccounts: function updateSelectedAccounts() { if (this._updateSelectedAccounts) { this._updateSelectedAccounts(); } }, /** * Called by the view when an accounts selection changes * * @param {object} account the account that changed. Unused by the function. */ accountSelectionUpdated: function accountSelectionUpdated(account) { this.updateSelectedAccounts(); }, /** * Check if an account is eligible for the overwrite dropdown * * @param {object} account account to be checked * @returns {boolean} whether or not the account could ever need overwriting */ canNeedOverwrite: function canNeedOverwrite(account) { var localUsers = this.PAGE.local.users; var localDomains = this.PAGE.local.domains; return localUsers[account.user] || localUsers[account.localuser] || (localDomains[account.domain] === account.localuser); }, /** * Update the specific overwrite flags based on the overwrite_type of the account * accountSettingUpdate is then called, passing along the validate value * * @param {object} account account to be updated * @param {boolean} validate whether to validate during the accountSettingUpdated phase */ updateOverwriteFlags: function updateOverwriteFlags(account, validate, skipForceSelect) { account.overwrite_account = 0; account.overwrite_with_delete = 0; switch (account.overwrite_type.value) { case this.overwriteStates.OVERWRITE_WITH_DELETE: account.overwrite_with_delete = 1; // fall through here is intentional as we want it to set overwrite_account as well when we set overwrite_with_delete case this.overwriteStates.OVERWRITE: account.overwrite_account = 1; break; } this.accountSettingUpdated(account, validate, skipForceSelect); }, openOverwriteDescriptionModal: function openOverwriteDescriptionModal() { var self = this; self.overwriteModal = this.openModal({ templateUrl: this.overwriteDescriptionTemplate, controller: ["$scope", function($scope) { $scope.close = function() { self.closeOverwriteDescriptionModal(); }; }], }); }, closeOverwriteDescriptionModal: function closeOverwriteDescriptionModal() { if (this.overwriteModal) { this.overwriteModal.close(); this.overwriteModal = null; } }, }); // Retrieve the current application var app; try { app = angular.module("App"); // For runtime app.value("PAGE", PAGE); } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } AccountTableController.$inject = CONTROLLER_INJECTABLES; var controller = app.controller("AccountTableController", AccountTableController); return controller; } ); /* # templates/transfer_tool/directives/boolToIntDirective.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( 'app/directives/boolToIntDirective',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } // Main - reusable /** * Angular directive that when attached to an element with an ng-model will render that model as true or false * but ensure that any changing will result in 1 or 0 values. Necessary because Perl cannot evaluate JavaScript * true/false when submitted in JSON. */ app.directive("boolToInt", [ function() { return { restrict: "A", require: "ngModel", priority: 99, link: function(scope, elem, attrs, controller) { controller.$formatters.push(function(modelValue) { return !!modelValue; }); controller.$parsers.push(function(viewValue) { return viewValue ? 1 : 0; }); } }; } ]); } ); /* # templates/transfer_tool/directives/preventBubblingDirective.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( 'app/directives/ngDebounceDirective',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } // Main - reusable // https://gist.github.com/tommaitland/7579618 /** * Angular directive that prevents input from being processed. Useful when paired with an input filter or ajax request * to prevent rapid calling of underlining functionality. */ app.directive("ngDebounce", ["$timeout", function($timeout) { return { restrict: "A", require: "ngModel", priority: 99, link: function(scope, elm, attr, ngModelCtrl) { if (attr.type === "radio" || attr.type === "checkbox") { return; } elm.unbind("input"); var debounce; elm.bind("input", function() { $timeout.cancel(debounce); debounce = $timeout(function() { scope.$apply(function() { ngModelCtrl.$setViewValue(elm.val()); }); }, 250); }); elm.bind("blur", function() { // http://stackoverflow.com/questions/12729122/prevent-error-digest-already-in-progress-when-calling-scope-apply $timeout(function() { scope.$apply(function() { ngModelCtrl.$setViewValue(elm.val()); }); }); }); } }; } ]); } ); /* # templates/transfer_tool/directives/preventBubblingDirective.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( 'app/directives/preventBubblingDirective',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } // Main - reusable /** * Angular directive which prevents event propogation. Used in a Bootstrap dropdown menu with a form to prevent * accidental closure when interacting with the fields. */ app.directive("preventBubbling", [ function() { return { restrict: "A", link: function(scope, element) { element.bind("click", function(event) { event.preventDefault(); event.stopPropagation(); }); } }; } ]); } ); /* # templates/transfer_tool/directives/clickOnceDirective.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( 'app/directives/clickOnceDirective',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } // Main - reusable /** * Angular directive which disables a button on form submit. * Original work found here: http://stackoverflow.com/a/19825570 */ app.directive("clickOnce", ["$timeout", function($timeout) { return { restrict: "A", link: function(scope, element, attrs) { var replacementText = attrs.clickOnce; element.bind("click", function() { $timeout(function() { if (replacementText) { element.html(replacementText); } element.attr("disabled", true); }, 0); }); } }; } ]); } ); /* # templates/transfer_tool/filters/overwriteFilter.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, PAGE */ define( 'app/filters/overwriteFilter',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } /** * Returns true for account that can be overwritten * @param {object} item * @return {array} */ app.filter("overwriteFilter", function() { var localUsers = PAGE.local.users; var localDomains = PAGE.local.domains; return function(accounts) { var filteredAccounts = []; angular.forEach(accounts, function(account) { if (localUsers[account.user] || localUsers[account.localuser] || localDomains[account.domain] === account.localuser) { filteredAccounts.push(account); } }); return filteredAccounts; }; }); } ); /* # templates/transfer_tool/filters/bytesFilter.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( 'app/filters/bytesFilter',[ "angular" ], function(angular) { "use strict"; // Retrieve the current application var app; try { app = angular.module("App"); // For runtime } catch (e) { app = angular.module("App", []); // Fall-back for unit testing } // Main - reusable /** * Angular filter which returns a string localized with LOCALE.format_bytes * @return {string} */ app.filter("bytes", function() { return function(bytes) { return LOCALE.format_bytes(bytes); }; }); } ); /* # cpanel - templates/transfer_tool/getacctlist.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 require:false, define:false, confirm:false, alert:false, PAGE, EVENT:true */ (function(window) { "use strict"; var enterSessionIfNotPending = function() { CPANEL.api({ "func": "get_transfer_session_state", "data": { "transfer_session_id": PAGE.transfer_session_id }, "callback": { success: function(o) { var response = o.cpanel_data; var statename = response.state_name; if (o.cpanel_error) { alert(LOCALE.maketext("Failed to retrieve the session state: [_1]", o.cpanel_error)); } else if (statename) { if (statename !== "PENDING") { if (confirm(LOCALE.maketext("The session has already started and cannot accept additional inputs. Would you like to view the transfer session?"))) { window.location.href = "transfer_session?transfer_session_id=" + encodeURIComponent(PAGE.transfer_session_id); } else { window.history.go(-1); /* Don't let them enter data on the screen as it will screen as it will just fail on the next screen since it the transfer sessions is already in progress */ } } } }, failure: function() { alert(LOCALE.maketext("Failed to retrieve the session state.")); } } }); }; var reAnalyzeRemote = function() { var reAnalyzeRemoteButton = CPANEL.Y.one("#reAnalyzeRemoteButton"), preChangeText = reAnalyzeRemoteButton.innerHTML; reAnalyzeRemoteButton.disabled = true; reAnalyzeRemoteButton.innerHTML = "<i class='glyphicon glyphicon-refresh animate-spin'></i> " + LOCALE.maketext("Performing Analysis …"); CPANEL.api({ func: "analyze_transfer_session_remote", data: { "transfer_session_id": PAGE.transfer_session_id }, callback: CPANEL.ajax.build_page_callback(function() { window.location.href = "transfer_selection?transfer_session_id=" + encodeURIComponent(PAGE.transfer_session_id); }, { pagenotice_container: "callback_block", on_error: function() { reAnalyzeRemoteButton.disabled = false; reAnalyzeRemoteButton.innerHTML = preChangeText; } }) }); }; var init = function() { EVENT.on(CPANEL.Y.one("#reAnalyzeRemoteButton"), "click", reAnalyzeRemote); enterSessionIfNotPending(); // Parse Blocker Data for Easy Apache if (PAGE.configuration_modules.Apache && PAGE.configuration_modules.Apache.analysis) { PAGE.EABlockers = PAGE.configuration_modules.Apache.analysis["Blocker Data"] || []; // Loop through each item, look for Blocker level item for (var i = PAGE.EABlockers.length - 1; i >= 0; i--) { if (PAGE.EABlockers[i].vendor_id === "Cpanel" && PAGE.EABlockers[i].items) { for (var j = PAGE.EABlockers[i].items.length - 1; j >= 0; j--) { if (PAGE.EABlockers[i].items[j].status === 2) { PAGE.blockerExists = true; } } } } } }; EVENT.onDOMReady(init); })(window); /* angular portion */ define( 'app/getacctlist',[ "angular", "app/directives/accountExpandPanel", "cjt/util/locale", "app/overwriteStates", "app/overwriteOptions", "jquery", "ngRoute", "uiBootstrap", "angular-chosen", "ngSanitize", "cjt/modules", "cjt/directives/toggleLabelInfoDirective", ], function(angular, AccountExpandPanel, LOCALE, OVERWRITE_STATES, OVERWRITE_OPTIONS) { "use strict"; return function() { var app = angular.module("App", [ "cjt2.config.whm.configProvider", // This needs to load first "cjt2.whm", "ngSanitize", "ui.bootstrap", AccountExpandPanel.namespace ]); app.value("OVERWRITE_DESCRIPTION_TEMPLATE", "overwriteWithDeleteDescription.ptt"); app.value("OVERWRITE_STATES", OVERWRITE_STATES); app.value("OVERWRITE_OPTIONS", OVERWRITE_OPTIONS); app.value("LOCAL_WORKER_NODES", PAGE.local.linked_nodes); app.value("REMOTE_WORKER_NODES", PAGE.remote.linked_nodes); return require( [ "cjt/bootstrap", // Application Modules "app/controllers/MainController", "app/controllers/AccountTableController", "app/directives/boolToIntDirective", "app/directives/ngDebounceDirective", "app/directives/preventBubblingDirective", "cjt/directives/pageSizeDirective", "app/directives/clickOnceDirective", "app/filters/overwriteFilter", "app/filters/bytesFilter" ], function(BOOTSTRAP) { BOOTSTRAP(document); }); }; } );
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Generation time: 0.05 |
proxy
|
phpinfo
|
Settings