Convert `Media/Upload` to TypeScript
authorMatthias Schmidt <gravatronics@live.com>
Tue, 5 Jan 2021 17:40:16 +0000 (18:40 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Tue, 5 Jan 2021 17:40:16 +0000 (18:40 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Media/Upload.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.js [deleted file]
wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.ts [new file with mode: 0644]

index 86c4abdc419c20df7ff4700820bb94c56d71d43b..45a280069d47c349335dce0dbdb86afbcb3f64cc 100644 (file)
 /**
  * Uploads media files.
  *
- * @author     Matthias Schmidt
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Media/Upload
+ * @author  Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Media/Upload
  */
-define([
-    'Core',
-    'DateUtil',
-    'Dom/ChangeListener',
-    'Dom/Traverse',
-    'Dom/Util',
-    'EventHandler',
-    'Language',
-    'Permission',
-    'Upload',
-    'User',
-    'WoltLabSuite/Core/FileUtil'
-], function (Core, DateUtil, DomChangeListener, DomTraverse, DomUtil, EventHandler, Language, Permission, Upload, User, FileUtil) {
+define(["require", "exports", "tslib", "../Upload", "../Core", "../Dom/Util", "../Dom/Traverse", "../Language", "../User", "../Date/Util", "../FileUtil", "../Dom/Change/Listener", "../Event/Handler"], function (require, exports, tslib_1, Upload_1, Core, DomUtil, DomTraverse, Language, User_1, DateUtil, FileUtil, DomChangeListener, EventHandler) {
     "use strict";
-    if (!COMPILER_TARGET_DEFAULT) {
-        var Fake = function () { };
-        Fake.prototype = {
-            _createFileElement: function () { },
-            _getParameters: function () { },
-            _success: function () { },
-            _uploadFiles: function () { },
-            _createButton: function () { },
-            _createFileElements: function () { },
-            _failure: function () { },
-            _insertButton: function () { },
-            _progress: function () { },
-            _removeButton: function () { },
-            _upload: function () { }
-        };
-        return Fake;
-    }
-    /**
-     * @constructor
-     */
-    function MediaUpload(buttonContainerId, targetId, options) {
-        options = options || {};
-        this._elementTagSize = 144;
-        if (options.elementTagSize) {
-            this._elementTagSize = options.elementTagSize;
-        }
-        this._mediaManager = null;
-        if (options.mediaManager) {
-            this._mediaManager = options.mediaManager;
-            delete options.mediaManager;
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.MediaUpload = void 0;
+    Upload_1 = tslib_1.__importDefault(Upload_1);
+    Core = tslib_1.__importStar(Core);
+    DomUtil = tslib_1.__importStar(DomUtil);
+    DomTraverse = tslib_1.__importStar(DomTraverse);
+    Language = tslib_1.__importStar(Language);
+    User_1 = tslib_1.__importDefault(User_1);
+    DateUtil = tslib_1.__importStar(DateUtil);
+    FileUtil = tslib_1.__importStar(FileUtil);
+    DomChangeListener = tslib_1.__importStar(DomChangeListener);
+    EventHandler = tslib_1.__importStar(EventHandler);
+    class MediaUpload extends Upload_1.default {
+        constructor(buttonContainerId, targetId, options) {
+            super(buttonContainerId, targetId, Core.extend({
+                className: "wcf\\data\\media\\MediaAction",
+                multiple: options.mediaManager ? true : false,
+                singleFileRequests: true,
+            }, options || {}));
+            this._categoryId = null;
+            options = options || {};
+            this._elementTagSize = 144;
+            if (this._options.elementTagSize) {
+                this._elementTagSize = this._options.elementTagSize;
+            }
+            this._mediaManager = null;
+            if (this._options.mediaManager) {
+                this._mediaManager = this._options.mediaManager;
+                delete this._options.mediaManager;
+            }
         }
-        this._categoryId = null;
-        Upload.call(this, buttonContainerId, targetId, Core.extend({
-            className: 'wcf\\data\\media\\MediaAction',
-            multiple: this._mediaManager ? true : false,
-            singleFileRequests: true
-        }, options));
-    }
-    Core.inherit(MediaUpload, Upload, {
-        /**
-         * @see        WoltLabSuite/Core/Upload#_createFileElement
-         */
-        _createFileElement: function (file) {
-            var fileElement;
-            if (this._target.nodeName === 'OL' || this._target.nodeName === 'UL') {
-                fileElement = elCreate('li');
+        _createFileElement(file) {
+            let fileElement;
+            if (this._target.nodeName === "OL" || this._target.nodeName === "UL") {
+                fileElement = document.createElement("li");
             }
-            else if (this._target.nodeName === 'TBODY') {
-                var firstTr = elByTag('TR', this._target)[0];
-                var tableContainer = this._target.parentNode.parentNode;
-                if (tableContainer.style.getPropertyValue('display') === 'none') {
+            else if (this._target.nodeName === "TBODY") {
+                const firstTr = this._target.getElementsByTagName("TR")[0];
+                const tableContainer = this._target.parentNode.parentNode;
+                if (tableContainer.style.getPropertyValue("display") === "none") {
                     fileElement = firstTr;
-                    tableContainer.style.removeProperty('display');
-                    elRemove(elById(elData(this._target, 'no-items-info')));
+                    tableContainer.style.removeProperty("display");
+                    document.getElementById(this._target.dataset.noItemsInfo).remove();
                 }
                 else {
                     fileElement = firstTr.cloneNode(true);
                     // regenerate id of table row
-                    fileElement.removeAttribute('id');
+                    fileElement.removeAttribute("id");
                     DomUtil.identify(fileElement);
                 }
-                var cells = elByTag('TD', fileElement), cell;
-                for (var i = 0, length = cells.length; i < length; i++) {
-                    cell = cells[i];
-                    if (cell.classList.contains('columnMark')) {
-                        elBySelAll('[data-object-id]', cell, elHide);
+                Array.from(fileElement.getElementsByTagName("TD")).forEach((cell) => {
+                    if (cell.classList.contains("columnMark")) {
+                        cell.querySelectorAll("[data-object-id]").forEach((el) => (el.style.display = "none"));
                     }
-                    else if (cell.classList.contains('columnIcon')) {
-                        elBySelAll('[data-object-id]', cell, elHide);
-                        elByClass('mediaEditButton', cell)[0].classList.add('jsMediaEditButton');
-                        elData(elByClass('jsDeleteButton', cell)[0], 'confirm-message-html', Language.get('wcf.media.delete.confirmMessage', {
-                            title: file.name
-                        }));
+                    else if (cell.classList.contains("columnIcon")) {
+                        cell.querySelectorAll("[data-object-id]").forEach((el) => (el.style.display = "none"));
+                        cell.querySelector(".mediaEditButton").classList.add("jsMediaEditButton");
+                        cell.querySelector(".jsDeleteButton").dataset.confirmMessageHtml = Language.get("wcf.media.delete.confirmMessage", {
+                            title: file.name,
+                        });
                     }
-                    else if (cell.classList.contains('columnFilename')) {
+                    else if (cell.classList.contains("columnFilename")) {
                         // replace copied image with spinner
-                        var image = elByTag('IMG', cell);
-                        if (!image.length) {
-                            image = elByClass('icon48', cell);
+                        let image = cell.querySelector("img");
+                        if (!image) {
+                            image = cell.querySelector(".icon48");
                         }
-                        var spinner = elCreate('span');
-                        spinner.className = 'icon icon48 fa-spinner mediaThumbnail';
-                        DomUtil.replaceElement(image[0], spinner);
+                        const spinner = document.createElement("span");
+                        spinner.className = "icon icon48 fa-spinner mediaThumbnail";
+                        DomUtil.replaceElement(image, spinner);
                         // replace title and uploading user
-                        var ps = elBySelAll('.box48 > div > p', cell);
+                        const ps = cell.querySelectorAll(".box48 > div > p");
                         ps[0].textContent = file.name;
-                        var userLink = elByTag('A', ps[1])[0];
+                        let userLink = ps[1].getElementsByTagName("A")[0];
                         if (!userLink) {
-                            userLink = elCreate('a');
-                            elByTag('SMALL', ps[1])[0].appendChild(userLink);
+                            userLink = document.createElement("a");
+                            ps[1].getElementsByTagName("SMALL")[0].appendChild(userLink);
                         }
-                        userLink.setAttribute('href', User.getLink());
-                        userLink.textContent = User.username;
+                        userLink.setAttribute("href", User_1.default.getLink());
+                        userLink.textContent = User_1.default.username;
                     }
-                    else if (cell.classList.contains('columnUploadTime')) {
-                        cell.innerHTML = '';
+                    else if (cell.classList.contains("columnUploadTime")) {
+                        cell.innerHTML = "";
                         cell.appendChild(DateUtil.getTimeElement(new Date()));
                     }
-                    else if (cell.classList.contains('columnDigits')) {
+                    else if (cell.classList.contains("columnDigits")) {
                         cell.textContent = FileUtil.formatFilesize(file.size);
                     }
                     else {
                         // empty the other cells
-                        cell.innerHTML = '';
+                        cell.innerHTML = "";
                     }
-                }
+                });
                 DomUtil.prepend(fileElement, this._target);
                 return fileElement;
             }
             else {
-                fileElement = elCreate('p');
+                fileElement = document.createElement("p");
             }
-            var thumbnail = elCreate('div');
-            thumbnail.className = 'mediaThumbnail';
+            const thumbnail = document.createElement("div");
+            thumbnail.className = "mediaThumbnail";
             fileElement.appendChild(thumbnail);
-            var fileIcon = elCreate('span');
-            fileIcon.className = 'icon icon144 fa-spinner';
+            const fileIcon = document.createElement("span");
+            fileIcon.className = "icon icon144 fa-spinner";
             thumbnail.appendChild(fileIcon);
-            var mediaInformation = elCreate('div');
-            mediaInformation.className = 'mediaInformation';
+            const mediaInformation = document.createElement("div");
+            mediaInformation.className = "mediaInformation";
             fileElement.appendChild(mediaInformation);
-            var p = elCreate('p');
-            p.className = 'mediaTitle';
+            const p = document.createElement("p");
+            p.className = "mediaTitle";
             p.textContent = file.name;
             mediaInformation.appendChild(p);
-            var progress = elCreate('progress');
-            elAttr(progress, 'max', 100);
+            const progress = document.createElement("progress");
+            progress.max = 100;
             mediaInformation.appendChild(progress);
             DomUtil.prepend(fileElement, this._target);
             DomChangeListener.trigger();
             return fileElement;
-        },
-        /**
-         * @see        WoltLabSuite/Core/Upload#_getParameters
-         */
-        _getParameters: function () {
-            var parameters = {
-                elementTagSize: this._elementTagSize
+        }
+        _getParameters() {
+            const parameters = {
+                elementTagSize: this._elementTagSize,
             };
             if (this._mediaManager) {
-                parameters.imagesOnly = this._mediaManager.getOption('imagesOnly');
-                var categoryId = this._mediaManager.getCategoryId();
+                parameters.imagesOnly = this._mediaManager.getOption("imagesOnly");
+                const categoryId = this._mediaManager.getCategoryId();
                 if (categoryId) {
                     parameters.categoryID = categoryId;
                 }
             }
-            return Core.extend(MediaUpload._super.prototype._getParameters.call(this), parameters);
-        },
-        /**
-         * Replaces the default or copied file icon with the actual file icon.
-         *
-         * @param      {HTMLElement}   fileIcon        file icon element
-         * @param      {object}        media           media data
-         * @param      {integer}       size            size of the file icon in pixels
-         */
-        _replaceFileIcon: function (fileIcon, media, size) {
+            return Core.extend(super._getParameters(), parameters);
+        }
+        _replaceFileIcon(fileIcon, media, size) {
             if (media.elementTag) {
                 fileIcon.outerHTML = media.elementTag;
             }
             else if (media.tinyThumbnailType) {
-                var img = elCreate('img');
-                elAttr(img, 'src', media.tinyThumbnailLink);
-                elAttr(img, 'alt', '');
-                img.style.setProperty('width', size + 'px');
-                img.style.setProperty('height', size + 'px');
+                const img = document.createElement("img");
+                img.src = media.tinyThumbnailLink;
+                img.alt = "";
+                img.style.setProperty("width", `${size}px`);
+                img.style.setProperty("height", `${size}px`);
                 DomUtil.replaceElement(fileIcon, img);
             }
             else {
-                fileIcon.classList.remove('fa-spinner');
-                var fileIconName = FileUtil.getIconNameByFilename(media.filename);
+                fileIcon.classList.remove("fa-spinner");
+                let fileIconName = FileUtil.getIconNameByFilename(media.filename);
                 if (fileIconName) {
-                    fileIconName = '-' + fileIconName;
+                    fileIconName = "-" + fileIconName;
                 }
-                fileIcon.classList.add('fa-file' + fileIconName + '-o');
+                fileIcon.classList.add(`fa-file${fileIconName}-o`);
             }
-        },
-        /**
-         * @see        WoltLabSuite/Core/Upload#_success
-         */
-        _success: function (uploadId, data) {
-            var files = this._fileElements[uploadId];
-            for (var i = 0, length = files.length; i < length; i++) {
-                var file = files[i];
-                var internalFileId = elData(file, 'internal-file-id');
-                var media = data.returnValues.media[internalFileId];
-                if (file.tagName === 'TR') {
+        }
+        _success(uploadId, data) {
+            const files = this._fileElements[uploadId];
+            files.forEach((file) => {
+                const internalFileId = file.dataset.internalFileId;
+                const media = data.returnValues.media[internalFileId];
+                if (file.tagName === "TR") {
                     if (media) {
                         // update object id
-                        var objectIdElements = elBySelAll('[data-object-id]', file);
-                        for (var i = 0, length = objectIdElements.length; i < length; i++) {
-                            elData(objectIdElements[i], 'object-id', ~~media.mediaID);
-                            elShow(objectIdElements[i]);
-                        }
-                        elByClass('columnMediaID', file)[0].textContent = media.mediaID;
+                        file.querySelectorAll("[data-object-id]").forEach((el) => {
+                            el.dataset.objectId = media.mediaID;
+                            el.style.removeProperty("display");
+                        });
+                        file.querySelector(".columnMediaID").textContent = media.mediaID;
                         // update icon
-                        var fileIcon = elByClass('fa-spinner', file)[0];
-                        this._replaceFileIcon(fileIcon, media, 48);
+                        this._replaceFileIcon(file.querySelector(".fa-spinner"), media, 48);
                     }
                     else {
-                        var error = data.returnValues.errors[internalFileId];
+                        let error = data.returnValues.errors[internalFileId];
                         if (!error) {
                             error = {
-                                errorType: 'uploadFailed',
-                                filename: elData(file, 'filename')
+                                errorType: "uploadFailed",
+                                filename: file.dataset.filename,
                             };
                         }
-                        var fileIcon = elByClass('fa-spinner', file)[0];
-                        fileIcon.classList.remove('fa-spinner');
-                        fileIcon.classList.add('fa-remove');
-                        fileIcon.classList.add('pointer');
-                        fileIcon.classList.add('jsTooltip');
-                        elAttr(fileIcon, 'title', Language.get('wcf.global.button.delete'));
-                        fileIcon.addEventListener('click', function (event) {
-                            elRemove(event.currentTarget.parentNode.parentNode.parentNode);
-                            EventHandler.fire('com.woltlab.wcf.media.upload', 'removedErroneousUploadRow');
+                        const fileIcon = file.querySelector(".fa-spinner");
+                        fileIcon.classList.remove("fa-spinner");
+                        fileIcon.classList.add("fa-remove");
+                        fileIcon.classList.add("pointer");
+                        fileIcon.classList.add("jsTooltip");
+                        fileIcon.title = Language.get("wcf.global.button.delete");
+                        fileIcon.addEventListener("click", (event) => {
+                            const target = event.currentTarget;
+                            target.parentNode.parentNode.parentNode.remove();
+                            EventHandler.fire("com.woltlab.wcf.media.upload", "removedErroneousUploadRow");
                         });
-                        file.classList.add('uploadFailed');
-                        var p = elBySelAll('.columnFilename .box48 > div > p', file)[1];
-                        elInnerError(p, Language.get('wcf.media.upload.error.' + error.errorType, {
-                            filename: error.filename
+                        file.classList.add("uploadFailed");
+                        const p = file.querySelectorAll(".columnFilename .box48 > div > p")[1];
+                        DomUtil.innerError(p, Language.get(`wcf.media.upload.error.${error.errorType}`, {
+                            filename: error.filename,
                         }));
-                        elRemove(p);
+                        p.remove();
                     }
                 }
                 else {
-                    elRemove(DomTraverse.childByTag(DomTraverse.childByClass(file, 'mediaInformation'), 'PROGRESS'));
+                    DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaInformation"), "PROGRESS").remove();
                     if (media) {
-                        var fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, 'mediaThumbnail'), 'SPAN');
+                        const fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaThumbnail"), "SPAN");
                         this._replaceFileIcon(fileIcon, media, 144);
-                        file.className = 'jsClipboardObject mediaFile';
-                        elData(file, 'object-id', media.mediaID);
+                        file.className = "jsClipboardObject mediaFile";
+                        file.dataset.objectId = media.mediaID;
                         if (this._mediaManager) {
                             this._mediaManager.setupMediaElement(media, file);
                             this._mediaManager.addMedia(media, file);
                         }
                     }
                     else {
-                        var error = data.returnValues.errors[internalFileId];
+                        let error = data.returnValues.errors[internalFileId];
                         if (!error) {
                             error = {
-                                errorType: 'uploadFailed',
-                                filename: elData(file, 'filename')
+                                errorType: "uploadFailed",
+                                filename: file.dataset.filename,
                             };
                         }
-                        var fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, 'mediaThumbnail'), 'SPAN');
-                        fileIcon.classList.remove('fa-spinner');
-                        fileIcon.classList.add('fa-remove');
-                        fileIcon.classList.add('pointer');
-                        file.classList.add('uploadFailed');
-                        file.classList.add('jsTooltip');
-                        elAttr(file, 'title', Language.get('wcf.global.button.delete'));
-                        file.addEventListener('click', function () {
-                            elRemove(this);
-                        });
-                        var title = DomTraverse.childByClass(DomTraverse.childByClass(file, 'mediaInformation'), 'mediaTitle');
-                        title.innerText = Language.get('wcf.media.upload.error.' + error.errorType, {
-                            filename: error.filename
+                        const fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaThumbnail"), "SPAN");
+                        fileIcon.classList.remove("fa-spinner");
+                        fileIcon.classList.add("fa-remove");
+                        fileIcon.classList.add("pointer");
+                        file.classList.add("uploadFailed");
+                        file.classList.add("jsTooltip");
+                        file.title = Language.get("wcf.global.button.delete");
+                        file.addEventListener("click", () => file.remove());
+                        const title = DomTraverse.childByClass(DomTraverse.childByClass(file, "mediaInformation"), "mediaTitle");
+                        title.innerText = Language.get(`wcf.media.upload.error.${error.errorType}`, {
+                            filename: error.filename,
                         });
                     }
                 }
                 DomChangeListener.trigger();
-            }
-            EventHandler.fire('com.woltlab.wcf.media.upload', 'success', {
+            });
+            EventHandler.fire("com.woltlab.wcf.media.upload", "success", {
                 files: files,
                 isMultiFileUpload: this._multiFileUploadIds.indexOf(uploadId) !== -1,
                 media: data.returnValues.media,
                 upload: this,
-                uploadId: uploadId
+                uploadId: uploadId,
             });
-        },
-        /**
-         * @see        WoltLabSuite/Core/Upload#_uploadFiles
-         */
-        _uploadFiles: function (files, blob) {
-            return MediaUpload._super.prototype._uploadFiles.call(this, files, blob);
         }
-    });
-    return MediaUpload;
+    }
+    exports.MediaUpload = MediaUpload;
+    Core.enableLegacyInheritance(MediaUpload);
+    exports.default = MediaUpload;
 });
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.js
deleted file mode 100644 (file)
index ab31ba0..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/**
- * Uploads media files.
- * 
- * @author     Matthias Schmidt
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     WoltLabSuite/Core/Media/Upload
- */
-define(
-       [
-               'Core',
-               'DateUtil',
-               'Dom/ChangeListener',
-               'Dom/Traverse',
-               'Dom/Util',
-               'EventHandler',
-               'Language',
-               'Permission',
-               'Upload',
-               'User',
-               'WoltLabSuite/Core/FileUtil'
-       ],
-       function(
-               Core,
-               DateUtil,
-               DomChangeListener,
-               DomTraverse,
-               DomUtil,
-               EventHandler,
-               Language,
-               Permission,
-               Upload,
-               User,
-               FileUtil
-       )
-{
-       "use strict";
-       
-       if (!COMPILER_TARGET_DEFAULT) {
-               var Fake = function() {};
-               Fake.prototype = {
-                       _createFileElement: function() {},
-                       _getParameters: function() {},
-                       _success: function() {},
-                       _uploadFiles: function() {},
-                       _createButton: function() {},
-                       _createFileElements: function() {},
-                       _failure: function() {},
-                       _insertButton: function() {},
-                       _progress: function() {},
-                       _removeButton: function() {},
-                       _upload: function() {}
-               };
-               return Fake;
-       }
-       
-       /**
-        * @constructor
-        */
-       function MediaUpload(buttonContainerId, targetId, options) {
-               options = options || {};
-               
-               this._elementTagSize = 144;
-               if (options.elementTagSize) {
-                       this._elementTagSize = options.elementTagSize;
-               }
-               
-               this._mediaManager = null;
-               if (options.mediaManager) {
-                       this._mediaManager = options.mediaManager;
-                       delete options.mediaManager;
-               }
-               this._categoryId = null;
-               
-               Upload.call(this, buttonContainerId, targetId, Core.extend({
-                       className: 'wcf\\data\\media\\MediaAction',
-                       multiple: this._mediaManager ? true : false,
-                       singleFileRequests: true
-               }, options));
-       }
-       Core.inherit(MediaUpload, Upload, {
-               /**
-                * @see WoltLabSuite/Core/Upload#_createFileElement
-                */
-               _createFileElement: function(file) {
-                       var fileElement;
-                       if (this._target.nodeName === 'OL' || this._target.nodeName === 'UL') {
-                               fileElement = elCreate('li');
-                       }
-                       else if (this._target.nodeName === 'TBODY') {
-                               var firstTr = elByTag('TR', this._target)[0];
-                               var tableContainer = this._target.parentNode.parentNode;
-                               if (tableContainer.style.getPropertyValue('display') === 'none') {
-                                       fileElement = firstTr;
-                                       
-                                       tableContainer.style.removeProperty('display');
-                                       
-                                       elRemove(elById(elData(this._target, 'no-items-info')));
-                               }
-                               else {
-                                       fileElement = firstTr.cloneNode(true);
-                                       
-                                       // regenerate id of table row
-                                       fileElement.removeAttribute('id');
-                                       DomUtil.identify(fileElement);
-                               }
-                               
-                               var cells = elByTag('TD', fileElement), cell;
-                               for (var i = 0, length = cells.length; i < length; i++) {
-                                       cell = cells[i];
-                                       
-                                       if (cell.classList.contains('columnMark')) {
-                                               elBySelAll('[data-object-id]', cell, elHide);
-                                       }
-                                       else if (cell.classList.contains('columnIcon')) {
-                                               elBySelAll('[data-object-id]', cell, elHide);
-                                               
-                                               elByClass('mediaEditButton', cell)[0].classList.add('jsMediaEditButton');
-                                               elData(elByClass('jsDeleteButton', cell)[0], 'confirm-message-html', Language.get('wcf.media.delete.confirmMessage', {
-                                                       title: file.name
-                                               }));
-                                       }
-                                       else if (cell.classList.contains('columnFilename')) {
-                                               // replace copied image with spinner
-                                               var image = elByTag('IMG', cell);
-                                               
-                                               if (!image.length) {
-                                                       image = elByClass('icon48', cell);
-                                               }
-                                               
-                                               var spinner = elCreate('span');
-                                               spinner.className = 'icon icon48 fa-spinner mediaThumbnail';
-                                               
-                                               DomUtil.replaceElement(image[0], spinner);
-                                               
-                                               // replace title and uploading user
-                                               var ps = elBySelAll('.box48 > div > p', cell);
-                                               ps[0].textContent = file.name;
-                                               
-                                               var userLink = elByTag('A', ps[1])[0];
-                                               if (!userLink) {
-                                                       userLink = elCreate('a');
-                                                       elByTag('SMALL', ps[1])[0].appendChild(userLink);
-                                               }
-                                               
-                                               userLink.setAttribute('href', User.getLink());
-                                               userLink.textContent = User.username;
-                                       }
-                                       else if (cell.classList.contains('columnUploadTime')) {
-                                               cell.innerHTML = '';
-                                               cell.appendChild(DateUtil.getTimeElement(new Date()));
-                                       }
-                                       else if (cell.classList.contains('columnDigits')) {
-                                               cell.textContent = FileUtil.formatFilesize(file.size);
-                                       }
-                                       else {
-                                               // empty the other cells
-                                               cell.innerHTML = '';
-                                       }
-                               }
-                               
-                               DomUtil.prepend(fileElement, this._target);
-                               
-                               return fileElement;
-                       }
-                       else {
-                               fileElement = elCreate('p');
-                       }
-                       
-                       var thumbnail = elCreate('div');
-                       thumbnail.className = 'mediaThumbnail';
-                       fileElement.appendChild(thumbnail);
-                       
-                       var fileIcon = elCreate('span');
-                       fileIcon.className = 'icon icon144 fa-spinner';
-                       thumbnail.appendChild(fileIcon);
-                       
-                       var mediaInformation = elCreate('div');
-                       mediaInformation.className = 'mediaInformation';
-                       fileElement.appendChild(mediaInformation);
-                       
-                       var p = elCreate('p');
-                       p.className = 'mediaTitle';
-                       p.textContent = file.name;
-                       mediaInformation.appendChild(p);
-                       
-                       var progress = elCreate('progress');
-                       elAttr(progress, 'max', 100);
-                       mediaInformation.appendChild(progress);
-                       
-                       DomUtil.prepend(fileElement, this._target);
-                       
-                       DomChangeListener.trigger();
-                       
-                       return fileElement;
-               },
-               
-               /**
-                * @see WoltLabSuite/Core/Upload#_getParameters
-                */
-               _getParameters: function() {
-                       var parameters = {
-                               elementTagSize: this._elementTagSize
-                       };
-                       if (this._mediaManager) {
-                               parameters.imagesOnly = this._mediaManager.getOption('imagesOnly');
-                               
-                               var categoryId = this._mediaManager.getCategoryId();
-                               if (categoryId) {
-                                       parameters.categoryID = categoryId;
-                               }
-                       }
-                       
-                       return Core.extend(MediaUpload._super.prototype._getParameters.call(this), parameters);
-               },
-               
-               /**
-                * Replaces the default or copied file icon with the actual file icon.
-                * 
-                * @param       {HTMLElement}   fileIcon        file icon element
-                * @param       {object}        media           media data
-                * @param       {integer}       size            size of the file icon in pixels
-                */
-               _replaceFileIcon: function(fileIcon, media, size) {
-                       if (media.elementTag) {
-                               fileIcon.outerHTML = media.elementTag;
-                       }
-                       else if (media.tinyThumbnailType) {
-                               var img = elCreate('img');
-                               elAttr(img, 'src', media.tinyThumbnailLink);
-                               elAttr(img, 'alt', '');
-                               img.style.setProperty('width', size + 'px');
-                               img.style.setProperty('height', size + 'px');
-                               
-                               DomUtil.replaceElement(fileIcon, img);
-                       }
-                       else {
-                               fileIcon.classList.remove('fa-spinner');
-                               
-                               var fileIconName = FileUtil.getIconNameByFilename(media.filename);
-                               if (fileIconName) {
-                                       fileIconName = '-' + fileIconName;
-                               }
-                               fileIcon.classList.add('fa-file' + fileIconName + '-o');
-                       }
-               },
-               
-               /**
-                * @see WoltLabSuite/Core/Upload#_success
-                */
-               _success: function(uploadId, data) {
-                       var files = this._fileElements[uploadId];
-                       
-                       for (var i = 0, length = files.length; i < length; i++) {
-                               var file = files[i];
-                               var internalFileId = elData(file, 'internal-file-id');
-                               var media = data.returnValues.media[internalFileId];
-                               
-                               if (file.tagName === 'TR') {
-                                       if (media) {
-                                               // update object id
-                                               var objectIdElements = elBySelAll('[data-object-id]', file);
-                                               for (var i = 0, length = objectIdElements.length; i < length; i++) {
-                                                       elData(objectIdElements[i], 'object-id', ~~media.mediaID);
-                                                       elShow(objectIdElements[i]);
-                                               }
-                                               
-                                               elByClass('columnMediaID', file)[0].textContent = media.mediaID;
-                                               
-                                               // update icon
-                                               var fileIcon = elByClass('fa-spinner', file)[0];
-                                               this._replaceFileIcon(fileIcon, media, 48);
-                                       }
-                                       else {
-                                               var error = data.returnValues.errors[internalFileId];
-                                               if (!error) {
-                                                       error = {
-                                                               errorType: 'uploadFailed',
-                                                               filename: elData(file, 'filename')
-                                                       };
-                                               }
-                                               
-                                               var fileIcon = elByClass('fa-spinner', file)[0];
-                                               fileIcon.classList.remove('fa-spinner');
-                                               fileIcon.classList.add('fa-remove');
-                                               fileIcon.classList.add('pointer');
-                                               fileIcon.classList.add('jsTooltip');
-                                               elAttr(fileIcon, 'title', Language.get('wcf.global.button.delete'));
-                                               fileIcon.addEventListener('click', function (event) {
-                                                       elRemove(event.currentTarget.parentNode.parentNode.parentNode);
-                                                       
-                                                       EventHandler.fire('com.woltlab.wcf.media.upload', 'removedErroneousUploadRow');
-                                               });
-                                               
-                                               file.classList.add('uploadFailed');
-                                               
-                                               var p = elBySelAll('.columnFilename .box48 > div > p', file)[1];
-                                               
-                                               elInnerError(p, Language.get('wcf.media.upload.error.' + error.errorType, {
-                                                       filename: error.filename
-                                               }));
-                                               
-                                               elRemove(p);
-                                       }
-                               }
-                               else {
-                                       elRemove(DomTraverse.childByTag(DomTraverse.childByClass(file, 'mediaInformation'), 'PROGRESS'));
-                                       
-                                       if (media) {
-                                               var fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, 'mediaThumbnail'), 'SPAN');
-                                               this._replaceFileIcon(fileIcon, media, 144);
-                                               
-                                               file.className = 'jsClipboardObject mediaFile';
-                                               elData(file, 'object-id', media.mediaID);
-                                               
-                                               if (this._mediaManager) {
-                                                       this._mediaManager.setupMediaElement(media, file);
-                                                       this._mediaManager.addMedia(media, file);
-                                               }
-                                       }
-                                       else {
-                                               var error = data.returnValues.errors[internalFileId];
-                                               if (!error) {
-                                                       error = {
-                                                               errorType: 'uploadFailed',
-                                                               filename: elData(file, 'filename')
-                                                       };
-                                               }
-                                               
-                                               var fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, 'mediaThumbnail'), 'SPAN');
-                                               fileIcon.classList.remove('fa-spinner');
-                                               fileIcon.classList.add('fa-remove');
-                                               fileIcon.classList.add('pointer');
-                                               
-                                               file.classList.add('uploadFailed');
-                                               file.classList.add('jsTooltip');
-                                               elAttr(file, 'title', Language.get('wcf.global.button.delete'));
-                                               file.addEventListener('click', function () {
-                                                       elRemove(this);
-                                               });
-                                               
-                                               var title = DomTraverse.childByClass(DomTraverse.childByClass(file, 'mediaInformation'), 'mediaTitle');
-                                               title.innerText = Language.get('wcf.media.upload.error.' + error.errorType, {
-                                                       filename: error.filename
-                                               });
-                                       }
-                               }
-                               
-                               DomChangeListener.trigger();
-                       }
-                       
-                       EventHandler.fire('com.woltlab.wcf.media.upload', 'success', {
-                               files: files,
-                               isMultiFileUpload: this._multiFileUploadIds.indexOf(uploadId) !== -1,
-                               media: data.returnValues.media,
-                               upload: this,
-                               uploadId: uploadId
-                       });
-               },
-               
-               /**
-                * @see WoltLabSuite/Core/Upload#_uploadFiles
-                */
-               _uploadFiles: function(files, blob) {
-                       return MediaUpload._super.prototype._uploadFiles.call(this, files, blob);
-               }
-       });
-       
-       return MediaUpload;
-});
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.ts
new file mode 100644 (file)
index 0000000..0eac346
--- /dev/null
@@ -0,0 +1,315 @@
+/**
+ * Uploads media files.
+ *
+ * @author  Matthias Schmidt
+ * @copyright 2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Media/Upload
+ */
+
+import Upload from "../Upload";
+import * as Core from "../Core";
+import * as DomUtil from "../Dom/Util";
+import * as DomTraverse from "../Dom/Traverse";
+import * as Language from "../Language";
+import User from "../User";
+import * as DateUtil from "../Date/Util";
+import * as FileUtil from "../FileUtil";
+import * as DomChangeListener from "../Dom/Change/Listener";
+import {
+  Media,
+  MediaUploadOptions,
+  MediaUploadSuccessEventData,
+  MediaUploadError,
+  MediaUploadAjaxResponseData,
+} from "./Data";
+import * as EventHandler from "../Event/Handler";
+import MediaManager from "./Manager/Base";
+
+export class MediaUpload<TOptions extends MediaUploadOptions = MediaUploadOptions> extends Upload<TOptions> {
+  protected _categoryId: number | null = null;
+  protected readonly _elementTagSize: number;
+  protected readonly _mediaManager: MediaManager | null;
+
+  constructor(buttonContainerId: string, targetId: string, options: Partial<TOptions>) {
+    super(
+      buttonContainerId,
+      targetId,
+      Core.extend(
+        {
+          className: "wcf\\data\\media\\MediaAction",
+          multiple: options.mediaManager ? true : false,
+          singleFileRequests: true,
+        },
+        options || {},
+      ),
+    );
+
+    options = options || {};
+
+    this._elementTagSize = 144;
+    if (this._options.elementTagSize) {
+      this._elementTagSize = this._options.elementTagSize;
+    }
+
+    this._mediaManager = null;
+    if (this._options.mediaManager) {
+      this._mediaManager = this._options.mediaManager;
+      delete this._options.mediaManager;
+    }
+  }
+
+  protected _createFileElement(file: File): HTMLElement {
+    let fileElement: HTMLElement;
+    if (this._target.nodeName === "OL" || this._target.nodeName === "UL") {
+      fileElement = document.createElement("li");
+    } else if (this._target.nodeName === "TBODY") {
+      const firstTr = this._target.getElementsByTagName("TR")[0] as HTMLTableRowElement;
+      const tableContainer = this._target.parentNode!.parentNode! as HTMLElement;
+      if (tableContainer.style.getPropertyValue("display") === "none") {
+        fileElement = firstTr;
+
+        tableContainer.style.removeProperty("display");
+
+        document.getElementById(this._target.dataset.noItemsInfo!)!.remove();
+      } else {
+        fileElement = firstTr.cloneNode(true) as HTMLTableRowElement;
+
+        // regenerate id of table row
+        fileElement.removeAttribute("id");
+        DomUtil.identify(fileElement);
+      }
+
+      Array.from(fileElement.getElementsByTagName("TD")).forEach((cell: HTMLTableDataCellElement) => {
+        if (cell.classList.contains("columnMark")) {
+          cell.querySelectorAll("[data-object-id]").forEach((el: HTMLElement) => (el.style.display = "none"));
+        } else if (cell.classList.contains("columnIcon")) {
+          cell.querySelectorAll("[data-object-id]").forEach((el: HTMLElement) => (el.style.display = "none"));
+
+          cell.querySelector(".mediaEditButton")!.classList.add("jsMediaEditButton");
+          (cell.querySelector(".jsDeleteButton") as HTMLElement).dataset.confirmMessageHtml = Language.get(
+            "wcf.media.delete.confirmMessage",
+            {
+              title: file.name,
+            },
+          );
+        } else if (cell.classList.contains("columnFilename")) {
+          // replace copied image with spinner
+          let image = cell.querySelector("img");
+          if (!image) {
+            image = cell.querySelector(".icon48");
+          }
+
+          const spinner = document.createElement("span");
+          spinner.className = "icon icon48 fa-spinner mediaThumbnail";
+
+          DomUtil.replaceElement(image!, spinner);
+
+          // replace title and uploading user
+          const ps = cell.querySelectorAll(".box48 > div > p");
+          ps[0].textContent = file.name;
+
+          let userLink = ps[1].getElementsByTagName("A")[0];
+          if (!userLink) {
+            userLink = document.createElement("a");
+            ps[1].getElementsByTagName("SMALL")[0].appendChild(userLink);
+          }
+
+          userLink.setAttribute("href", User.getLink());
+          userLink.textContent = User.username;
+        } else if (cell.classList.contains("columnUploadTime")) {
+          cell.innerHTML = "";
+          cell.appendChild(DateUtil.getTimeElement(new Date()));
+        } else if (cell.classList.contains("columnDigits")) {
+          cell.textContent = FileUtil.formatFilesize(file.size);
+        } else {
+          // empty the other cells
+          cell.innerHTML = "";
+        }
+      });
+
+      DomUtil.prepend(fileElement, this._target);
+
+      return fileElement;
+    } else {
+      fileElement = document.createElement("p");
+    }
+
+    const thumbnail = document.createElement("div");
+    thumbnail.className = "mediaThumbnail";
+    fileElement.appendChild(thumbnail);
+
+    const fileIcon = document.createElement("span");
+    fileIcon.className = "icon icon144 fa-spinner";
+    thumbnail.appendChild(fileIcon);
+
+    const mediaInformation = document.createElement("div");
+    mediaInformation.className = "mediaInformation";
+    fileElement.appendChild(mediaInformation);
+
+    const p = document.createElement("p");
+    p.className = "mediaTitle";
+    p.textContent = file.name;
+    mediaInformation.appendChild(p);
+
+    const progress = document.createElement("progress");
+    progress.max = 100;
+    mediaInformation.appendChild(progress);
+
+    DomUtil.prepend(fileElement, this._target);
+
+    DomChangeListener.trigger();
+
+    return fileElement;
+  }
+
+  protected _getParameters(): ArbitraryObject {
+    const parameters: ArbitraryObject = {
+      elementTagSize: this._elementTagSize,
+    };
+    if (this._mediaManager) {
+      parameters.imagesOnly = this._mediaManager.getOption("imagesOnly");
+
+      const categoryId = this._mediaManager.getCategoryId();
+      if (categoryId) {
+        parameters.categoryID = categoryId;
+      }
+    }
+
+    return Core.extend(super._getParameters() as object, parameters as object) as ArbitraryObject;
+  }
+
+  protected _replaceFileIcon(fileIcon: HTMLElement, media: Media, size: number): void {
+    if (media.elementTag) {
+      fileIcon.outerHTML = media.elementTag;
+    } else if (media.tinyThumbnailType) {
+      const img = document.createElement("img");
+      img.src = media.tinyThumbnailLink;
+      img.alt = "";
+      img.style.setProperty("width", `${size}px`);
+      img.style.setProperty("height", `${size}px`);
+
+      DomUtil.replaceElement(fileIcon, img);
+    } else {
+      fileIcon.classList.remove("fa-spinner");
+
+      let fileIconName = FileUtil.getIconNameByFilename(media.filename);
+      if (fileIconName) {
+        fileIconName = "-" + fileIconName;
+      }
+      fileIcon.classList.add(`fa-file${fileIconName}-o`);
+    }
+  }
+
+  protected _success(uploadId: number, data: MediaUploadAjaxResponseData): void {
+    const files = this._fileElements[uploadId];
+    files.forEach((file) => {
+      const internalFileId = file.dataset.internalFileId!;
+      const media: Media = data.returnValues.media[internalFileId];
+
+      if (file.tagName === "TR") {
+        if (media) {
+          // update object id
+          file.querySelectorAll("[data-object-id]").forEach((el: HTMLElement) => {
+            el.dataset.objectId = (media.mediaID as unknown) as string;
+            el.style.removeProperty("display");
+          });
+
+          file.querySelector(".columnMediaID")!.textContent = (media.mediaID as unknown) as string;
+
+          // update icon
+          this._replaceFileIcon(file.querySelector(".fa-spinner") as HTMLSpanElement, media, 48);
+        } else {
+          let error: MediaUploadError = data.returnValues.errors[internalFileId];
+          if (!error) {
+            error = {
+              errorType: "uploadFailed",
+              filename: file.dataset.filename!,
+            };
+          }
+
+          const fileIcon = file.querySelector(".fa-spinner") as HTMLSpanElement;
+          fileIcon.classList.remove("fa-spinner");
+          fileIcon.classList.add("fa-remove");
+          fileIcon.classList.add("pointer");
+          fileIcon.classList.add("jsTooltip");
+          fileIcon.title = Language.get("wcf.global.button.delete");
+          fileIcon.addEventListener("click", (event) => {
+            const target = event.currentTarget as HTMLSpanElement;
+            (target.parentNode!.parentNode!.parentNode! as HTMLElement).remove();
+
+            EventHandler.fire("com.woltlab.wcf.media.upload", "removedErroneousUploadRow");
+          });
+
+          file.classList.add("uploadFailed");
+
+          const p = file.querySelectorAll(".columnFilename .box48 > div > p")[1] as HTMLElement;
+
+          DomUtil.innerError(
+            p,
+            Language.get(`wcf.media.upload.error.${error.errorType}`, {
+              filename: error.filename,
+            }),
+          );
+
+          p.remove();
+        }
+      } else {
+        DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaInformation")!, "PROGRESS")!.remove();
+
+        if (media) {
+          const fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaThumbnail")!, "SPAN")!;
+          this._replaceFileIcon(fileIcon, media, 144);
+
+          file.className = "jsClipboardObject mediaFile";
+          file.dataset.objectId = (media.mediaID as unknown) as string;
+
+          if (this._mediaManager) {
+            this._mediaManager.setupMediaElement(media, file);
+            this._mediaManager.addMedia(media, file as HTMLLIElement);
+          }
+        } else {
+          let error: MediaUploadError = data.returnValues.errors[internalFileId];
+          if (!error) {
+            error = {
+              errorType: "uploadFailed",
+              filename: file.dataset.filename!,
+            };
+          }
+
+          const fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaThumbnail")!, "SPAN")!;
+          fileIcon.classList.remove("fa-spinner");
+          fileIcon.classList.add("fa-remove");
+          fileIcon.classList.add("pointer");
+
+          file.classList.add("uploadFailed");
+          file.classList.add("jsTooltip");
+          file.title = Language.get("wcf.global.button.delete");
+          file.addEventListener("click", () => file.remove());
+
+          const title = DomTraverse.childByClass(
+            DomTraverse.childByClass(file, "mediaInformation")!,
+            "mediaTitle",
+          ) as HTMLElement;
+          title.innerText = Language.get(`wcf.media.upload.error.${error.errorType}`, {
+            filename: error.filename,
+          });
+        }
+      }
+
+      DomChangeListener.trigger();
+    });
+
+    EventHandler.fire("com.woltlab.wcf.media.upload", "success", {
+      files: files,
+      isMultiFileUpload: this._multiFileUploadIds.indexOf(uploadId) !== -1,
+      media: data.returnValues.media,
+      upload: this,
+      uploadId: uploadId,
+    } as MediaUploadSuccessEventData);
+  }
+}
+
+Core.enableLegacyInheritance(MediaUpload);
+
+export default MediaUpload;