Viewing File: /usr/local/cpanel/base/frontend/jupiter/domains/directives/tldPriorityInputDirective.js
// Copyright 2026 WebPros International, LLC
// All rights reserved.
// copyright@cpanel.net http://cpanel.net
// This code is subject to the cPanel license. Unauthorized copying is prohibited.
/* global define */
/**
* @namespace cpanel.domains.directive.tldPriorityInput
*
* Shared "Filter TLDs" input control. Both the create-domain
* "purchase" chooser (views/listDomains) and the domain-recommendations
* modal (directives/domainSearchModal) used to ship near-identical copies
* of this logic; this directive centralizes them so they cannot diverge.
*
* Bindings:
* priorities (=) Array of selected TLD strings (with leading dot).
* Two-way bound so callers can read the latest set.
* (Binding name preserved for backwards compatibility;
* the values are now used as filters by callers.)
* supportedTlds (=) null while loading, [] when unavailable, otherwise
* array of supported TLDs (with leading dot).
* disabled (<?) Optional boolean that disables the add button.
* inputId (@?) Optional id for the text input (so an external
* <label for="..."> can target it).
*/
define(
[
"angular",
"cjt/util/locale",
],
function(angular, LOCALE) {
"use strict";
var MODULE_NAMESPACE = "cpanel.domains.tldPriorityInput";
var TEMPLATE_URL = "directives/tldPriorityInput.ptt";
var module = angular.module(MODULE_NAMESPACE, []);
function _normalizeTld(raw) {
var s = (raw || "").trim().toLowerCase();
if (!s) {
return "";
}
if (s.charAt(0) !== ".") {
s = "." + s;
}
return s;
}
module.directive("tldPriorityInput", [function() {
return {
restrict: "E",
scope: {
priorities: "=",
supportedTlds: "=",
disabled: "=?",
inputId: "@?",
},
templateUrl: TEMPLATE_URL,
link: function(scope) {
if (!angular.isArray(scope.priorities)) {
scope.priorities = [];
}
scope.tldForm = { input: "", error: null };
scope.inputId = scope.inputId || "tldPriorityInput";
scope.errorId = scope.inputId + "Error";
// Localized strings owned by the directive — keeps the
// visual + textual contract identical at every call site.
scope.strings = {
heading: LOCALE.maketext("Filter TLDs"),
description: LOCALE.maketext("A Top-Level Domain (TLD) is the last part of a domain name."),
enterTldLabel: LOCALE.maketext("Enter a TLD"),
addLabel: LOCALE.maketext("Add"),
example: LOCALE.maketext("Ex: .com, .net"),
selectedTldsLabel: LOCALE.maketext("Selected TLDs"),
};
scope.removeTldLabel = function(tld) {
return LOCALE.maketext("Remove “[_1]”", tld);
};
scope.validateTldInput = function() {
var raw = _normalizeTld(scope.tldForm.input);
if (!raw) {
scope.tldForm.error = null;
return;
}
// Skip validation while TLDs are loading or unavailable.
if (!scope.supportedTlds || !scope.supportedTlds.length) {
scope.tldForm.error = null;
return;
}
scope.tldForm.error = scope.supportedTlds.indexOf(raw) === -1
? LOCALE.maketext('“[_1]” is not a supported TLD.', raw)
: null;
};
scope.addTldPriority = function() {
var raw = _normalizeTld(scope.tldForm.input);
if (!raw) {
return;
}
if (scope.supportedTlds && scope.supportedTlds.length &&
scope.supportedTlds.indexOf(raw) === -1) {
scope.tldForm.error = LOCALE.maketext('“[_1]” is not a supported TLD.', raw);
return;
}
scope.tldForm.error = null;
if (!angular.isArray(scope.priorities)) {
scope.priorities = [];
}
if (scope.priorities.indexOf(raw) === -1) {
scope.priorities.push(raw);
}
scope.tldForm.input = "";
};
scope.removeTldPriority = function(tld) {
if (!angular.isArray(scope.priorities)) {
return;
}
var idx = scope.priorities.indexOf(tld);
if (idx !== -1) {
scope.priorities.splice(idx, 1);
}
};
scope.handleTldKeydown = function($event) {
if ($event.keyCode === 13) {
$event.preventDefault();
scope.addTldPriority();
}
};
},
};
}]);
return {
namespace: MODULE_NAMESPACE,
};
}
);
Back to Directory