Viewing File: /usr/local/cpanel/base/frontend/jupiter/domains/views/listDomains.js

//                                      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.


/* global define */

/** @namespace cpanel.domains.views.listDomains */

define(
    [
        "angular",
        "cjt/util/locale",
        "app/services/domains",
        "app/directives/domainSearchModalDirective",
        "app/directives/tldPriorityInputDirective",
        "cjt/services/cpanel/componentSettingSaverService",
    ],
    function(angular, LOCALE) {

        "use strict";

        var app = angular.module("cpanel.domains");

        /**
         * View Controller for Domain Listing
         *
         * @module listDomains
         *
         * @param  {Object} $scope angular scope
         * @param  {Object} $local angular location Object
         * @param  {Array} domains array of domains to display
         * @param  {Object} ITEM_LISTER_CONSTANTS event constants for table actions
         *
         */

        var COMPONENT_NAME = "listDomainsView";

        var controller = app.controller(
            "listDomains",
            ["$scope", "$location", "$filter", "componentSettingSaverService", "currentDomains", "ITEM_LISTER_CONSTANTS", "PAGE", "domains", "alertService", "DOMAIN_TYPE_CONSTANTS", "domainSearchModalService", "$document", "$timeout",
                function($scope, $location, $filter, $CSSS, initialDomains, ITEM_LISTER_CONSTANTS, PAGE, $domainsService, $alertService, DOMAIN_TYPE_CONSTANTS, domainSearchModalService, $document, $timeout) {

                    var _tableConfigurationOptions = [];
                    var LIST_DOMAIN_EVENTS = {
                        HIDE_ASSOCIATED: "hideAssociatedSubdomains",
                        SHOW_ASSOCIATED: "showAssociatedSubdomains",
                    };

                    // ---- Dialog focus-trap / scroll-lock helpers ----------

                    var _triggerElement = null;
                    var _dialogKeydownHandler = null;
                    var _focusTimeoutPromise = null;

                    var _FOCUSABLE_SELECTOR = [
                        "a[href]",
                        "button:not([disabled])",
                        "input:not([disabled])",
                        "select:not([disabled])",
                        "textarea:not([disabled])",
                        "[tabindex]:not([tabindex='-1'])",
                    ].join(", ");

                    function _getFocusableInDialog() {
                        var dialog = $document[0].querySelector(".domain-chooser");
                        if (!dialog) {
                            return [];
                        }

                        // offsetParent is null for elements inside position:fixed containers
                        // in some browsers, so check visibility via getComputedStyle instead.
                        var view = $document[0].defaultView;
                        return Array.prototype.filter.call(
                            dialog.querySelectorAll(_FOCUSABLE_SELECTOR),
                            function(el) {
                                if (!view) {
                                    return true;
                                }
                                var style = view.getComputedStyle(el);
                                return style.display !== "none" && style.visibility !== "hidden";
                            }
                        );
                    }

                    function _teardownDialogTrap() {
                        $document[0].body.classList.remove("domain-chooser-open");
                        if (_dialogKeydownHandler) {
                            $document[0].removeEventListener("keydown", _dialogKeydownHandler);
                            _dialogKeydownHandler = null;
                        }
                        if (_focusTimeoutPromise) {
                            $timeout.cancel(_focusTimeoutPromise);
                            _focusTimeoutPromise = null;
                        }
                    }

                    var associatedDomainsExist = initialDomains.some(function(domainObject) {
                        if (domainObject.associatedAddonDomain) {
                            return true;
                        }
                        return false;
                    });

                    /**
                     * Navigate to the Manage screen for a specific domain
                     *
                     * @method manageDomain
                     *
                     * @param  {String} domain domain to manage
                     *
                     */

                    function _manageDomain(domain) {
                        $location.path("manage").search("domain", domain);
                    }

                    function _itemChangeRequested(event, parameters) {
                        switch (parameters.actionType) {
                            case "manage":
                                _manageDomain(parameters.item.domain);
                                break;
                        }
                    }

                    function _itemListerUpdated(event, parameters) {
                        $scope.itemListerMeta = parameters.meta;
                        $scope.currentSearchFilterValue = $scope.itemListerMeta.filterValue;
                    }

                    /**
                     * On updating of the show associated addon domains checkbox, refilter domains
                     *
                     * @method onUpdateShowAssociated
                     *
                     */
                    function _filterAssociatedDomains(domain) {
                        if ($scope.showAssociatedSubdomains) {
                            return true;
                        }
                        if (!domain.associatedAddonDomain) {
                            return true;
                        }

                        return false;
                    }

                    var lastFiltered = true;

                    function _updateFiltered() {
                        var filteredDomains = $filter("filter")(initialDomains, _filterAssociatedDomains);
                        lastFiltered = $scope.showAssociatedSubdomains;

                        // Need to do this without destroying the original array
                        $scope.filteredDomains = filteredDomains;
                    }

                    function toggleShowAssociatedSubdomains() {
                        $scope.showAssociatedSubdomains = !$scope.showAssociatedSubdomains;
                        $CSSS.set(COMPONENT_NAME, { showAssociatedSubdomains: $scope.showAssociatedSubdomains });
                        _updateFiltered();
                        _updateTableConfigurationOptions();
                    }

                    function getFilteredDomains() {
                        if (lastFiltered !== $scope.showAssociatedSubdomains) {
                            _updateFiltered();
                        }
                        return $scope.filteredDomains;
                    }

                    function _updateTableConfigurationOptions() {
                        _tableConfigurationOptions.splice(0);

                        if (!associatedDomainsExist) {
                            return;
                        }

                        if ($scope.showAssociatedSubdomains) {
                            _tableConfigurationOptions.push({
                                label: LOCALE.maketext("Hide Associated Subdomains"),
                                event: LIST_DOMAIN_EVENTS.HIDE_ASSOCIATED,
                            });
                        } else {
                            _tableConfigurationOptions.push({
                                label: LOCALE.maketext("Show Associated Subdomains"),
                                event: LIST_DOMAIN_EVENTS.SHOW_ASSOCIATED,
                            });
                        }
                    }

                    $scope.$on(ITEM_LISTER_CONSTANTS.TABLE_ITEM_BUTTON_EVENT, _itemChangeRequested);
                    $scope.$on(ITEM_LISTER_CONSTANTS.ITEM_LISTER_UPDATED_EVENT, _itemListerUpdated);
                    $scope.$on(LIST_DOMAIN_EVENTS.SHOW_ASSOCIATED, toggleShowAssociatedSubdomains);
                    $scope.$on(LIST_DOMAIN_EVENTS.HIDE_ASSOCIATED, toggleShowAssociatedSubdomains);

                    $scope.domains = initialDomains;
                    $scope.filteredDomains = initialDomains;
                    $scope.showAssociatedSubdomains = false;
                    $scope.temporaryDomainBannerText = LOCALE.maketext("You cannot create an email account for a temporary domain.");
                    $scope.hasTemporaryDomainInList = !PAGE.isDisabledTempDomains && initialDomains.some(function(domain) {
                        return domain.is_temporary;
                    });
                    $scope.tableHeaderItems = [];
                    $scope.tableHeaderItems.push({ field: "batchSelect", sortable: false, label: null });
                    $scope.tableHeaderItems.push({ field: "domain", sortable: true, label: LOCALE.maketext("Domain") });
                    if (PAGE.hasWebServerRole) {
                        $scope.tableHeaderItems.push({ field: "documentRoot", sortable: true, label: LOCALE.maketext("Document Root"), hiddenInSmall: true });
                        $scope.tableHeaderItems.push({ field: "redirectsTo", sortable: true, label: LOCALE.maketext("Redirects To"), hiddenInSmall: true });
                        $scope.tableHeaderItems.push({ field: "HTTPSRedirect", sortable: true, label: LOCALE.maketext("Force HTTPS Redirect"), hiddenInSmall: true });
                    }
                    $scope.tableHeaderItems.push({ field: "actions", label: LOCALE.maketext("Actions"), hiddenInSmall: true });

                    _updateTableConfigurationOptions();

                    // Domain chooser modal logic
                    var domainRecommendationsEnabled = !!(PAGE.features && PAGE.features.domain_recommendation);
                    var canCreateAlias = !!(PAGE.features && PAGE.features.alias);
                    var mainDomain = $domainsService.getMainDomain() || {};
                    var mainDomainDocRoot = mainDomain.documentRoot || "/home/user/public_html";
                    var mainDomainName = mainDomain.domain || "";

                    function openDomainChooser() {
                        if ($scope.showDomainChooser) {
                            return;
                        }
                        _triggerElement = $document[0].activeElement || null;
                        $scope.showDomainChooser = true;
                        $scope.selectedDomainOption = null;
                        $document[0].body.classList.add("domain-chooser-open");

                        _dialogKeydownHandler = function($event) {
                            if ($event.key === "Escape") {
                                $scope.$apply(function() {
                                    if (!$scope.creatingDomain) {
                                        closeDomainChooser();
                                    }
                                });
                                return;
                            }
                            if ($event.key !== "Tab") {
                                return;
                            }
                            var focusable = _getFocusableInDialog();
                            if (!focusable.length) {
                                $event.preventDefault();
                                return;
                            }
                            var first = focusable[0];
                            var last = focusable[focusable.length - 1];
                            var dialog = $document[0].querySelector(".domain-chooser");
                            var focusIsInDialog = dialog && dialog.contains($document[0].activeElement);
                            if (!focusIsInDialog) {

                                // Focus escaped the dialog (or never landed): pull it back.
                                $event.preventDefault();
                                if ($event.shiftKey) {
                                    last.focus();
                                } else {
                                    first.focus();
                                }
                            } else if ($event.shiftKey) {
                                if ($document[0].activeElement === first) {
                                    $event.preventDefault();
                                    last.focus();
                                }
                            } else {
                                if ($document[0].activeElement === last) {
                                    $event.preventDefault();
                                    first.focus();
                                }
                            }
                        };
                        $document[0].addEventListener("keydown", _dialogKeydownHandler);

                        _focusTimeoutPromise = $timeout(function() {
                            _focusTimeoutPromise = null;
                            var focusable = _getFocusableInDialog();
                            if (focusable.length) {
                                focusable[0].focus();
                            }
                        });
                    }

                    // Monotonic token guarding the async purchase-search launch.
                    // Bumped on every launch and on cancel/close so a saved-TLD
                    // read that resolves late cannot open a stale or duplicate
                    // modal (CPANEL-53293).
                    var _purchaseLaunchToken = 0;

                    function _invalidatePurchaseLaunch() {
                        _purchaseLaunchToken++;
                    }

                    function closeDomainChooser() {
                        _invalidatePurchaseLaunch();
                        $scope.showDomainChooser = false;
                        $scope.selectedDomainOption = null;
                        $scope.registeredForm.domainName = "";
                        $scope.registeredForm.shareDocRoot = canCreateAlias;
                        $scope.registeredForm.documentRootPath = "";
                        _resetPurchaseForm();
                        _teardownDialogTrap();
                        if (_triggerElement && typeof _triggerElement.focus === "function") {
                            _triggerElement.focus();
                            _triggerElement = null;
                        }
                    }

                    function _resetPurchaseForm() {
                        $scope.purchaseForm.searchQuery = "";
                        $scope.purchaseForm.showSearchOptions = false;
                        $scope.purchaseForm.tldFilters = [];
                    }

                    // Pre-populate the prioritised TLDs from the user's saved
                    // NVData preference so a prioritisation set in a previous
                    // session carries over into the create-domain chooser and
                    // is forwarded to the search modal (CPANEL-53293). Runs
                    // after _resetPurchaseForm(); only applies the saved value
                    // when the (freshly reset) list is still empty so it never
                    // clobbers in-progress edits.
                    // Tracks the in-flight saved-TLD read so a purchase search
                    // can wait for it before seeding the modal (see
                    // _launchPurchaseSearch).
                    var _savedTldFiltersLoad = null;

                    function _loadSavedTldFilters() {
                        _savedTldFiltersLoad = $domainsService.getPrioritizedTlds().then(function(savedTlds) {
                            if (savedTlds && savedTlds.length && !$scope.purchaseForm.tldFilters.length) {
                                $scope.purchaseForm.tldFilters = savedTlds;
                            }
                        });
                        return _savedTldFiltersLoad;
                    }

                    function selectDomainOption(option) {
                        $scope.selectedDomainOption = option;
                        if (option === "registered") {
                            $scope.registeredForm.domainName = "";
                            $scope.registeredForm.shareDocRoot = canCreateAlias;
                            $scope.registeredForm.documentRootPath = "";
                            $scope.registeredForm.subdomain = "";
                            $scope.registeredForm.rootDomain = "";
                            $scope.registeredForm.domainType = "";
                        } else if (option === "purchase") {
                            _resetPurchaseForm();
                            _ensureSupportedTldsLoaded();
                            _loadSavedTldFilters();
                        }
                    }

                    function cancelDomainOption() {
                        _invalidatePurchaseLaunch();
                        $scope.selectedDomainOption = null;
                        $scope.registeredForm.domainName = "";
                        $scope.registeredForm.shareDocRoot = canCreateAlias;
                        $scope.registeredForm.documentRootPath = "";
                        $scope.registeredForm.subdomain = "";
                        $scope.registeredForm.rootDomain = "";
                        $scope.registeredForm.domainType = "";
                        _resetPurchaseForm();
                    }

                    // ----- Purchase chooser: TLD priority helpers ----------
                    // null = not yet loaded; [] = loaded but empty/unavailable.
                    $scope.supportedTlds = null;
                    var _supportedTldsRequested = false;

                    function _ensureSupportedTldsLoaded() {
                        if (_supportedTldsRequested) {
                            return;
                        }
                        _supportedTldsRequested = true;
                        $domainsService.fetchSupportedTlds()
                            .then(function(tlds) {
                                $scope.supportedTlds = tlds;
                            })
                            .catch(function() {
                                $scope.supportedTlds = [];
                            });
                    }

                    function togglePurchaseSearchOptions() {
                        $scope.purchaseForm.showSearchOptions = !$scope.purchaseForm.showSearchOptions;
                    }

                    function handlePurchaseSearchKeyup($event) {
                        if ($event.key !== "Enter") {
                            return;
                        }
                        if (!$scope.purchaseForm.searchQuery || $scope.creatingDomain) {
                            return;
                        }

                        // Handling on keyup (not keydown) lets the Enter event
                        // chain finish on the still-focused input before we
                        // mutate the DOM.  This prevents the browser from
                        // dispatching a synthetic click on whatever button
                        // gains focus next (e.g. the "Create A New Domain"
                        // trigger), which would re-open the chooser overlay
                        // on top of the search modal.
                        $event.preventDefault();
                        $event.stopPropagation();
                        confirmDomainOption();
                    }

                    function onUpdateRegisteredDomainName() {

                        // Clear derived fields on each update so previous suggestions invalidate
                        $scope.registeredForm.documentRootPath = "";
                        $scope.registeredForm.subdomain = "";
                        $scope.registeredForm.rootDomain = "";
                        $scope.registeredForm.domainType = "";

                        if (!$scope.registeredForm.domainName) {
                            return;
                        }

                        // The backend doesn't accept uppercase letters in domain names
                        $scope.registeredForm.domainName = $scope.registeredForm.domainName.toLowerCase();

                        var domainName = $scope.registeredForm.domainName;

                        // Determine domain type from name
                        var domainType = "";
                        var rootDomain = "";

                        if ($scope.registeredForm.shareDocRoot && canCreateAlias) {
                            domainType = DOMAIN_TYPE_CONSTANTS.ALIAS;
                        } else {
                            var domainParts = domainName.split(".");
                            if (domainParts.length > 2) {
                                for (var i = 1; i < domainParts.length; i++) {
                                    var suffix = domainParts.slice(i).join(".");
                                    if ($domainsService.findDomainByName(suffix)) {
                                        domainType = DOMAIN_TYPE_CONSTANTS.SUBDOMAIN;
                                        rootDomain = suffix;
                                        break;
                                    }
                                }
                            }
                            if (!domainType) {
                                domainType = DOMAIN_TYPE_CONSTANTS.ADDON;
                                rootDomain = mainDomainName;
                            }
                        }

                        $scope.registeredForm.domainType = domainType;
                        $scope.registeredForm.rootDomain = rootDomain;

                        // Auto-populate document root
                        if (!$scope.registeredForm.shareDocRoot) {
                            $scope.registeredForm.documentRootPath = domainName.replace("*", "_wildcard_");
                        }

                        // Auto-populate subdomain
                        $scope.registeredForm.subdomain = domainName;
                    }

                    function onToggleShareDocRoot() {
                        if (!$scope.registeredForm.domainName) {
                            return;
                        }

                        // Update domain type based on the new checkbox state
                        if ($scope.registeredForm.shareDocRoot && canCreateAlias) {
                            $scope.registeredForm.domainType = DOMAIN_TYPE_CONSTANTS.ALIAS;
                            $scope.registeredForm.documentRootPath = mainDomainDocRoot.replace(mainDomain.homedir + "/", "");
                        } else {
                            // Re-derive from domain name when unchecked
                            onUpdateRegisteredDomainName();
                        }
                    }

                    function confirmDomainOption() {
                        var option = $scope.selectedDomainOption;
                        if (!option) {
                            return;
                        }
                        if (option === "purchase") {
                            _launchPurchaseSearch();
                            return;
                        }
                        if (option === "temporary") {
                            _createTemporaryDomain();
                            return;
                        }
                        if (option === "registered") {
                            _createRegisteredDomain();
                            return;
                        }
                        $scope.showDomainChooser = false;
                        $scope.selectedDomainOption = null;
                        $location.path("/create").search("mode", option);
                    }

                    function _createTemporaryDomain() {
                        $scope.creatingDomain = true;

                        var domainObject = {
                            domainType: DOMAIN_TYPE_CONSTANTS.ADDON,
                            createTemporaryDomain: "1",
                            newDomainName: null,
                            documentRoot: null,
                            subdomain: null,
                            domain: null,
                            fullDocumentRoot: null,
                        };

                        $domainsService.add(domainObject).then(function(result) {
                            var domainName = result.domain;
                            var msg;
                            if (PAGE.hasWebServerRole) {
                                msg = LOCALE.maketext("You have successfully created the new “[_1]” domain with the document root of “[_2]”.", domainName, _.escape(result.documentRoot));
                            } else {
                                msg = LOCALE.maketext("You have successfully created the new “[_1]” domain.", domainName);
                            }
                            $alertService.add({
                                type: "success",
                                message: msg,
                                autoClose: 10000,
                            });
                            _updateFiltered();
                            $scope.hasTemporaryDomainInList = true;
                        }).finally(function() {
                            $scope.creatingDomain = false;
                            closeDomainChooser();
                        });
                    }

                    function _createRegisteredDomain() {
                        var domainName = ($scope.registeredForm.domainName || "").trim().toLowerCase();
                        if (!domainName) {
                            return;
                        }

                        $scope.creatingDomain = true;

                        // Use pre-computed domain type from auto-populate, or detect now
                        var domainType = $scope.registeredForm.domainType;
                        var rootDomain = $scope.registeredForm.rootDomain;

                        if (!domainType) {
                            if ($scope.registeredForm.shareDocRoot && canCreateAlias) {
                                domainType = DOMAIN_TYPE_CONSTANTS.ALIAS;
                            } else {
                                var domainParts = domainName.split(".");
                                if (domainParts.length > 2) {
                                    for (var i = 1; i < domainParts.length; i++) {
                                        var suffix = domainParts.slice(i).join(".");
                                        if ($domainsService.findDomainByName(suffix)) {
                                            domainType = DOMAIN_TYPE_CONSTANTS.SUBDOMAIN;
                                            rootDomain = suffix;
                                            break;
                                        }
                                    }
                                }
                                if (!domainType) {
                                    domainType = DOMAIN_TYPE_CONSTANTS.ADDON;
                                    rootDomain = $domainsService.getMainDomain().domain;
                                }
                            }
                        }

                        // No webserver role forces alias type
                        if (!PAGE.hasWebServerRole) {
                            domainType = DOMAIN_TYPE_CONSTANTS.ALIAS;
                        }

                        // Build document root paths — alias domains share the main domain's docroot
                        var relativeDocRoot, fullDocRoot;
                        if (domainType === DOMAIN_TYPE_CONSTANTS.ALIAS) {
                            fullDocRoot = mainDomainDocRoot;
                            relativeDocRoot = mainDomainDocRoot.replace(mainDomain.homedir + "/", "");
                        } else {
                            relativeDocRoot = $scope.registeredForm.documentRootPath || domainName.replace("*", "_wildcard_");
                            fullDocRoot = $domainsService.generateFullDocumentRoot(relativeDocRoot);
                        }

                        var subdomain = $scope.registeredForm.subdomain || domainName;

                        var domainObject = {
                            domainType: domainType,
                            newDomainName: domainName,
                            subdomain: subdomain,
                            domain: rootDomain,
                            documentRoot: relativeDocRoot,
                            fullDocumentRoot: fullDocRoot,
                            inheritDocumentRoot: $scope.registeredForm.shareDocRoot,
                        };

                        $domainsService.add(domainObject).then(function(result) {
                            var createdDomain = result.domain || domainName;
                            var msg;
                            if (PAGE.hasWebServerRole) {
                                msg = LOCALE.maketext("You have successfully created the new “[_1]” domain with the document root of “[_2]”.", _.escape(createdDomain), _.escape(result.documentRoot));
                            } else {
                                msg = LOCALE.maketext("You have successfully created the new “[_1]” domain.", _.escape(createdDomain));
                            }
                            $alertService.add({
                                type: "success",
                                message: msg,
                                autoClose: 10000,
                            });
                            _updateFiltered();
                            closeDomainChooser();
                        }).finally(function() {
                            $scope.creatingDomain = false;
                        });
                    }

                    function _launchPurchaseSearch() {
                        var query = ($scope.purchaseForm.searchQuery || "").trim();
                        if (!query) {
                            return;
                        }

                        // Claim this launch. A later launch or a cancel/close
                        // bumps the token, so a stale or duplicate callback is
                        // ignored below.
                        var token = ++_purchaseLaunchToken;

                        function _openModal() {

                            // Ignore if a repeated submit or a cancel superseded
                            // this launch while the saved-TLD read was in flight.
                            if (token !== _purchaseLaunchToken) {
                                return;
                            }
                            var initialTldFilters = $scope.purchaseForm.tldFilters.slice();
                            closeDomainChooser();
                            domainSearchModalService.open({
                                initialQuery: query,
                                initialTldFilters: initialTldFilters,
                                autoSearch: true,
                                source: "create",
                                onAddDomain: _addPurchasedDomain,
                            });
                        }

                        // Wait for any in-flight saved-TLD read to settle before
                        // seeding the modal. Without this, a fast user (select
                        // purchase → type → Continue) could open the modal with an
                        // empty initialTldFilters before the NVData read resolves;
                        // the modal treats the presence of that property as an
                        // explicit empty seed, skips its own load, and then
                        // persists the empty list on auto-search — clearing the
                        // saved preference (CPANEL-53293).
                        if (_savedTldFiltersLoad && typeof _savedTldFiltersLoad.finally === "function") {
                            _savedTldFiltersLoad.finally(_openModal);
                        } else {
                            _openModal();
                        }
                    }

                    // Callback handed to the domain-search modal: after the
                    // user purchases a domain in the store, re-open the
                    // create-domain chooser on its "Registered Domain" step
                    // with the just-purchased name prefilled, so they can add
                    // it to cPanel without retyping it.
                    // Deferred a tick so the search modal finishes tearing
                    // down — and releases focus — before the chooser dialog
                    // opens and claims it. selectDomainOption("registered")
                    // resets the form, so the name is set afterwards and the
                    // derived fields (type, document root, subdomain) are
                    // computed via onUpdateRegisteredDomainName().
                    function _addPurchasedDomain(domain) {
                        if (!domain) {
                            return;
                        }
                        $timeout(function() {
                            openDomainChooser();
                            selectDomainOption("registered");
                            $scope.registeredForm.domainName = domain;
                            onUpdateRegisteredDomainName();
                        });
                    }

                    $scope.$on("openDomainChooser", openDomainChooser);

                    angular.extend($scope, {
                        getFilteredDomains: getFilteredDomains,
                        showAssociatedSubdomains: false,
                        toggleShowAssociatedSubdomains: toggleShowAssociatedSubdomains,
                        tableConfigurationOptions: _tableConfigurationOptions,
                        showDomainChooser: false,
                        selectedDomainOption: null,
                        creatingDomain: false,
                        registeredForm: {
                            domainName: "",
                            shareDocRoot: canCreateAlias,
                            documentRootPath: "",
                            subdomain: "",
                            rootDomain: "",
                            domainType: "",
                        },
                        purchaseForm: {
                            searchQuery: "",
                            showSearchOptions: false,
                            tldFilters: [],
                        },
                        togglePurchaseSearchOptions: togglePurchaseSearchOptions,
                        handlePurchaseSearchKeyup: handlePurchaseSearchKeyup,
                        canCreateAlias: canCreateAlias,
                        domainRecommendationsEnabled: domainRecommendationsEnabled,
                        documentRootPattern: $domainsService.getDocumentRootPattern(),
                        DOMAIN_TYPE_CONSTANTS: DOMAIN_TYPE_CONSTANTS,
                        openDomainChooser: openDomainChooser,
                        closeDomainChooser: closeDomainChooser,
                        selectDomainOption: selectDomainOption,
                        cancelDomainOption: cancelDomainOption,
                        confirmDomainOption: confirmDomainOption,
                        onUpdateRegisteredDomainName: onUpdateRegisteredDomainName,
                        onToggleShareDocRoot: onToggleShareDocRoot,
                        domainChooserStrings: {
                            dialogLabel: LOCALE.maketext("Choose Domain Type"),
                            closeLabel: LOCALE.maketext("Close"),
                            heading: LOCALE.maketext("What kind of domain do you want to use?"),
                            temporaryAlt: LOCALE.maketext("Temporary domain illustration."),
                            temporarySubtitle: LOCALE.maketext("Find a domain later."),
                            temporaryHeading: LOCALE.maketext("Temporary Domain"),
                            registeredAlt: LOCALE.maketext("Registered domain illustration."),
                            registeredSubtitle: LOCALE.maketext("Use a domain you own."),
                            registeredHeading: LOCALE.maketext("Registered Domain"),
                            purchaseAlt: LOCALE.maketext("Purchase a domain illustration."),
                            purchaseSubtitle: LOCALE.maketext("Search for a new domain."),
                            purchaseHeading: LOCALE.maketext("Purchase a Domain"),
                            cancelLabel: LOCALE.maketext("Cancel"),
                            continueLabel: LOCALE.maketext("Continue"),
                            creatingLabel: LOCALE.maketext("Creating …"),
                            registeredFormLabel: LOCALE.maketext("Registered Domain"),
                            registeredFormDescription: LOCALE.maketext("Add a domain that is already registered. You can also create a subdomain for an existing domain."),
                            shareDocRootLabel: LOCALE.maketext("Share document root ([_1]) with “[_2]”?", mainDomainDocRoot, mainDomainName),
                            shareDocRootHelp: LOCALE.maketext("If the document root is shared, the new domain will serve the same content as “[_1]”. [output,strong,You cannot change this setting once you create the domain].", mainDomainName),
                            docRootHeading: LOCALE.maketext("Document Root (File System Location)"),
                            docRootDescription: LOCALE.maketext("Specify the directory where you want the files for this domain to exist."),
                            domainRequired: LOCALE.maketext("The Domain field is required."),
                            domainNotUnique: LOCALE.maketext("This domain already exists on this account."),
                            docRootPatternError: LOCALE.maketext("Directory paths cannot be empty, contain spaces, or contain the following characters: [output,chr,92] ? % * : | [output,quot] [output,gt] [output,lt]"),
                            subdomainHeading: LOCALE.maketext("Subdomain"),
                            subdomainDescription: LOCALE.maketext("An addon domain requires a subdomain in order to use a separate document root."),
                            subdomainRequired: LOCALE.maketext("A subdomain is required."),
                            purchaseFormLabel: LOCALE.maketext("Search for a domain"),
                            purchaseFormDescription: "",
                            searchLabel: LOCALE.maketext("Search"),
                            showOptions: LOCALE.maketext("Show Options"),
                            hideOptions: LOCALE.maketext("Hide Options"),
                            purchaseSearchPlaceholder: LOCALE.maketext("Use exact terms or let our AI find unique suggestions based on your input."),
                        },
                    });


                    // When the user arrives from the Manage screen's
                    // "Explore Domains → Purchase → Add Domain" flow, the
                    // purchased domain is handed over through the domains
                    // service. Consume it (one-shot) and open the chooser on
                    // its "Registered Domain" step prefilled.
                    var _pendingAddDomain = $domainsService.consumePendingAddDomain();
                    if (_pendingAddDomain) {
                        _addPurchasedDomain(_pendingAddDomain);
                    }

                    var registerSuccess = $CSSS.register(COMPONENT_NAME);
                    if ( registerSuccess ) {
                        registerSuccess.then(function _savedStateLoaded(result) {
                            if (result && $scope.showAssociatedSubdomains !== result.showAssociatedSubdomains) {
                                $scope.showAssociatedSubdomains = result.showAssociatedSubdomains;
                                _updateFiltered();
                                _updateTableConfigurationOptions();
                            }
                        });
                    }

                    $scope.$on("$destroy", function() {
                        $CSSS.unregister(COMPONENT_NAME);
                        _teardownDialogTrap();
                    });

                },
            ]
        );

        return controller;
    }
);
Back to Directory