From d71e839184acbbf165c424266ca0ebd6c6c8339c Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Tue, 5 Jan 2021 18:40:16 +0100 Subject: [PATCH] Convert `Media/Upload` to TypeScript --- .../js/WoltLabSuite/Core/Media/Upload.js | 362 ++++++++--------- .../ts/WoltLabSuite/Core/Media/Upload.js | 370 ------------------ .../ts/WoltLabSuite/Core/Media/Upload.ts | 315 +++++++++++++++ 3 files changed, 473 insertions(+), 574 deletions(-) delete mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.js create mode 100644 wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.ts diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Upload.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Upload.js index 86c4abdc41..45a280069d 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Upload.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Upload.js @@ -1,301 +1,255 @@ /** * Uploads media files. * - * @author Matthias Schmidt - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module WoltLabSuite/Core/Media/Upload + * @author Matthias Schmidt + * @copyright 2001-2021 WoltLab GmbH + * @license GNU Lesser General Public License + * @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 index ab31ba09e6..0000000000 --- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.js +++ /dev/null @@ -1,370 +0,0 @@ -/** - * Uploads media files. - * - * @author Matthias Schmidt - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @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 index 0000000000..0eac346529 --- /dev/null +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Upload.ts @@ -0,0 +1,315 @@ +/** + * Uploads media files. + * + * @author Matthias Schmidt + * @copyright 2001-2021 WoltLab GmbH + * @license GNU Lesser General Public License + * @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 extends Upload { + protected _categoryId: number | null = null; + protected readonly _elementTagSize: number; + protected readonly _mediaManager: MediaManager | null; + + constructor(buttonContainerId: string, targetId: string, options: Partial) { + 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; -- 2.20.1