Convert `Ui/User/Editor` to TypeScript
authorAlexander Ebert <ebert@woltlab.com>
Sun, 25 Oct 2020 20:28:24 +0000 (21:28 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Wed, 28 Oct 2020 11:57:20 +0000 (12:57 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Dialog.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/User/Editor.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Dialog.ts
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Dialog/Data.ts
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Notification.ts
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/User/Editor.js [deleted file]
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/User/Editor.ts [new file with mode: 0644]

index ae0b9ced67a026adf83ebf07d14f1a9665730558..e01d74018db6ed0408ab0f1187dc8c7045cf973a 100644 (file)
@@ -29,7 +29,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
 var __importDefault = (this && this.__importDefault) || function (mod) {
     return (mod && mod.__esModule) ? mod : { "default": mod };
 };
-define(["require", "exports", "../Core", "../Dom/Change/Listener", "./Screen", "../Dom/Util", "../Language", "../Environment", "../Event/Handler"], function (require, exports, Core, Listener_1, UiScreen, Util_1, Language, Environment, EventHandler) {
+define(["require", "exports", "../Core", "../Dom/Change/Listener", "./Screen", "../Dom/Util", "../Language", "../Environment", "../Event/Handler", "./Dropdown/Simple"], function (require, exports, Core, Listener_1, UiScreen, Util_1, Language, Environment, EventHandler, Simple_1) {
     "use strict";
     Core = __importStar(Core);
     Listener_1 = __importDefault(Listener_1);
@@ -38,6 +38,7 @@ define(["require", "exports", "../Core", "../Dom/Change/Listener", "./Screen", "
     Language = __importStar(Language);
     Environment = __importStar(Environment);
     EventHandler = __importStar(EventHandler);
+    Simple_1 = __importDefault(Simple_1);
     let _activeDialog = null;
     let _callbackFocus;
     let _container;
@@ -63,7 +64,10 @@ define(["require", "exports", "../Core", "../Dom/Change/Listener", "./Screen", "
         '[contenteditable]:not([tabindex^="-"]):not([inert])',
         '[tabindex]:not([tabindex^="-"]):not([inert])',
     ];
-    return {
+    /**
+     * @exports  WoltLabSuite/Core/Ui/Dialog
+     */
+    const UiDialog = {
         /**
          * Sets up global container and internal variables.
          */
@@ -439,8 +443,7 @@ define(["require", "exports", "../Core", "../Dom/Change/Listener", "./Screen", "
             }
             if (Core.stringToBool(data.dialog.getAttribute('aria-hidden'))) {
                 // close existing dropdowns
-                // TODO
-                //UiSimpleDropdown.closeAll();
+                Simple_1.default.closeAll();
                 window.WCF.Dropdown.Interactive.Handler.closeAll();
                 if (_callbackFocus === null) {
                     _callbackFocus = this._maintainFocus.bind(this);
@@ -772,4 +775,5 @@ define(["require", "exports", "../Core", "../Dom/Change/Listener", "./Screen", "
             return {};
         },
     };
+    return UiDialog;
 });
index d3b1c69f70b6b6f8ab4aa9bee3bc898338e25c18..a9c7ed3c9b991153f9ef92da9918cdb3d5018af9 100644 (file)
 /**
  * Simple notification overlay.
  *
- * @author     Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Ui/User/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/Ui/User/Editor
  */
-define(['Ajax', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Dialog', 'Ui/Notification'], function (Ajax, Language, StringUtil, DomUtil, UiDialog, UiNotification) {
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+    Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+    o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+    __setModuleDefault(result, mod);
+    return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+define(["require", "exports", "../../Ajax", "../../Core", "../../Dom/Util", "../../Language", "../../StringUtil", "../Dialog", "../Notification"], function (require, exports, Ajax, Core, Util_1, Language, StringUtil, Dialog_1, UiNotification) {
     "use strict";
-    if (!COMPILER_TARGET_DEFAULT) {
-        var Fake = function () { };
-        Fake.prototype = {
-            init: function () { },
-            _click: function () { },
-            _submit: function () { },
-            _ajaxSuccess: function () { },
-            _ajaxSetup: function () { },
-            _dialogSetup: function () { }
-        };
-        return Fake;
-    }
-    var _actionName = '';
-    var _userHeader = null;
-    /**
-     * @exports     WoltLabSuite/Core/Ui/User/Editor
-     */
-    return {
-        /**
-         * Initializes the user editor.
-         */
-        init: function () {
-            _userHeader = elBySel('.userProfileUser');
-            // init buttons
-            ['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature', 'enable'].forEach((function (action) {
-                var button = elBySel('.userProfileButtonMenu .jsButtonUser' + StringUtil.ucfirst(action));
-                // button is missing if users lacks the permission
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.init = void 0;
+    Ajax = __importStar(Ajax);
+    Core = __importStar(Core);
+    Util_1 = __importDefault(Util_1);
+    Language = __importStar(Language);
+    StringUtil = __importStar(StringUtil);
+    Dialog_1 = __importDefault(Dialog_1);
+    UiNotification = __importStar(UiNotification);
+    class UserEditor {
+        constructor() {
+            this.actionName = '';
+            this.header = document.querySelector('.userProfileUser');
+            ['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature', 'enable'].forEach(action => {
+                const button = document.querySelector('.userProfileButtonMenu .jsButtonUser' + StringUtil.ucfirst(action));
+                // The button is missing if the current user lacks the permission.
                 if (button) {
-                    elData(button, 'action', action);
-                    button.addEventListener(WCF_CLICK_EVENT, this._click.bind(this));
+                    button.dataset.action = action;
+                    button.addEventListener('click', this._click.bind(this));
                 }
-            }).bind(this));
-        },
+            });
+        }
         /**
          * Handles clicks on action buttons.
-         *
-         * @param       {Event}         event           event object
-         * @protected
          */
-        _click: function (event) {
+        _click(event) {
             event.preventDefault();
-            //noinspection JSCheckFunctionSignatures
-            var action = elData(event.currentTarget, 'action');
-            var actionName = '';
+            const target = event.currentTarget;
+            const action = target.dataset.action || '';
+            let actionName = '';
             switch (action) {
                 case 'ban':
-                    if (elDataBool(_userHeader, 'banned')) {
+                    if (Core.stringToBool(this.header.dataset.banned || '')) {
                         actionName = 'unban';
                     }
                     break;
                 case 'disableAvatar':
-                    if (elDataBool(_userHeader, 'disable-avatar')) {
+                    if (Core.stringToBool(this.header.dataset.disableAvatar || '')) {
                         actionName = 'enableAvatar';
                     }
                     break;
                 case 'disableCoverPhoto':
-                    if (elDataBool(_userHeader, 'disable-cover-photo')) {
+                    if (Core.stringToBool(this.header.dataset.disableCoverPhoto || '')) {
                         actionName = 'enableCoverPhoto';
                     }
                     break;
                 case 'disableSignature':
-                    if (elDataBool(_userHeader, 'disable-signature')) {
+                    if (Core.stringToBool(this.header.dataset.disableSignature || '')) {
                         actionName = 'enableSignature';
                     }
                     break;
                 case 'enable':
-                    actionName = (elDataBool(_userHeader, 'is-disabled')) ? 'enable' : 'disable';
+                    actionName = (Core.stringToBool(this.header.dataset.isDisabled || '')) ? 'enable' : 'disable';
                     break;
             }
             if (actionName === '') {
-                _actionName = action;
-                UiDialog.open(this);
+                this.actionName = action;
+                Dialog_1.default.open(this);
             }
             else {
                 Ajax.api(this, {
-                    actionName: actionName
+                    actionName: actionName,
                 });
             }
-        },
+        }
         /**
          * Handles form submit and input validation.
-         *
-         * @param       {Event}         event           event object
-         * @protected
          */
-        _submit: function (event) {
+        _submit(event) {
             event.preventDefault();
-            var label = elById('wcfUiUserEditorExpiresLabel');
-            var expires = '';
-            var errorMessage = '';
-            if (!elById('wcfUiUserEditorNeverExpires').checked) {
-                expires = elById('wcfUiUserEditorExpiresDatePicker').value;
+            const label = document.getElementById('wcfUiUserEditorExpiresLabel');
+            let expires = '';
+            let errorMessage = '';
+            const neverExpires = document.getElementById('wcfUiUserEditorNeverExpires');
+            if (!neverExpires.checked) {
+                const expireValue = document.getElementById('wcfUiUserEditorExpiresDatePicker');
+                expires = expireValue.value;
                 if (expires === '') {
                     errorMessage = Language.get('wcf.global.form.error.empty');
                 }
             }
-            elInnerError(label, errorMessage);
-            var parameters = {};
-            parameters[_actionName + 'Expires'] = expires;
-            parameters[_actionName + 'Reason'] = elById('wcfUiUserEditorReason').value.trim();
+            Util_1.default.innerError(label, errorMessage);
+            const parameters = {};
+            parameters[this.actionName + 'Expires'] = expires;
+            const reason = document.getElementById('wcfUiUserEditorReason');
+            parameters[this.actionName + 'Reason'] = reason.value.trim();
             Ajax.api(this, {
-                actionName: _actionName,
-                parameters: parameters
+                actionName: this.actionName,
+                parameters: parameters,
             });
-        },
-        _ajaxSuccess: function (data) {
+        }
+        _ajaxSuccess(data) {
+            let button;
             switch (data.actionName) {
                 case 'ban':
                 case 'unban':
-                    elData(_userHeader, 'banned', (data.actionName === 'ban'));
-                    elBySel('.userProfileButtonMenu .jsButtonUserBan').textContent = Language.get('wcf.user.' + (data.actionName === 'ban' ? 'unban' : 'ban'));
-                    var contentTitle = elBySel('.contentTitle', _userHeader);
-                    var banIcon = elBySel('.jsUserBanned', contentTitle);
+                    this.header.dataset.banned = (data.actionName === 'ban') ? 'true' : 'false';
+                    button = document.querySelector('.userProfileButtonMenu .jsButtonUserBan');
+                    button.textContent = Language.get('wcf.user.' + (data.actionName === 'ban' ? 'unban' : 'ban'));
+                    const contentTitle = this.header.querySelector('.contentTitle');
+                    let banIcon = contentTitle.querySelector('.jsUserBanned');
                     if (data.actionName === 'ban') {
-                        banIcon = elCreate('span');
+                        banIcon = document.createElement('span');
                         banIcon.className = 'icon icon24 fa-lock jsUserBanned jsTooltip';
                         banIcon.title = data.returnValues;
                         contentTitle.appendChild(banIcon);
                     }
                     else if (banIcon) {
-                        elRemove(banIcon);
+                        banIcon.remove();
                     }
                     break;
                 case 'disableAvatar':
                 case 'enableAvatar':
-                    elData(_userHeader, 'disable-avatar', (data.actionName === 'disableAvatar'));
-                    elBySel('.userProfileButtonMenu .jsButtonUserDisableAvatar').textContent = Language.get('wcf.user.' + (data.actionName === 'disableAvatar' ? 'enable' : 'disable') + 'Avatar');
+                    this.header.dataset.disableAvatar = (data.actionName === 'disableAvatar') ? 'true' : 'false';
+                    button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableAvatar');
+                    button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableAvatar' ? 'enable' : 'disable') + 'Avatar');
                     break;
                 case 'disableCoverPhoto':
                 case 'enableCoverPhoto':
-                    elData(_userHeader, 'disable-cover-photo', (data.actionName === 'disableCoverPhoto'));
-                    elBySel('.userProfileButtonMenu .jsButtonUserDisableCoverPhoto').textContent = Language.get('wcf.user.' + (data.actionName === 'disableCoverPhoto' ? 'enable' : 'disable') + 'CoverPhoto');
+                    this.header.dataset.disableCoverPhoto = (data.actionName === 'disableCoverPhoto') ? 'true' : 'false';
+                    button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableCoverPhoto');
+                    button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableCoverPhoto' ? 'enable' : 'disable') + 'CoverPhoto');
                     break;
                 case 'disableSignature':
                 case 'enableSignature':
-                    elData(_userHeader, 'disable-signature', (data.actionName === 'disableSignature'));
-                    elBySel('.userProfileButtonMenu .jsButtonUserDisableSignature').textContent = Language.get('wcf.user.' + (data.actionName === 'disableSignature' ? 'enable' : 'disable') + 'Signature');
+                    this.header.dataset.disableSignature = (data.actionName === 'disableSignature') ? 'true' : 'false';
+                    button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableSignature');
+                    button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableSignature' ? 'enable' : 'disable') + 'Signature');
                     break;
                 case 'enable':
                 case 'disable':
-                    elData(_userHeader, 'is-disabled', (data.actionName === 'disable'));
-                    elBySel('.userProfileButtonMenu .jsButtonUserEnable').textContent = Language.get('wcf.acp.user.' + (data.actionName === 'enable' ? 'disable' : 'enable'));
+                    this.header.dataset.isDisabled = (data.actionName === 'disable') ? 'true' : 'false';
+                    button = document.querySelector('.userProfileButtonMenu .jsButtonUserEnable');
+                    button.textContent = Language.get('wcf.acp.user.' + (data.actionName === 'enable' ? 'disable' : 'enable'));
                     break;
             }
-            if (data.actionName === 'ban' || data.actionName === 'disableAvatar' || data.actionName === 'disableCoverPhoto' || data.actionName === 'disableSignature') {
-                UiDialog.close(this);
+            if (['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature'].indexOf(data.actionName) !== -1) {
+                Dialog_1.default.close(this);
             }
             UiNotification.show();
-        },
-        _ajaxSetup: function () {
+        }
+        _ajaxSetup() {
             return {
                 data: {
                     className: 'wcf\\data\\user\\UserAction',
-                    objectIDs: [elData(_userHeader, 'object-id')]
-                }
+                    objectIDs: [+this.header.dataset.objectId],
+                },
             };
-        },
-        _dialogSetup: function () {
+        }
+        _dialogSetup() {
             return {
                 id: 'wcfUiUserEditor',
                 options: {
-                    onSetup: (function (content) {
-                        elById('wcfUiUserEditorNeverExpires').addEventListener('change', function () {
-                            window[(this.checked) ? 'elHide' : 'elShow'](elById('wcfUiUserEditorExpiresSettings'));
+                    onSetup: content => {
+                        const checkbox = document.getElementById('wcfUiUserEditorNeverExpires');
+                        checkbox.addEventListener('change', () => {
+                            const settings = document.getElementById('wcfUiUserEditorExpiresSettings');
+                            Util_1.default[checkbox.checked ? 'hide' : 'show'](settings);
                         });
-                        elBySel('button.buttonPrimary', content).addEventListener(WCF_CLICK_EVENT, this._submit.bind(this));
-                    }).bind(this),
-                    onShow: function (content) {
-                        UiDialog.setTitle('wcfUiUserEditor', Language.get('wcf.user.' + _actionName + '.confirmMessage'));
-                        var label = elById('wcfUiUserEditorReason').nextElementSibling;
-                        var phrase = 'wcf.user.' + _actionName + '.reason.description';
+                        const submitButton = content.querySelector('button.buttonPrimary');
+                        submitButton.addEventListener('click', this._submit.bind(this));
+                    },
+                    onShow: content => {
+                        Dialog_1.default.setTitle('wcfUiUserEditor', Language.get('wcf.user.' + this.actionName + '.confirmMessage'));
+                        const reason = document.getElementById('wcfUiUserEditorReason');
+                        let label = reason.nextElementSibling;
+                        const phrase = 'wcf.user.' + this.actionName + '.reason.description';
                         label.textContent = Language.get(phrase);
                         window[(label.textContent === phrase) ? 'elHide' : 'elShow'](label);
-                        label = elById('wcfUiUserEditorNeverExpires').nextElementSibling;
-                        label.textContent = Language.get('wcf.user.' + _actionName + '.neverExpires');
-                        label = elBySel('label[for="wcfUiUserEditorExpires"]', content);
-                        label.textContent = Language.get('wcf.user.' + _actionName + '.expires');
-                        label = elById('wcfUiUserEditorExpiresLabel');
-                        label.textContent = Language.get('wcf.user.' + _actionName + '.expires.description');
-                    }
+                        label = document.getElementById('wcfUiUserEditorNeverExpires').nextElementSibling;
+                        label.textContent = Language.get('wcf.user.' + this.actionName + '.neverExpires');
+                        label = content.querySelector('label[for="wcfUiUserEditorExpires"]');
+                        label.textContent = Language.get('wcf.user.' + this.actionName + '.expires');
+                        label = document.getElementById('wcfUiUserEditorExpiresLabel');
+                        label.textContent = Language.get('wcf.user.' + this.actionName + '.expires.description');
+                    },
                 },
-                source: '<div class="section">'
-                    + '<dl>'
-                    + '<dt><label for="wcfUiUserEditorReason">' + Language.get('wcf.global.reason') + '</label></dt>'
-                    + '<dd><textarea id="wcfUiUserEditorReason" cols="40" rows="3"></textarea><small></small></dd>'
-                    + '</dl>'
-                    + '<dl>'
-                    + '<dt></dt>'
-                    + '<dd><label><input type="checkbox" id="wcfUiUserEditorNeverExpires" checked> <span></span></label></dd>'
-                    + '</dl>'
-                    + '<dl id="wcfUiUserEditorExpiresSettings" style="display: none">'
-                    + '<dt><label for="wcfUiUserEditorExpires"></label></dt>'
-                    + '<dd>'
-                    + '<input type="date" name="wcfUiUserEditorExpires" id="wcfUiUserEditorExpires" class="medium" min="' + new Date(TIME_NOW * 1000).toISOString() + '" data-ignore-timezone="true">'
-                    + '<small id="wcfUiUserEditorExpiresLabel"></small>'
-                    + '</dd>'
-                    + '</dl>'
-                    + '</div>'
-                    + '<div class="formSubmit"><button class="buttonPrimary">' + Language.get('wcf.global.button.submit') + '</button></div>'
+                source: `<div class="section">
+        <dl>
+          <dt><label for="wcfUiUserEditorReason">${Language.get('wcf.global.reason')}</label></dt>
+          <dd><textarea id="wcfUiUserEditorReason" cols="40" rows="3"></textarea><small></small></dd>
+        </dl>
+        <dl>
+          <dt></dt>
+          <dd><label><input type="checkbox" id="wcfUiUserEditorNeverExpires" checked> <span></span></label></dd>
+        </dl>
+        <dl id="wcfUiUserEditorExpiresSettings" style="display: none">
+          <dt><label for="wcfUiUserEditorExpires"></label></dt>
+          <dd>
+            <input type="date" name="wcfUiUserEditorExpires" id="wcfUiUserEditorExpires" class="medium" min="${new Date(window.TIME_NOW * 1000).toISOString()}" data-ignore-timezone="true">
+            <small id="wcfUiUserEditorExpiresLabel"></small>
+          </dd>
+        </dl>
+      </div>
+      <div class="formSubmit">
+        <button class="buttonPrimary">${Language.get('wcf.global.button.submit')}</button>
+      </div>`,
             };
         }
-    };
+    }
+    /**
+     * Initializes the user editor.
+     */
+    function init() {
+        new UserEditor();
+    }
+    exports.init = init;
 });
index 67e52155985380e7550ea8104d89bb0a324bb1e4..e8a855eee294ad6b162f14534fa992c5927d6ac1 100644 (file)
@@ -12,10 +12,18 @@ import * as Core from '../Core';
 import DomChangeListener from '../Dom/Change/Listener';
 import * as UiScreen from './Screen';
 import DomUtil from '../Dom/Util';
-import { DialogCallbackObject, DialogData, DialogId, DialogOptions, DialogHtml, AjaxInitialization } from './Dialog/Data';
+import {
+  DialogCallbackObject,
+  DialogData,
+  DialogId,
+  DialogOptions,
+  DialogHtml,
+  AjaxInitialization,
+} from './Dialog/Data';
 import * as Language from '../Language';
 import * as Environment from '../Environment';
 import * as EventHandler from '../Event/Handler';
+import UiDropdownSimple from './Dropdown/Simple';
 
 let _activeDialog: string | null = null;
 let _callbackFocus: (event: FocusEvent) => void;
@@ -48,7 +56,7 @@ const _focusableElements = [
 /**
  * @exports  WoltLabSuite/Core/Ui/Dialog
  */
-export = {
+const UiDialog = {
   /**
    * Sets up global container and internal variables.
    */
@@ -345,7 +353,7 @@ export = {
 
     const title = document.createElement('span');
     title.classList.add('dialogTitle');
-    title.textContent = options.title;
+    title.textContent = options.title!;
     title.id = titleId;
     header.appendChild(title);
 
@@ -480,8 +488,7 @@ export = {
 
     if (Core.stringToBool(data.dialog.getAttribute('aria-hidden'))) {
       // close existing dropdowns
-      // TODO
-      //UiSimpleDropdown.closeAll();
+      UiDropdownSimple.closeAll();
       window.WCF.Dropdown.Interactive.Handler.closeAll();
 
       if (_callbackFocus === null) {
@@ -875,6 +882,8 @@ export = {
   },
 };
 
+export = UiDialog;
+
 interface DialogInternalData {
   id: string;
 }
index 14aeb47390bff92728cd13c47d44f59ac76f50d7..eb5b76427e5e8b44916ef855dbcc134d5d9d3562 100644 (file)
@@ -32,7 +32,7 @@ export interface DialogOptions {
   closeButtonLabel?: string;
   closeConfirmMessage?: string;
   disableContentPadding?: boolean;
-  title: string;
+  title?: string;
 
   onBeforeClose?: CallbackOnBeforeClose | null;
   onClose?: CallbackOnClose | null;
index 65e21cd760960e07c87a8e2fe7a906ec5f06a087..a3e582f88cca527a519a7786ac222e451bfeed3a 100644 (file)
@@ -51,7 +51,7 @@ function hide() {
 /**
  * Displays a notification.
  */
-export function show(message: string, callback?: Callback, cssClassName?: string): void {
+export function show(message?: string, callback?: Callback, cssClassName?: string): void {
   if (_busy) {
     return;
   }
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/User/Editor.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/User/Editor.js
deleted file mode 100644 (file)
index 6bd2dca..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/**
- * Simple notification overlay.
- * 
- * @author     Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Ui/User/Editor
- */
-define(['Ajax', 'Language', 'StringUtil', 'Dom/Util', 'Ui/Dialog', 'Ui/Notification'], function(Ajax, Language, StringUtil, DomUtil, UiDialog, UiNotification) {
-       "use strict";
-       
-       if (!COMPILER_TARGET_DEFAULT) {
-               var Fake = function() {};
-               Fake.prototype = {
-                       init: function() {},
-                       _click: function() {},
-                       _submit: function() {},
-                       _ajaxSuccess: function() {},
-                       _ajaxSetup: function() {},
-                       _dialogSetup: function() {}
-               };
-               return Fake;
-       }
-       
-       var _actionName = '';
-       var _userHeader = null;
-       
-       /**
-        * @exports     WoltLabSuite/Core/Ui/User/Editor
-        */
-       return {
-               /**
-                * Initializes the user editor.
-                */
-               init: function() {
-                       _userHeader = elBySel('.userProfileUser');
-                       
-                       // init buttons
-                       ['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature', 'enable'].forEach((function(action) {
-                               var button = elBySel('.userProfileButtonMenu .jsButtonUser' + StringUtil.ucfirst(action));
-                               
-                               // button is missing if users lacks the permission
-                               if (button) {
-                                       elData(button, 'action', action);
-                                       button.addEventListener(WCF_CLICK_EVENT, this._click.bind(this));
-                               }
-                       }).bind(this));
-               },
-               
-               /**
-                * Handles clicks on action buttons.
-                * 
-                * @param       {Event}         event           event object
-                * @protected
-                */
-               _click: function(event) {
-                       event.preventDefault();
-                       
-                       //noinspection JSCheckFunctionSignatures
-                       var action = elData(event.currentTarget, 'action');
-                       var actionName = '';
-                       switch (action) {
-                               case 'ban':
-                                       if (elDataBool(_userHeader, 'banned')) {
-                                               actionName = 'unban';
-                                       }
-                                       break;
-                               
-                               case 'disableAvatar':
-                                       if (elDataBool(_userHeader, 'disable-avatar')) {
-                                               actionName = 'enableAvatar';
-                                       }
-                                       break;
-                                       
-                               case 'disableCoverPhoto':
-                                       if (elDataBool(_userHeader, 'disable-cover-photo')) {
-                                               actionName = 'enableCoverPhoto';
-                                       }
-                                       break;
-                               
-                               case 'disableSignature':
-                                       if (elDataBool(_userHeader, 'disable-signature')) {
-                                               actionName = 'enableSignature';
-                                       }
-                                       break;
-                               
-                               case 'enable':
-                                       actionName = (elDataBool(_userHeader, 'is-disabled')) ? 'enable' : 'disable';
-                                       break;
-                       }
-                       
-                       if (actionName === '') {
-                               _actionName = action;
-                               
-                               UiDialog.open(this);
-                       }
-                       else {
-                               Ajax.api(this, {
-                                       actionName: actionName
-                               });
-                       }
-               },
-               
-               /**
-                * Handles form submit and input validation.
-                * 
-                * @param       {Event}         event           event object
-                * @protected
-                */
-               _submit: function(event) {
-                       event.preventDefault();
-                       
-                       var label = elById('wcfUiUserEditorExpiresLabel');
-                       
-                       var expires = '';
-                       var errorMessage = '';
-                       if (!elById('wcfUiUserEditorNeverExpires').checked) {
-                               expires = elById('wcfUiUserEditorExpiresDatePicker').value;
-                               if (expires === '') {
-                                       errorMessage = Language.get('wcf.global.form.error.empty');
-                               }
-                       }
-                       
-                       elInnerError(label, errorMessage);
-                       
-                       var parameters = {};
-                       parameters[_actionName + 'Expires'] = expires;
-                       parameters[_actionName + 'Reason'] = elById('wcfUiUserEditorReason').value.trim();
-                       
-                       Ajax.api(this, {
-                               actionName: _actionName,
-                               parameters: parameters
-                       });
-               },
-               
-               _ajaxSuccess: function(data) {
-                       switch (data.actionName) {
-                               case 'ban':
-                               case 'unban':
-                                       elData(_userHeader, 'banned', (data.actionName === 'ban'));
-                                       elBySel('.userProfileButtonMenu .jsButtonUserBan').textContent = Language.get('wcf.user.' + (data.actionName === 'ban' ? 'unban' : 'ban'));
-                                       
-                                       var contentTitle = elBySel('.contentTitle', _userHeader);
-                                       var banIcon = elBySel('.jsUserBanned', contentTitle);
-                                       if (data.actionName === 'ban') {
-                                               banIcon = elCreate('span');
-                                               banIcon.className = 'icon icon24 fa-lock jsUserBanned jsTooltip';
-                                               banIcon.title = data.returnValues;
-                                               contentTitle.appendChild(banIcon);
-                                       }
-                                       else if (banIcon) {
-                                               elRemove(banIcon);
-                                       }
-                                       
-                                       break;
-                               
-                               case 'disableAvatar':
-                               case 'enableAvatar':
-                                       elData(_userHeader, 'disable-avatar', (data.actionName === 'disableAvatar'));
-                                       elBySel('.userProfileButtonMenu .jsButtonUserDisableAvatar').textContent = Language.get('wcf.user.' + (data.actionName === 'disableAvatar' ? 'enable' : 'disable') + 'Avatar');
-                                       
-                                       break;
-                                       
-                               case 'disableCoverPhoto':
-                               case 'enableCoverPhoto':
-                                       elData(_userHeader, 'disable-cover-photo', (data.actionName === 'disableCoverPhoto'));
-                                       elBySel('.userProfileButtonMenu .jsButtonUserDisableCoverPhoto').textContent = Language.get('wcf.user.' + (data.actionName === 'disableCoverPhoto' ? 'enable' : 'disable') + 'CoverPhoto');
-                                       
-                                       break;
-                                       
-                               case 'disableSignature':
-                               case 'enableSignature':
-                                       elData(_userHeader, 'disable-signature', (data.actionName === 'disableSignature'));
-                                       elBySel('.userProfileButtonMenu .jsButtonUserDisableSignature').textContent = Language.get('wcf.user.' + (data.actionName === 'disableSignature' ? 'enable' : 'disable') + 'Signature');
-                                       
-                                       break;
-                               
-                               case 'enable':
-                               case 'disable':
-                                       elData(_userHeader, 'is-disabled', (data.actionName === 'disable'));
-                                       elBySel('.userProfileButtonMenu .jsButtonUserEnable').textContent = Language.get('wcf.acp.user.' + (data.actionName === 'enable' ? 'disable' : 'enable'));
-                                       
-                                       break;
-                       }
-                       
-                       if (data.actionName === 'ban' || data.actionName === 'disableAvatar' || data.actionName === 'disableCoverPhoto' || data.actionName === 'disableSignature') {
-                               UiDialog.close(this);
-                       }
-                       
-                       UiNotification.show();
-               },
-               
-               _ajaxSetup: function () {
-                       return {
-                               data: {
-                                       className: 'wcf\\data\\user\\UserAction',
-                                       objectIDs: [ elData(_userHeader, 'object-id') ]
-                               }
-                       };
-               },
-               
-               _dialogSetup: function() {
-                       return {
-                               id: 'wcfUiUserEditor',
-                               options: {
-                                       onSetup: (function (content) {
-                                               elById('wcfUiUserEditorNeverExpires').addEventListener('change', function () {
-                                                       window[(this.checked) ? 'elHide' : 'elShow'](elById('wcfUiUserEditorExpiresSettings'));
-                                               });
-                                               
-                                               elBySel('button.buttonPrimary', content).addEventListener(WCF_CLICK_EVENT, this._submit.bind(this));
-                                       }).bind(this),
-                                       onShow: function(content) {
-                                               UiDialog.setTitle('wcfUiUserEditor', Language.get('wcf.user.' + _actionName + '.confirmMessage'));
-                                               
-                                               var label = elById('wcfUiUserEditorReason').nextElementSibling;
-                                               var phrase = 'wcf.user.' + _actionName + '.reason.description';
-                                               label.textContent = Language.get(phrase);
-                                               window[(label.textContent === phrase) ? 'elHide' : 'elShow'](label);
-                                               
-                                               label = elById('wcfUiUserEditorNeverExpires').nextElementSibling;
-                                               label.textContent = Language.get('wcf.user.' + _actionName + '.neverExpires');
-                                               
-                                               label = elBySel('label[for="wcfUiUserEditorExpires"]', content);
-                                               label.textContent = Language.get('wcf.user.' + _actionName + '.expires');
-                                               
-                                               label = elById('wcfUiUserEditorExpiresLabel');
-                                               label.textContent = Language.get('wcf.user.' + _actionName + '.expires.description');
-                                       }
-                               },
-                               source: '<div class="section">'
-                                               + '<dl>'
-                                                       + '<dt><label for="wcfUiUserEditorReason">' + Language.get('wcf.global.reason') + '</label></dt>'
-                                                       + '<dd><textarea id="wcfUiUserEditorReason" cols="40" rows="3"></textarea><small></small></dd>'
-                                               + '</dl>'
-                                               + '<dl>'
-                                                       + '<dt></dt>'
-                                                       + '<dd><label><input type="checkbox" id="wcfUiUserEditorNeverExpires" checked> <span></span></label></dd>'
-                                               + '</dl>'
-                                               + '<dl id="wcfUiUserEditorExpiresSettings" style="display: none">'
-                                                       + '<dt><label for="wcfUiUserEditorExpires"></label></dt>'
-                                                       + '<dd>'
-                                                               + '<input type="date" name="wcfUiUserEditorExpires" id="wcfUiUserEditorExpires" class="medium" min="' + new Date(TIME_NOW * 1000).toISOString() + '" data-ignore-timezone="true">'
-                                                               + '<small id="wcfUiUserEditorExpiresLabel"></small>'
-                                                       + '</dd>'
-                                               +'</dl>'
-                                       + '</div>'
-                                       + '<div class="formSubmit"><button class="buttonPrimary">' + Language.get('wcf.global.button.submit') + '</button></div>'
-                       };
-               }
-       };
-});
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/User/Editor.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/User/Editor.ts
new file mode 100644 (file)
index 0000000..314954e
--- /dev/null
@@ -0,0 +1,250 @@
+/**
+ * Simple notification overlay.
+ *
+ * @author  Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Ui/User/Editor
+ */
+
+import * as Ajax from '../../Ajax';
+import { AjaxCallbackObject } from '../../Ajax/Data';
+import * as Core from '../../Core';
+import { DialogCallbackObject, DialogSettings } from '../Dialog/Data';
+import DomUtil from '../../Dom/Util';
+import * as Language from '../../Language';
+import * as StringUtil from '../../StringUtil';
+import UiDialog from '../Dialog';
+import * as UiNotification from '../Notification';
+
+class UserEditor implements AjaxCallbackObject, DialogCallbackObject {
+  private actionName = '';
+  private readonly header: HTMLElement;
+
+  constructor() {
+    this.header = document.querySelector('.userProfileUser') as HTMLElement;
+
+    ['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature', 'enable'].forEach(action => {
+      const button = document.querySelector('.userProfileButtonMenu .jsButtonUser' + StringUtil.ucfirst(action)) as HTMLElement;
+
+      // The button is missing if the current user lacks the permission.
+      if (button) {
+        button.dataset.action = action;
+        button.addEventListener('click', this._click.bind(this));
+      }
+    });
+  }
+
+  /**
+   * Handles clicks on action buttons.
+   */
+  _click(event: MouseEvent): void {
+    event.preventDefault();
+
+    const target = event.currentTarget as HTMLElement;
+    const action = target.dataset.action || '';
+    let actionName = '';
+    switch (action) {
+      case 'ban':
+        if (Core.stringToBool(this.header.dataset.banned || '')) {
+          actionName = 'unban';
+        }
+        break;
+
+      case 'disableAvatar':
+        if (Core.stringToBool(this.header.dataset.disableAvatar || '')) {
+          actionName = 'enableAvatar';
+        }
+        break;
+
+      case 'disableCoverPhoto':
+        if (Core.stringToBool(this.header.dataset.disableCoverPhoto || '')) {
+          actionName = 'enableCoverPhoto';
+        }
+        break;
+
+      case 'disableSignature':
+        if (Core.stringToBool(this.header.dataset.disableSignature || '')) {
+          actionName = 'enableSignature';
+        }
+        break;
+
+      case 'enable':
+        actionName = (Core.stringToBool(this.header.dataset.isDisabled || '')) ? 'enable' : 'disable';
+        break;
+    }
+
+    if (actionName === '') {
+      this.actionName = action;
+
+      UiDialog.open(this);
+    } else {
+      Ajax.api(this, {
+        actionName: actionName,
+      });
+    }
+  }
+
+  /**
+   * Handles form submit and input validation.
+   */
+  _submit(event: Event): void {
+    event.preventDefault();
+
+    const label = document.getElementById('wcfUiUserEditorExpiresLabel') as HTMLElement;
+
+    let expires = '';
+    let errorMessage = '';
+    const neverExpires = document.getElementById('wcfUiUserEditorNeverExpires') as HTMLInputElement;
+    if (!neverExpires.checked) {
+      const expireValue = document.getElementById('wcfUiUserEditorExpiresDatePicker') as HTMLInputElement;
+      expires = expireValue.value;
+      if (expires === '') {
+        errorMessage = Language.get('wcf.global.form.error.empty');
+      }
+    }
+
+    DomUtil.innerError(label, errorMessage);
+
+    const parameters = {};
+    parameters[this.actionName + 'Expires'] = expires;
+    const reason = document.getElementById('wcfUiUserEditorReason') as HTMLTextAreaElement;
+    parameters[this.actionName + 'Reason'] = reason.value.trim();
+
+    Ajax.api(this, {
+      actionName: this.actionName,
+      parameters: parameters,
+    });
+  }
+
+  _ajaxSuccess(data) {
+    let button: HTMLElement;
+    switch (data.actionName) {
+      case 'ban':
+      case 'unban':
+        this.header.dataset.banned = (data.actionName === 'ban') ? 'true' : 'false';
+        button = document.querySelector('.userProfileButtonMenu .jsButtonUserBan') as HTMLElement;
+        button.textContent = Language.get('wcf.user.' + (data.actionName === 'ban' ? 'unban' : 'ban'));
+
+        const contentTitle = this.header.querySelector('.contentTitle') as HTMLElement;
+        let banIcon = contentTitle.querySelector('.jsUserBanned') as HTMLElement;
+        if (data.actionName === 'ban') {
+          banIcon = document.createElement('span');
+          banIcon.className = 'icon icon24 fa-lock jsUserBanned jsTooltip';
+          banIcon.title = data.returnValues;
+          contentTitle.appendChild(banIcon);
+        } else if (banIcon) {
+          banIcon.remove();
+        }
+        break;
+
+      case 'disableAvatar':
+      case 'enableAvatar':
+        this.header.dataset.disableAvatar = (data.actionName === 'disableAvatar') ? 'true' : 'false';
+        button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableAvatar') as HTMLElement;
+        button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableAvatar' ? 'enable' : 'disable') + 'Avatar');
+        break;
+
+      case 'disableCoverPhoto':
+      case 'enableCoverPhoto':
+        this.header.dataset.disableCoverPhoto = (data.actionName === 'disableCoverPhoto') ? 'true' : 'false';
+        button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableCoverPhoto') as HTMLElement;
+        button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableCoverPhoto' ? 'enable' : 'disable') + 'CoverPhoto');
+        break;
+
+      case 'disableSignature':
+      case 'enableSignature':
+        this.header.dataset.disableSignature = (data.actionName === 'disableSignature') ? 'true' : 'false';
+        button = document.querySelector('.userProfileButtonMenu .jsButtonUserDisableSignature') as HTMLElement;
+        button.textContent = Language.get('wcf.user.' + (data.actionName === 'disableSignature' ? 'enable' : 'disable') + 'Signature');
+        break;
+
+      case 'enable':
+      case 'disable':
+        this.header.dataset.isDisabled = (data.actionName === 'disable') ? 'true' : 'false';
+        button = document.querySelector('.userProfileButtonMenu .jsButtonUserEnable') as HTMLElement;
+        button.textContent = Language.get('wcf.acp.user.' + (data.actionName === 'enable' ? 'disable' : 'enable'));
+        break;
+    }
+
+    if (['ban', 'disableAvatar', 'disableCoverPhoto', 'disableSignature'].indexOf(data.actionName) !== -1) {
+      UiDialog.close(this);
+    }
+
+    UiNotification.show();
+  }
+
+  _ajaxSetup() {
+    return {
+      data: {
+        className: 'wcf\\data\\user\\UserAction',
+        objectIDs: [+this.header.dataset.objectId!],
+      },
+    };
+  }
+
+  _dialogSetup(): DialogSettings {
+    return {
+      id: 'wcfUiUserEditor',
+      options: {
+        onSetup: content => {
+          const checkbox = document.getElementById('wcfUiUserEditorNeverExpires') as HTMLInputElement;
+          checkbox.addEventListener('change', () => {
+            const settings = document.getElementById('wcfUiUserEditorExpiresSettings') as HTMLElement;
+            DomUtil[checkbox.checked ? 'hide' : 'show'](settings);
+          });
+
+          const submitButton = content.querySelector('button.buttonPrimary') as HTMLButtonElement;
+          submitButton.addEventListener('click', this._submit.bind(this));
+        },
+        onShow: content => {
+          UiDialog.setTitle('wcfUiUserEditor', Language.get('wcf.user.' + this.actionName + '.confirmMessage'));
+
+          const reason = document.getElementById('wcfUiUserEditorReason') as HTMLElement;
+          let label = reason.nextElementSibling as HTMLElement;
+          const phrase = 'wcf.user.' + this.actionName + '.reason.description';
+          label.textContent = Language.get(phrase);
+          window[(label.textContent === phrase) ? 'elHide' : 'elShow'](label);
+
+          label = document.getElementById('wcfUiUserEditorNeverExpires')!.nextElementSibling as HTMLElement;
+          label.textContent = Language.get('wcf.user.' + this.actionName + '.neverExpires');
+
+          label = content.querySelector('label[for="wcfUiUserEditorExpires"]') as HTMLElement;
+          label.textContent = Language.get('wcf.user.' + this.actionName + '.expires');
+
+          label = document.getElementById('wcfUiUserEditorExpiresLabel') as HTMLElement;
+          label.textContent = Language.get('wcf.user.' + this.actionName + '.expires.description');
+        },
+      },
+      source: `<div class="section">
+        <dl>
+          <dt><label for="wcfUiUserEditorReason">${Language.get('wcf.global.reason')}</label></dt>
+          <dd><textarea id="wcfUiUserEditorReason" cols="40" rows="3"></textarea><small></small></dd>
+        </dl>
+        <dl>
+          <dt></dt>
+          <dd><label><input type="checkbox" id="wcfUiUserEditorNeverExpires" checked> <span></span></label></dd>
+        </dl>
+        <dl id="wcfUiUserEditorExpiresSettings" style="display: none">
+          <dt><label for="wcfUiUserEditorExpires"></label></dt>
+          <dd>
+            <input type="date" name="wcfUiUserEditorExpires" id="wcfUiUserEditorExpires" class="medium" min="${new Date(window.TIME_NOW * 1000).toISOString()}" data-ignore-timezone="true">
+            <small id="wcfUiUserEditorExpiresLabel"></small>
+          </dd>
+        </dl>
+      </div>
+      <div class="formSubmit">
+        <button class="buttonPrimary">${Language.get('wcf.global.button.submit')}</button>
+      </div>`,
+    };
+  }
+}
+
+/**
+ * Initializes the user editor.
+ */
+export function init() {
+  new UserEditor();
+}
+               
+