Convert `Acp/Ui/Style/Editor` to TypeScript
authorAlexander Ebert <ebert@woltlab.com>
Fri, 4 Dec 2020 14:48:35 +0000 (15:48 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Fri, 4 Dec 2020 14:48:35 +0000 (15:48 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Style/Editor.js
wcfsetup/install/files/js/WoltLabSuite/Core/Dom/Util.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Acp/Ui/Style/Editor.js [deleted file]
wcfsetup/install/files/ts/WoltLabSuite/Core/Acp/Ui/Style/Editor.ts [new file with mode: 0644]
wcfsetup/install/files/ts/WoltLabSuite/Core/Dom/Util.ts

index af8129e18b1d91258c08e7d3f8c924287739f555..c66eb5cd0cbd3b0201c991d0c0046c1b9769b9b0 100644 (file)
 /**
  * Provides the style editor.
  *
- * @author     Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Acp/Ui/Style/Editor
+ * @author  Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Acp/Ui/Style/Editor
  */
-define(['Ajax', 'Core', 'Dictionary', 'Dom/Util', 'EventHandler', 'Ui/Screen'], function (Ajax, Core, Dictionary, DomUtil, EventHandler, UiScreen) {
+define(["require", "exports", "tslib", "../../../Ajax", "../../../Core", "../../../Dom/Util", "../../../Event/Handler", "../../../Ui/Screen"], function (require, exports, tslib_1, Ajax, Core, Util_1, EventHandler, UiScreen) {
     "use strict";
-    var _stylePreviewRegions = new Dictionary();
-    var _stylePreviewRegionMarker = null;
-    var _stylePreviewWindow = elById('spWindow');
-    var _isVisible = true;
-    var _isSmartphone = false;
-    var _updateRegionMarker = null;
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.showVisualEditor = exports.hideVisualEditor = exports.setup = void 0;
+    Ajax = tslib_1.__importStar(Ajax);
+    Core = tslib_1.__importStar(Core);
+    Util_1 = tslib_1.__importDefault(Util_1);
+    EventHandler = tslib_1.__importStar(EventHandler);
+    UiScreen = tslib_1.__importStar(UiScreen);
+    const _stylePreviewRegions = new Map();
+    let _stylePreviewRegionMarker;
+    const _stylePreviewWindow = document.getElementById("spWindow");
+    let _isVisible = true;
+    let _isSmartphone = false;
+    let _updateRegionMarker;
     /**
-     * @module WoltLabSuite/Core/Acp/Ui/Style/Editor
+     * Handles the switch between static and fluid layout.
      */
-    return {
-        /**
-         * Sets up dynamic style options.
-         */
-        setup: function (options) {
-            this._handleLayoutWidth();
-            this._handleScss(options.isTainted);
-            if (!options.isTainted) {
-                this._handleProtection(options.styleId);
+    function handleLayoutWidth() {
+        const useFluidLayout = document.getElementById("useFluidLayout");
+        const fluidLayoutMinWidth = document.getElementById("fluidLayoutMinWidth");
+        const fluidLayoutMaxWidth = document.getElementById("fluidLayoutMaxWidth");
+        const fixedLayoutVariables = document.getElementById("fixedLayoutVariables");
+        function change() {
+            if (useFluidLayout.checked) {
+                Util_1.default.show(fluidLayoutMinWidth);
+                Util_1.default.show(fluidLayoutMaxWidth);
+                Util_1.default.hide(fixedLayoutVariables);
             }
-            this._initVisualEditor(options.styleRuleMap);
-            UiScreen.on('screen-sm-down', {
-                match: this.hideVisualEditor.bind(this),
-                unmatch: this.showVisualEditor.bind(this),
-                setup: this.hideVisualEditor.bind(this)
-            });
-            var callbackRegionMarker = function () {
-                if (_isVisible)
-                    _updateRegionMarker();
-            };
-            window.addEventListener('resize', callbackRegionMarker);
-            EventHandler.add('com.woltlab.wcf.AcpMenu', 'resize', callbackRegionMarker);
-            EventHandler.add('com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer', 'select', function (data) {
-                _isVisible = (data.activeName === 'colors');
-                callbackRegionMarker();
-            });
-        },
-        /**
-         * Handles the switch between static and fluid layout.
-         */
-        _handleLayoutWidth: function () {
-            var useFluidLayout = elById('useFluidLayout');
-            var fluidLayoutMinWidth = elById('fluidLayoutMinWidth');
-            var fluidLayoutMaxWidth = elById('fluidLayoutMaxWidth');
-            var fixedLayoutVariables = elById('fixedLayoutVariables');
-            function change() {
-                var checked = useFluidLayout.checked;
-                fluidLayoutMinWidth.style[(checked ? 'remove' : 'set') + 'Property']('display', 'none');
-                fluidLayoutMaxWidth.style[(checked ? 'remove' : 'set') + 'Property']('display', 'none');
-                fixedLayoutVariables.style[(checked ? 'set' : 'remove') + 'Property']('display', 'none');
+            else {
+                Util_1.default.hide(fluidLayoutMinWidth);
+                Util_1.default.hide(fluidLayoutMaxWidth);
+                Util_1.default.show(fixedLayoutVariables);
             }
-            useFluidLayout.addEventListener('change', change);
-            change();
-        },
-        /**
-         * Handles SCSS input fields.
-         *
-         * @param      {boolean}       isTainted       false if style is in protected mode
-         */
-        _handleScss: function (isTainted) {
-            var individualScss = elById('individualScss');
-            var overrideScss = elById('overrideScss');
-            if (isTainted) {
-                EventHandler.add('com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer', 'select', function (data) {
+        }
+        useFluidLayout.addEventListener("change", change);
+        change();
+    }
+    /**
+     * Handles SCSS input fields.
+     */
+    function handleScss(isTainted) {
+        const individualScss = document.getElementById("individualScss");
+        const overrideScss = document.getElementById("overrideScss");
+        if (isTainted) {
+            EventHandler.add("com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer", "select", () => {
+                individualScss.codemirror.refresh();
+                overrideScss.codemirror.refresh();
+            });
+        }
+        else {
+            EventHandler.add("com.woltlab.wcf.simpleTabMenu_advanced", "select", (data) => {
+                if (data.activeName === "advanced-custom") {
+                    document.getElementById("individualScssCustom").codemirror.refresh();
+                    document.getElementById("overrideScssCustom").codemirror.refresh();
+                }
+                else if (data.activeName === "advanced-original") {
                     individualScss.codemirror.refresh();
                     overrideScss.codemirror.refresh();
-                });
-            }
-            else {
-                EventHandler.add('com.woltlab.wcf.simpleTabMenu_advanced', 'select', function (data) {
-                    if (data.activeName === 'advanced-custom') {
-                        elById('individualScssCustom').codemirror.refresh();
-                        elById('overrideScssCustom').codemirror.refresh();
-                    }
-                    else if (data.activeName === 'advanced-original') {
-                        individualScss.codemirror.refresh();
-                        overrideScss.codemirror.refresh();
-                    }
-                });
-            }
-        },
-        _handleProtection: function (styleId) {
-            var button = elById('styleDisableProtectionSubmit');
-            var checkbox = elById('styleDisableProtectionConfirm');
-            checkbox.addEventListener('change', function () {
-                button.disabled = !checkbox.checked;
+                }
             });
-            button.addEventListener('click', function () {
-                Ajax.apiOnce({
-                    data: {
-                        actionName: 'markAsTainted',
-                        className: 'wcf\\data\\style\\StyleAction',
-                        objectIDs: [styleId]
-                    },
-                    success: function () {
-                        window.location.reload();
-                    }
-                });
+        }
+    }
+    function handleProtection(styleId) {
+        const button = document.getElementById("styleDisableProtectionSubmit");
+        const checkbox = document.getElementById("styleDisableProtectionConfirm");
+        checkbox.addEventListener("change", () => {
+            button.disabled = !checkbox.checked;
+        });
+        button.addEventListener("click", () => {
+            Ajax.apiOnce({
+                data: {
+                    actionName: "markAsTainted",
+                    className: "wcf\\data\\style\\StyleAction",
+                    objectIDs: [styleId],
+                },
+                success: () => {
+                    window.location.reload();
+                },
             });
-        },
-        _initVisualEditor: function (styleRuleMap) {
-            elBySelAll('[data-region]', _stylePreviewWindow, function (region) {
-                _stylePreviewRegions.set(elData(region, 'region'), region);
+        });
+    }
+    function initVisualEditor(styleRuleMap) {
+        _stylePreviewWindow.querySelectorAll("[data-region]").forEach((region) => {
+            _stylePreviewRegions.set(region.dataset.region, region);
+        });
+        _stylePreviewRegionMarker = document.createElement("div");
+        _stylePreviewRegionMarker.id = "stylePreviewRegionMarker";
+        _stylePreviewRegionMarker.innerHTML = '<div id="stylePreviewRegionMarkerBottom"></div>';
+        Util_1.default.hide(_stylePreviewRegionMarker);
+        document.getElementById("colors").appendChild(_stylePreviewRegionMarker);
+        const container = document.getElementById("spSidebar");
+        const select = document.getElementById("spCategories");
+        let lastValue = select.value;
+        _updateRegionMarker = () => {
+            if (_isSmartphone) {
+                return;
+            }
+            if (lastValue === "none") {
+                Util_1.default.hide(_stylePreviewRegionMarker);
+                return;
+            }
+            const region = _stylePreviewRegions.get(lastValue);
+            const rect = region.getBoundingClientRect();
+            let top = rect.top + (window.scrollY || window.pageYOffset);
+            Util_1.default.setStyles(_stylePreviewRegionMarker, {
+                height: `${region.clientHeight + 20}px`,
+                left: `${rect.left + document.body.scrollLeft - 10}px`,
+                top: `${top - 10}px`,
+                width: `${region.clientWidth + 20}px`,
             });
-            _stylePreviewRegionMarker = elCreate('div');
-            _stylePreviewRegionMarker.id = 'stylePreviewRegionMarker';
-            _stylePreviewRegionMarker.innerHTML = '<div id="stylePreviewRegionMarkerBottom"></div>';
-            elHide(_stylePreviewRegionMarker);
-            elById('colors').appendChild(_stylePreviewRegionMarker);
-            var container = elById('spSidebar');
-            var select = elById('spCategories');
-            var lastValue = select.value;
-            _updateRegionMarker = function () {
-                if (_isSmartphone) {
-                    return;
-                }
-                if (lastValue === 'none') {
-                    elHide(_stylePreviewRegionMarker);
-                    return;
-                }
-                var region = _stylePreviewRegions.get(lastValue);
-                var rect = region.getBoundingClientRect();
-                var top = rect.top + (window.scrollY || window.pageYOffset);
-                DomUtil.setStyles(_stylePreviewRegionMarker, {
-                    height: (region.clientHeight + 20) + 'px',
-                    left: (rect.left + document.body.scrollLeft - 10) + 'px',
-                    top: (top - 10) + 'px',
-                    width: (region.clientWidth + 20) + 'px'
-                });
-                elShow(_stylePreviewRegionMarker);
-                top = DomUtil.offset(region).top;
-                // `+ 80` = account for sticky header + selection markers (20px)
-                var firstVisiblePixel = (window.pageYOffset || window.scrollY) + 80;
-                if (firstVisiblePixel > top) {
-                    window.scrollTo(0, Math.max(top - 80, 0));
+            Util_1.default.show(_stylePreviewRegionMarker);
+            top = Util_1.default.offset(region).top;
+            // `+ 80` = account for sticky header + selection markers (20px)
+            const firstVisiblePixel = (window.pageYOffset || window.scrollY) + 80;
+            if (firstVisiblePixel > top) {
+                window.scrollTo(0, Math.max(top - 80, 0));
+            }
+            else {
+                const lastVisiblePixel = window.innerHeight + (window.pageYOffset || window.scrollY);
+                if (lastVisiblePixel < top) {
+                    window.scrollTo(0, top);
                 }
                 else {
-                    var lastVisiblePixel = window.innerHeight + (window.pageYOffset || window.scrollY);
-                    if (lastVisiblePixel < top) {
-                        window.scrollTo(0, top);
-                    }
-                    else {
-                        var bottom = top + region.offsetHeight + 20;
-                        if (lastVisiblePixel < bottom) {
-                            window.scrollBy(0, bottom - top);
-                        }
+                    const bottom = top + region.offsetHeight + 20;
+                    if (lastVisiblePixel < bottom) {
+                        window.scrollBy(0, bottom - top);
                     }
                 }
-            };
-            var apiVersions = elBySel('.spSidebarBox[data-category="apiVersion"]', container);
-            var element;
-            var callbackChange = function () {
-                element = elBySel('.spSidebarBox[data-category="' + lastValue + '"]', container);
-                elHide(element);
-                lastValue = select.value;
-                element = elBySel('.spSidebarBox[data-category="' + lastValue + '"]', container);
-                elShow(element);
-                var showCompatibilityNotice = elBySel('.spApiVersion', element) !== null;
-                window[showCompatibilityNotice ? 'elShow' : 'elHide'](apiVersions);
-                // set region marker
-                _updateRegionMarker();
-            };
-            select.addEventListener('change', callbackChange);
-            // apply CSS rules
-            var style = elCreate('style');
-            style.appendChild(document.createTextNode(''));
-            elData(style, 'created-by', 'WoltLab/Acp/Ui/Style/Editor');
-            document.head.appendChild(style);
-            function updateCSSRule(identifier, value) {
-                if (styleRuleMap[identifier] === undefined) {
-                    return;
-                }
-                var rule = styleRuleMap[identifier].replace(/VALUE/g, value + ' !important');
-                if (!rule) {
-                    return;
-                }
-                var rules = [];
-                if (rule.indexOf('__COMBO_RULE__')) {
-                    rules = rule.split('__COMBO_RULE__');
-                }
-                else {
-                    rules = [rule];
+            }
+        };
+        const apiVersions = container.querySelector('.spSidebarBox[data-category="apiVersion"]');
+        const callbackChange = () => {
+            let element = container.querySelector(`.spSidebarBox[data-category="${lastValue}"]`);
+            Util_1.default.hide(element);
+            lastValue = select.value;
+            element = container.querySelector(`.spSidebarBox[data-category="${lastValue}"]`);
+            Util_1.default.show(element);
+            const showCompatibilityNotice = element.querySelector(".spApiVersion") !== null;
+            if (showCompatibilityNotice) {
+                Util_1.default.show(apiVersions);
+            }
+            else {
+                Util_1.default.hide(apiVersions);
+            }
+            // set region marker
+            _updateRegionMarker();
+        };
+        select.addEventListener("change", callbackChange);
+        // apply CSS rules
+        const style = document.createElement("style");
+        style.appendChild(document.createTextNode(""));
+        style.dataset.createdBy = "WoltLab/Acp/Ui/Style/Editor";
+        document.head.appendChild(style);
+        function updateCSSRule(identifier, value) {
+            if (styleRuleMap[identifier] === undefined) {
+                return;
+            }
+            const rule = styleRuleMap[identifier].replace(/VALUE/g, value + " !important");
+            if (!rule) {
+                return;
+            }
+            let rules;
+            if (rule.indexOf("__COMBO_RULE__")) {
+                rules = rule.split("__COMBO_RULE__");
+            }
+            else {
+                rules = [rule];
+            }
+            rules.forEach((rule) => {
+                try {
+                    style.sheet.insertRule(rule, style.sheet.cssRules.length);
                 }
-                for (var i = 0, length = rules.length; i < length; i++) {
-                    try {
-                        style.sheet.insertRule(rules[i], style.sheet.cssRules.length);
-                    }
-                    catch (e) {
-                        // ignore errors for unknown placeholder selectors
-                        if (!/[a-z]+\-placeholder/.test(rules[i])) {
-                            console.debug(e.message);
-                        }
+                catch (e) {
+                    // ignore errors for unknown placeholder selectors
+                    if (!/[a-z]+-placeholder/.test(rule)) {
+                        console.debug(e.message);
                     }
                 }
-            }
-            var elements = elByClass('styleVariableColor', elById('spVariablesWrapper'));
-            [].forEach.call(elements, function (colorField) {
-                var variableName = elData(colorField, 'store').replace(/_value$/, '');
-                var observer = new MutationObserver(function (mutations) {
-                    mutations.forEach(function (mutation) {
-                        if (mutation.attributeName === 'style') {
-                            updateCSSRule(variableName, colorField.style.getPropertyValue('background-color'));
-                        }
-                    });
-                });
-                observer.observe(colorField, {
-                    attributes: true
-                });
-                updateCSSRule(variableName, colorField.style.getPropertyValue('background-color'));
-            });
-            // category selection by clicking on the area
-            var buttonToggleColorPalette = elBySel('.jsButtonToggleColorPalette');
-            var buttonSelectCategoryByClick = elBySel('.jsButtonSelectCategoryByClick');
-            var toggleSelectionMode = function () {
-                buttonSelectCategoryByClick.classList.toggle('active');
-                buttonToggleColorPalette.classList.toggle('disabled');
-                _stylePreviewWindow.classList.toggle('spShowRegions');
-                _stylePreviewRegionMarker.classList.toggle('forceHide');
-                select.disabled = !select.disabled;
-            };
-            buttonSelectCategoryByClick.addEventListener('click', function (event) {
-                event.preventDefault();
-                toggleSelectionMode();
             });
-            elBySelAll('[data-region]', _stylePreviewWindow, function (region) {
-                region.addEventListener('click', function (event) {
-                    if (!_stylePreviewWindow.classList.contains('spShowRegions')) {
-                        return;
+        }
+        const wrapper = document.getElementById("spVariablesWrapper");
+        wrapper.querySelectorAll(".styleVariableColor").forEach((colorField) => {
+            const variableName = colorField.dataset.store.replace(/_value$/, "");
+            const observer = new MutationObserver((mutations) => {
+                mutations.forEach((mutation) => {
+                    if (mutation.attributeName === "style") {
+                        updateCSSRule(variableName, colorField.style.getPropertyValue("background-color"));
                     }
-                    event.preventDefault();
-                    event.stopPropagation();
-                    toggleSelectionMode();
-                    select.value = elData(region, 'region');
-                    // Programmatically trigger the change event handler, rather than dispatching an event,
-                    // because Firefox fails to execute the event if it has previously been disabled.
-                    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1426856
-                    callbackChange();
                 });
             });
-            // toggle view
-            var spSelectCategory = elById('spSelectCategory');
-            buttonToggleColorPalette.addEventListener('click', function (event) {
+            observer.observe(colorField, {
+                attributes: true,
+            });
+            updateCSSRule(variableName, colorField.style.getPropertyValue("background-color"));
+        });
+        // category selection by clicking on the area
+        const buttonToggleColorPalette = document.querySelector(".jsButtonToggleColorPalette");
+        const buttonSelectCategoryByClick = document.querySelector(".jsButtonSelectCategoryByClick");
+        function toggleSelectionMode() {
+            buttonSelectCategoryByClick.classList.toggle("active");
+            buttonToggleColorPalette.classList.toggle("disabled");
+            _stylePreviewWindow.classList.toggle("spShowRegions");
+            _stylePreviewRegionMarker.classList.toggle("forceHide");
+            select.disabled = !select.disabled;
+        }
+        buttonSelectCategoryByClick.addEventListener("click", (event) => {
+            event.preventDefault();
+            toggleSelectionMode();
+        });
+        _stylePreviewWindow.querySelectorAll("[data-region]").forEach((region) => {
+            region.addEventListener("click", (event) => {
+                if (!_stylePreviewWindow.classList.contains("spShowRegions")) {
+                    return;
+                }
                 event.preventDefault();
-                buttonSelectCategoryByClick.classList.toggle('disabled');
-                elToggle(spSelectCategory);
-                buttonToggleColorPalette.classList.toggle('active');
-                _stylePreviewWindow.classList.toggle('spColorPalette');
-                _stylePreviewRegionMarker.classList.toggle('forceHide');
-                select.disabled = !select.disabled;
+                event.stopPropagation();
+                toggleSelectionMode();
+                select.value = region.dataset.region;
+                // Programmatically trigger the change event handler, rather than dispatching an event,
+                // because Firefox fails to execute the event if it has previously been disabled.
+                // See https://bugzilla.mozilla.org/show_bug.cgi?id=1426856
+                callbackChange();
             });
-        },
-        hideVisualEditor: function () {
-            elHide(_stylePreviewWindow);
-            elById('spVariablesWrapper').style.removeProperty('transform');
-            elHide(elById('stylePreviewRegionMarker'));
-            _isSmartphone = true;
-        },
-        showVisualEditor: function () {
-            elShow(_stylePreviewWindow);
-            window.setTimeout(function () {
-                Core.triggerEvent(elById('spCategories'), 'change');
-            }, 100);
-            _isSmartphone = false;
+        });
+        // toggle view
+        const spSelectCategory = document.getElementById("spSelectCategory");
+        buttonToggleColorPalette.addEventListener("click", (event) => {
+            event.preventDefault();
+            buttonSelectCategoryByClick.classList.toggle("disabled");
+            Util_1.default.toggle(spSelectCategory);
+            buttonToggleColorPalette.classList.toggle("active");
+            _stylePreviewWindow.classList.toggle("spColorPalette");
+            _stylePreviewRegionMarker.classList.toggle("forceHide");
+            select.disabled = !select.disabled;
+        });
+    }
+    /**
+     * Sets up dynamic style options.
+     */
+    function setup(options) {
+        handleLayoutWidth();
+        handleScss(options.isTainted);
+        if (!options.isTainted) {
+            handleProtection(options.styleId);
+        }
+        initVisualEditor(options.styleRuleMap);
+        UiScreen.on("screen-sm-down", {
+            match() {
+                hideVisualEditor();
+            },
+            unmatch() {
+                showVisualEditor();
+            },
+            setup() {
+                hideVisualEditor();
+            },
+        });
+        function callbackRegionMarker() {
+            if (_isVisible) {
+                _updateRegionMarker();
+            }
         }
-    };
+        window.addEventListener("resize", callbackRegionMarker);
+        EventHandler.add("com.woltlab.wcf.AcpMenu", "resize", callbackRegionMarker);
+        EventHandler.add("com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer", "select", function (data) {
+            _isVisible = data.activeName === "colors";
+            callbackRegionMarker();
+        });
+    }
+    exports.setup = setup;
+    function hideVisualEditor() {
+        Util_1.default.hide(_stylePreviewWindow);
+        document.getElementById("spVariablesWrapper").style.removeProperty("transform");
+        Util_1.default.hide(document.getElementById("stylePreviewRegionMarker"));
+        _isSmartphone = true;
+    }
+    exports.hideVisualEditor = hideVisualEditor;
+    function showVisualEditor() {
+        Util_1.default.show(_stylePreviewWindow);
+        window.setTimeout(() => {
+            Core.triggerEvent(document.getElementById("spCategories"), "change");
+        }, 100);
+        _isSmartphone = false;
+    }
+    exports.showVisualEditor = showVisualEditor;
 });
index fed4dc3d1cac8fb95257e9072eac7c9fa6f65548..a98d5d15b52afcb854b19f36e1af496b63a219df 100644 (file)
@@ -352,6 +352,17 @@ define(["require", "exports", "tslib", "../StringUtil"], function (require, expo
         isHidden(element) {
             return element.style.getPropertyValue("display") === "none";
         },
+        /**
+         * Shorthand function to toggle the element visibility using either `hide()` or `show()`.
+         */
+        toggle(element) {
+            if (this.isHidden(element)) {
+                this.show(element);
+            }
+            else {
+                this.hide(element);
+            }
+        },
         /**
          * Displays or removes an error message below the provided element.
          */
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Acp/Ui/Style/Editor.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Acp/Ui/Style/Editor.js
deleted file mode 100644 (file)
index fbcdcdd..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-/**
- * Provides the style editor.
- * 
- * @author     Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Acp/Ui/Style/Editor
- */
-define(['Ajax', 'Core', 'Dictionary', 'Dom/Util', 'EventHandler', 'Ui/Screen'], function(Ajax, Core, Dictionary, DomUtil, EventHandler, UiScreen) {
-       "use strict";
-       
-       var _stylePreviewRegions = new Dictionary();
-       var _stylePreviewRegionMarker = null;
-       var _stylePreviewWindow = elById('spWindow');
-       
-       var _isVisible = true;
-       var _isSmartphone = false;
-       var _updateRegionMarker = null;
-       
-       /**
-        * @module      WoltLabSuite/Core/Acp/Ui/Style/Editor
-        */
-       return {
-               /**
-                * Sets up dynamic style options.
-                */
-               setup: function(options) {
-                       this._handleLayoutWidth();
-                       this._handleScss(options.isTainted);
-                       
-                       if (!options.isTainted) {
-                               this._handleProtection(options.styleId);
-                       }
-                       
-                       this._initVisualEditor(options.styleRuleMap);
-                       
-                       UiScreen.on('screen-sm-down', {
-                               match: this.hideVisualEditor.bind(this),
-                               unmatch: this.showVisualEditor.bind(this),
-                               setup: this.hideVisualEditor.bind(this)
-                       });
-                       
-                       var callbackRegionMarker = function () {
-                               if (_isVisible) _updateRegionMarker();
-                       };
-                       window.addEventListener('resize', callbackRegionMarker);
-                       EventHandler.add('com.woltlab.wcf.AcpMenu', 'resize', callbackRegionMarker);
-                       EventHandler.add('com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer', 'select', function (data) {
-                               _isVisible = (data.activeName === 'colors');
-                               callbackRegionMarker();
-                       });
-               },
-               
-               /**
-                * Handles the switch between static and fluid layout.
-                */
-               _handleLayoutWidth: function() {
-                       var useFluidLayout = elById('useFluidLayout');
-                       var fluidLayoutMinWidth = elById('fluidLayoutMinWidth');
-                       var fluidLayoutMaxWidth = elById('fluidLayoutMaxWidth');
-                       var fixedLayoutVariables = elById('fixedLayoutVariables');
-                       
-                       function change() {
-                               var checked = useFluidLayout.checked;
-                               
-                               fluidLayoutMinWidth.style[(checked ? 'remove' : 'set') + 'Property']('display', 'none');
-                               fluidLayoutMaxWidth.style[(checked ? 'remove' : 'set') + 'Property']('display', 'none');
-                               fixedLayoutVariables.style[(checked ? 'set' : 'remove') + 'Property']('display', 'none');
-                       }
-                       
-                       useFluidLayout.addEventListener('change', change);
-                       
-                       change();
-               },
-               
-               /**
-                * Handles SCSS input fields.
-                * 
-                * @param       {boolean}       isTainted       false if style is in protected mode
-                */
-               _handleScss: function(isTainted) {
-                       var individualScss = elById('individualScss');
-                       var overrideScss = elById('overrideScss');
-                       
-                       if (isTainted) {
-                               EventHandler.add('com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer', 'select', function(data) {
-                                       individualScss.codemirror.refresh();
-                                       overrideScss.codemirror.refresh();
-                               });
-                       }
-                       else {
-                               EventHandler.add('com.woltlab.wcf.simpleTabMenu_advanced', 'select', function(data) {
-                                       if (data.activeName === 'advanced-custom') {
-                                               elById('individualScssCustom').codemirror.refresh();
-                                               elById('overrideScssCustom').codemirror.refresh();
-                                       }
-                                       else if (data.activeName === 'advanced-original') {
-                                               individualScss.codemirror.refresh();
-                                               overrideScss.codemirror.refresh();
-                                       }
-                               });
-                       }
-               },
-               
-               _handleProtection: function(styleId) {
-                       var button = elById('styleDisableProtectionSubmit');
-                       var checkbox = elById('styleDisableProtectionConfirm');
-                       
-                       checkbox.addEventListener('change', function() {
-                               button.disabled = !checkbox.checked;
-                       });
-                       
-                       button.addEventListener('click', function() {
-                               Ajax.apiOnce({
-                                       data: {
-                                               actionName: 'markAsTainted',
-                                               className: 'wcf\\data\\style\\StyleAction',
-                                               objectIDs: [styleId]
-                                       },
-                                       success: function() {
-                                               window.location.reload();
-                                       }
-                               });
-                       });
-               },
-               
-               _initVisualEditor: function(styleRuleMap) {
-                       elBySelAll('[data-region]', _stylePreviewWindow, function(region) {
-                               _stylePreviewRegions.set(elData(region, 'region'), region);
-                       });
-                       
-                       _stylePreviewRegionMarker = elCreate('div');
-                       _stylePreviewRegionMarker.id = 'stylePreviewRegionMarker';
-                       _stylePreviewRegionMarker.innerHTML = '<div id="stylePreviewRegionMarkerBottom"></div>';
-                       elHide(_stylePreviewRegionMarker);
-                       elById('colors').appendChild(_stylePreviewRegionMarker);
-                       
-                       var container = elById('spSidebar');
-                       var select = elById('spCategories');
-                       var lastValue = select.value;
-                       
-                       _updateRegionMarker = function() {
-                               if (_isSmartphone) {
-                                       return;
-                               }
-                               
-                               if (lastValue === 'none') {
-                                       elHide(_stylePreviewRegionMarker);
-                                       return;
-                               }
-                               
-                               var region = _stylePreviewRegions.get(lastValue);
-                               var rect = region.getBoundingClientRect();
-                               
-                               var top = rect.top + (window.scrollY || window.pageYOffset);
-                               
-                               DomUtil.setStyles(_stylePreviewRegionMarker, {
-                                       height: (region.clientHeight + 20) + 'px',
-                                       left: (rect.left + document.body.scrollLeft - 10) + 'px',
-                                       top: (top - 10) + 'px',
-                                       width: (region.clientWidth + 20) + 'px'
-                               });
-                               
-                               elShow(_stylePreviewRegionMarker);
-                               
-                               top = DomUtil.offset(region).top;
-                               // `+ 80` = account for sticky header + selection markers (20px)
-                               var firstVisiblePixel = (window.pageYOffset || window.scrollY) + 80;
-                               if (firstVisiblePixel > top) {
-                                       window.scrollTo(0, Math.max(top - 80, 0));
-                               }
-                               else {
-                                       var lastVisiblePixel = window.innerHeight + (window.pageYOffset || window.scrollY);
-                                       if (lastVisiblePixel < top) {
-                                               window.scrollTo(0, top);
-                                       }
-                                       else {
-                                               var bottom = top + region.offsetHeight + 20;
-                                               if (lastVisiblePixel < bottom) {
-                                                       window.scrollBy(0, bottom - top);
-                                               }
-                                       }
-                               }
-                       };
-                       
-                       var apiVersions = elBySel('.spSidebarBox[data-category="apiVersion"]', container);
-                       var element;
-                       var callbackChange = function() {
-                               element = elBySel('.spSidebarBox[data-category="' + lastValue + '"]', container);
-                               elHide(element);
-                               
-                               lastValue = select.value;
-                               element = elBySel('.spSidebarBox[data-category="' + lastValue + '"]', container);
-                               elShow(element);
-                               
-                               var showCompatibilityNotice = elBySel('.spApiVersion', element) !== null;
-                               window[showCompatibilityNotice ? 'elShow' : 'elHide'](apiVersions);
-                               
-                               // set region marker
-                               _updateRegionMarker();
-                       };
-                       select.addEventListener('change', callbackChange);
-                       
-                       // apply CSS rules
-                       var style = elCreate('style');
-                       style.appendChild(document.createTextNode(''));
-                       elData(style, 'created-by', 'WoltLab/Acp/Ui/Style/Editor');
-                       document.head.appendChild(style);
-                       
-                       function updateCSSRule(identifier, value) {
-                               if (styleRuleMap[identifier] === undefined) {
-                                       return;
-                               }
-                               
-                               var rule = styleRuleMap[identifier].replace(/VALUE/g, value + ' !important');
-                               if (!rule) {
-                                       return;
-                               }
-                               
-                               var rules = [];
-                               if (rule.indexOf('__COMBO_RULE__')) {
-                                       rules = rule.split('__COMBO_RULE__');
-                               }
-                               else {
-                                       rules = [rule];
-                               }
-                               
-                               for (var i = 0, length = rules.length; i < length; i++) {
-                                       try {
-                                               style.sheet.insertRule(rules[i], style.sheet.cssRules.length);
-                                       }
-                                       catch (e) {
-                                               // ignore errors for unknown placeholder selectors
-                                               if (!/[a-z]+\-placeholder/.test(rules[i])) {
-                                                       console.debug(e.message);
-                                               }
-                                       }
-                               }
-                       }
-                       
-                       var elements = elByClass('styleVariableColor', elById('spVariablesWrapper'));
-                       [].forEach.call(elements, function(colorField) {
-                               var variableName = elData(colorField, 'store').replace(/_value$/, '');
-                               
-                               var observer = new MutationObserver(function(mutations) {
-                                       mutations.forEach(function(mutation) {
-                                               if (mutation.attributeName === 'style') {
-                                                       updateCSSRule(variableName, colorField.style.getPropertyValue('background-color'));
-                                               }
-                                       });
-                               });
-                               
-                               observer.observe(colorField, {
-                                       attributes: true
-                               });
-                               
-                               updateCSSRule(variableName, colorField.style.getPropertyValue('background-color'));
-                       });
-                       
-                       // category selection by clicking on the area
-                       var buttonToggleColorPalette = elBySel('.jsButtonToggleColorPalette');
-                       var buttonSelectCategoryByClick = elBySel('.jsButtonSelectCategoryByClick');
-                       var toggleSelectionMode = function() {
-                               buttonSelectCategoryByClick.classList.toggle('active');
-                               buttonToggleColorPalette.classList.toggle('disabled');
-                               _stylePreviewWindow.classList.toggle('spShowRegions');
-                               _stylePreviewRegionMarker.classList.toggle('forceHide');
-                               select.disabled = !select.disabled;
-                       };
-                       
-                       buttonSelectCategoryByClick.addEventListener('click', function (event) {
-                               event.preventDefault();
-                               
-                               toggleSelectionMode();
-                       });
-                       
-                       elBySelAll('[data-region]', _stylePreviewWindow, function (region) {
-                               region.addEventListener('click', function (event) {
-                                       if (!_stylePreviewWindow.classList.contains('spShowRegions')) {
-                                               return;
-                                       }
-                                       
-                                       event.preventDefault();
-                                       event.stopPropagation();
-                                       
-                                       toggleSelectionMode();
-                                       
-                                       select.value = elData(region, 'region');
-                                       
-                                       // Programmatically trigger the change event handler, rather than dispatching an event,
-                                       // because Firefox fails to execute the event if it has previously been disabled.
-                                       // See https://bugzilla.mozilla.org/show_bug.cgi?id=1426856
-                                       callbackChange();
-                               });
-                       });
-                       
-                       // toggle view
-                       var spSelectCategory = elById('spSelectCategory');
-                       buttonToggleColorPalette.addEventListener('click', function (event) {
-                               event.preventDefault();
-                               
-                               buttonSelectCategoryByClick.classList.toggle('disabled');
-                               elToggle(spSelectCategory);
-                               buttonToggleColorPalette.classList.toggle('active');
-                               _stylePreviewWindow.classList.toggle('spColorPalette');
-                               _stylePreviewRegionMarker.classList.toggle('forceHide');
-                               select.disabled = !select.disabled;
-                       });
-               },
-               
-               hideVisualEditor: function() {
-                       elHide(_stylePreviewWindow);
-                       elById('spVariablesWrapper').style.removeProperty('transform');
-                       elHide(elById('stylePreviewRegionMarker'));
-                       
-                       _isSmartphone = true;
-               },
-               
-               showVisualEditor: function() {
-                       elShow(_stylePreviewWindow);
-                       
-                       window.setTimeout(function() {
-                               Core.triggerEvent(elById('spCategories'), 'change');
-                       }, 100);
-                       
-                       _isSmartphone = false;
-               }
-       };
-});
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Acp/Ui/Style/Editor.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Acp/Ui/Style/Editor.ts
new file mode 100644 (file)
index 0000000..507d713
--- /dev/null
@@ -0,0 +1,346 @@
+/**
+ * Provides the style editor.
+ *
+ * @author  Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Acp/Ui/Style/Editor
+ */
+
+import * as Ajax from "../../../Ajax";
+import * as Core from "../../../Core";
+import DomUtil from "../../../Dom/Util";
+import * as EventHandler from "../../../Event/Handler";
+import * as UiScreen from "../../../Ui/Screen";
+
+const _stylePreviewRegions = new Map<string, HTMLElement>();
+let _stylePreviewRegionMarker: HTMLElement;
+const _stylePreviewWindow = document.getElementById("spWindow")!;
+
+let _isVisible = true;
+let _isSmartphone = false;
+let _updateRegionMarker: () => void;
+
+interface StyleRuleMap {
+  [key: string]: string;
+}
+
+interface StyleEditorOptions {
+  isTainted: boolean;
+  styleId: number;
+  styleRuleMap: StyleRuleMap;
+}
+
+/**
+ * Handles the switch between static and fluid layout.
+ */
+function handleLayoutWidth(): void {
+  const useFluidLayout = document.getElementById("useFluidLayout") as HTMLInputElement;
+  const fluidLayoutMinWidth = document.getElementById("fluidLayoutMinWidth") as HTMLInputElement;
+  const fluidLayoutMaxWidth = document.getElementById("fluidLayoutMaxWidth") as HTMLInputElement;
+  const fixedLayoutVariables = document.getElementById("fixedLayoutVariables") as HTMLDListElement;
+
+  function change(): void {
+    if (useFluidLayout.checked) {
+      DomUtil.show(fluidLayoutMinWidth);
+      DomUtil.show(fluidLayoutMaxWidth);
+      DomUtil.hide(fixedLayoutVariables);
+    } else {
+      DomUtil.hide(fluidLayoutMinWidth);
+      DomUtil.hide(fluidLayoutMaxWidth);
+      DomUtil.show(fixedLayoutVariables);
+    }
+  }
+
+  useFluidLayout.addEventListener("change", change);
+
+  change();
+}
+
+/**
+ * Handles SCSS input fields.
+ */
+function handleScss(isTainted: boolean): void {
+  const individualScss = document.getElementById("individualScss")!;
+  const overrideScss = document.getElementById("overrideScss")!;
+
+  if (isTainted) {
+    EventHandler.add("com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer", "select", () => {
+      (individualScss as any).codemirror.refresh();
+      (overrideScss as any).codemirror.refresh();
+    });
+  } else {
+    EventHandler.add("com.woltlab.wcf.simpleTabMenu_advanced", "select", (data: { activeName: string }) => {
+      if (data.activeName === "advanced-custom") {
+        (document.getElementById("individualScssCustom") as any).codemirror.refresh();
+        (document.getElementById("overrideScssCustom") as any).codemirror.refresh();
+      } else if (data.activeName === "advanced-original") {
+        (individualScss as any).codemirror.refresh();
+        (overrideScss as any).codemirror.refresh();
+      }
+    });
+  }
+}
+
+function handleProtection(styleId: number): void {
+  const button = document.getElementById("styleDisableProtectionSubmit") as HTMLButtonElement;
+  const checkbox = document.getElementById("styleDisableProtectionConfirm") as HTMLInputElement;
+
+  checkbox.addEventListener("change", () => {
+    button.disabled = !checkbox.checked;
+  });
+
+  button.addEventListener("click", () => {
+    Ajax.apiOnce({
+      data: {
+        actionName: "markAsTainted",
+        className: "wcf\\data\\style\\StyleAction",
+        objectIDs: [styleId],
+      },
+      success: () => {
+        window.location.reload();
+      },
+    });
+  });
+}
+
+function initVisualEditor(styleRuleMap: StyleRuleMap): void {
+  _stylePreviewWindow.querySelectorAll("[data-region]").forEach((region: HTMLElement) => {
+    _stylePreviewRegions.set(region.dataset.region!, region);
+  });
+
+  _stylePreviewRegionMarker = document.createElement("div");
+  _stylePreviewRegionMarker.id = "stylePreviewRegionMarker";
+  _stylePreviewRegionMarker.innerHTML = '<div id="stylePreviewRegionMarkerBottom"></div>';
+  DomUtil.hide(_stylePreviewRegionMarker);
+  document.getElementById("colors")!.appendChild(_stylePreviewRegionMarker);
+
+  const container = document.getElementById("spSidebar")!;
+  const select = document.getElementById("spCategories") as HTMLSelectElement;
+  let lastValue = select.value;
+
+  _updateRegionMarker = (): void => {
+    if (_isSmartphone) {
+      return;
+    }
+
+    if (lastValue === "none") {
+      DomUtil.hide(_stylePreviewRegionMarker);
+      return;
+    }
+
+    const region = _stylePreviewRegions.get(lastValue)!;
+    const rect = region.getBoundingClientRect();
+
+    let top = rect.top + (window.scrollY || window.pageYOffset);
+
+    DomUtil.setStyles(_stylePreviewRegionMarker, {
+      height: `${region.clientHeight + 20}px`,
+      left: `${rect.left + document.body.scrollLeft - 10}px`,
+      top: `${top - 10}px`,
+      width: `${region.clientWidth + 20}px`,
+    });
+
+    DomUtil.show(_stylePreviewRegionMarker);
+
+    top = DomUtil.offset(region).top;
+    // `+ 80` = account for sticky header + selection markers (20px)
+    const firstVisiblePixel = (window.pageYOffset || window.scrollY) + 80;
+    if (firstVisiblePixel > top) {
+      window.scrollTo(0, Math.max(top - 80, 0));
+    } else {
+      const lastVisiblePixel = window.innerHeight + (window.pageYOffset || window.scrollY);
+      if (lastVisiblePixel < top) {
+        window.scrollTo(0, top);
+      } else {
+        const bottom = top + region.offsetHeight + 20;
+        if (lastVisiblePixel < bottom) {
+          window.scrollBy(0, bottom - top);
+        }
+      }
+    }
+  };
+
+  const apiVersions = container.querySelector('.spSidebarBox[data-category="apiVersion"]') as HTMLElement;
+  const callbackChange = () => {
+    let element = container.querySelector(`.spSidebarBox[data-category="${lastValue}"]`) as HTMLElement;
+    DomUtil.hide(element);
+
+    lastValue = select.value;
+    element = container.querySelector(`.spSidebarBox[data-category="${lastValue}"]`) as HTMLElement;
+    DomUtil.show(element);
+
+    const showCompatibilityNotice = element.querySelector(".spApiVersion") !== null;
+    if (showCompatibilityNotice) {
+      DomUtil.show(apiVersions);
+    } else {
+      DomUtil.hide(apiVersions);
+    }
+
+    // set region marker
+    _updateRegionMarker();
+  };
+  select.addEventListener("change", callbackChange);
+
+  // apply CSS rules
+  const style = document.createElement("style");
+  style.appendChild(document.createTextNode(""));
+  style.dataset.createdBy = "WoltLab/Acp/Ui/Style/Editor";
+  document.head.appendChild(style);
+
+  function updateCSSRule(identifier: string, value: string): void {
+    if (styleRuleMap[identifier] === undefined) {
+      return;
+    }
+
+    const rule = styleRuleMap[identifier].replace(/VALUE/g, value + " !important");
+    if (!rule) {
+      return;
+    }
+
+    let rules: string[];
+    if (rule.indexOf("__COMBO_RULE__")) {
+      rules = rule.split("__COMBO_RULE__");
+    } else {
+      rules = [rule];
+    }
+
+    rules.forEach((rule) => {
+      try {
+        style.sheet!.insertRule(rule, style.sheet!.cssRules.length);
+      } catch (e) {
+        // ignore errors for unknown placeholder selectors
+        if (!/[a-z]+-placeholder/.test(rule)) {
+          console.debug(e.message);
+        }
+      }
+    });
+  }
+
+  const wrapper = document.getElementById("spVariablesWrapper")!;
+  wrapper.querySelectorAll(".styleVariableColor").forEach((colorField: HTMLElement) => {
+    const variableName = colorField.dataset.store!.replace(/_value$/, "");
+
+    const observer = new MutationObserver((mutations) => {
+      mutations.forEach((mutation) => {
+        if (mutation.attributeName === "style") {
+          updateCSSRule(variableName, colorField.style.getPropertyValue("background-color"));
+        }
+      });
+    });
+
+    observer.observe(colorField, {
+      attributes: true,
+    });
+
+    updateCSSRule(variableName, colorField.style.getPropertyValue("background-color"));
+  });
+
+  // category selection by clicking on the area
+  const buttonToggleColorPalette = document.querySelector(".jsButtonToggleColorPalette") as HTMLAnchorElement;
+  const buttonSelectCategoryByClick = document.querySelector(".jsButtonSelectCategoryByClick") as HTMLAnchorElement;
+
+  function toggleSelectionMode(): void {
+    buttonSelectCategoryByClick.classList.toggle("active");
+    buttonToggleColorPalette.classList.toggle("disabled");
+    _stylePreviewWindow.classList.toggle("spShowRegions");
+    _stylePreviewRegionMarker.classList.toggle("forceHide");
+    select.disabled = !select.disabled;
+  }
+
+  buttonSelectCategoryByClick.addEventListener("click", (event) => {
+    event.preventDefault();
+
+    toggleSelectionMode();
+  });
+
+  _stylePreviewWindow.querySelectorAll("[data-region]").forEach((region: HTMLElement) => {
+    region.addEventListener("click", (event) => {
+      if (!_stylePreviewWindow.classList.contains("spShowRegions")) {
+        return;
+      }
+
+      event.preventDefault();
+      event.stopPropagation();
+
+      toggleSelectionMode();
+
+      select.value = region.dataset.region!;
+
+      // Programmatically trigger the change event handler, rather than dispatching an event,
+      // because Firefox fails to execute the event if it has previously been disabled.
+      // See https://bugzilla.mozilla.org/show_bug.cgi?id=1426856
+      callbackChange();
+    });
+  });
+
+  // toggle view
+  const spSelectCategory = document.getElementById("spSelectCategory") as HTMLSelectElement;
+  buttonToggleColorPalette.addEventListener("click", (event) => {
+    event.preventDefault();
+
+    buttonSelectCategoryByClick.classList.toggle("disabled");
+    DomUtil.toggle(spSelectCategory);
+    buttonToggleColorPalette.classList.toggle("active");
+    _stylePreviewWindow.classList.toggle("spColorPalette");
+    _stylePreviewRegionMarker.classList.toggle("forceHide");
+    select.disabled = !select.disabled;
+  });
+}
+
+/**
+ * Sets up dynamic style options.
+ */
+export function setup(options: StyleEditorOptions): void {
+  handleLayoutWidth();
+  handleScss(options.isTainted);
+
+  if (!options.isTainted) {
+    handleProtection(options.styleId);
+  }
+
+  initVisualEditor(options.styleRuleMap);
+
+  UiScreen.on("screen-sm-down", {
+    match() {
+      hideVisualEditor();
+    },
+    unmatch() {
+      showVisualEditor();
+    },
+    setup() {
+      hideVisualEditor();
+    },
+  });
+
+  function callbackRegionMarker(): void {
+    if (_isVisible) {
+      _updateRegionMarker();
+    }
+  }
+
+  window.addEventListener("resize", callbackRegionMarker);
+  EventHandler.add("com.woltlab.wcf.AcpMenu", "resize", callbackRegionMarker);
+  EventHandler.add("com.woltlab.wcf.simpleTabMenu_styleTabMenuContainer", "select", function (data) {
+    _isVisible = data.activeName === "colors";
+    callbackRegionMarker();
+  });
+}
+
+export function hideVisualEditor(): void {
+  DomUtil.hide(_stylePreviewWindow);
+  document.getElementById("spVariablesWrapper")!.style.removeProperty("transform");
+  DomUtil.hide(document.getElementById("stylePreviewRegionMarker")!);
+
+  _isSmartphone = true;
+}
+
+export function showVisualEditor(): void {
+  DomUtil.show(_stylePreviewWindow);
+
+  window.setTimeout(() => {
+    Core.triggerEvent(document.getElementById("spCategories")!, "change");
+  }, 100);
+
+  _isSmartphone = false;
+}
index f7b61452abec5c5649c045be3e08d045318446d0..4fad7f9bbeec9cb6609060f3ae79f6b49bdea804 100644 (file)
@@ -420,6 +420,17 @@ const DomUtil = {
     return element.style.getPropertyValue("display") === "none";
   },
 
+  /**
+   * Shorthand function to toggle the element visibility using either `hide()` or `show()`.
+   */
+  toggle(element: HTMLElement): void {
+    if (this.isHidden(element)) {
+      this.show(element);
+    } else {
+      this.hide(element);
+    }
+  },
+
   /**
    * Displays or removes an error message below the provided element.
    */