From: Matthias Schmidt Date: Tue, 5 Jan 2021 17:43:08 +0000 (+0100) Subject: Convert `Media/Manager/Base` to TypeScript X-Git-Tag: 5.4.0_Alpha_1~461^2~9 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=0611150d337a93c437e0e187a9f1b5b01ce60968;p=GitHub%2FWoltLab%2FWCF.git Convert `Media/Manager/Base` to TypeScript --- diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Manager/Base.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Manager/Base.js index 94be76efbb..5e7e6dc359 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Manager/Base.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Media/Manager/Base.js @@ -1,244 +1,206 @@ /** * Provides the media manager dialog. * - * @author Matthias Schmidt - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module WoltLabSuite/Core/Media/Manager/Base + * @author Matthias Schmidt + * @copyright 2001-2020 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Media/Manager/Base */ -define([ - 'Core', 'Dictionary', 'Dom/ChangeListener', 'Dom/Traverse', - 'Dom/Util', 'EventHandler', 'Language', 'List', - 'Permission', 'Ui/Dialog', 'Ui/Notification', 'WoltLabSuite/Core/Controller/Clipboard', - 'WoltLabSuite/Core/Media/Editor', 'WoltLabSuite/Core/Media/Upload', 'WoltLabSuite/Core/Media/Manager/Search', 'StringUtil', - 'WoltLabSuite/Core/Ui/Pagination', - 'WoltLabSuite/Core/Media/Clipboard' -], function (Core, Dictionary, DomChangeListener, DomTraverse, DomUtil, EventHandler, Language, List, Permission, UiDialog, UiNotification, Clipboard, MediaEditor, MediaUpload, MediaManagerSearch, StringUtil, UiPagination, MediaClipboard) { +define(["require", "exports", "tslib", "../../Core", "../../Language", "../../Permission", "../../Dom/Change/Listener", "../../Event/Handler", "../../Dom/Traverse", "../../Dom/Util", "../../Ui/Dialog", "../../Controller/Clipboard", "../../Ui/Pagination", "../../Ui/Notification", "../../StringUtil", "./Search", "../Upload", "../Editor", "../Clipboard"], function (require, exports, tslib_1, Core, Language, Permission, DomChangeListener, EventHandler, DomTraverse, DomUtil, UiDialog, Clipboard, Pagination_1, UiNotification, StringUtil, Search_1, Upload_1, Editor_1, MediaClipboard) { "use strict"; - if (!COMPILER_TARGET_DEFAULT) { - var Fake = function () { }; - Fake.prototype = { - _addButtonEventListeners: function () { }, - _click: function () { }, - _dialogClose: function () { }, - _dialogInit: function () { }, - _dialogSetup: function () { }, - _dialogShow: function () { }, - _editMedia: function () { }, - _editorClose: function () { }, - _editorSuccess: function () { }, - _removeClipboardCheckboxes: function () { }, - _setMedia: function () { }, - addMedia: function () { }, - clipboardDeleteMedia: function () { }, - getDialog: function () { }, - getMode: function () { }, - getOption: function () { }, - removeMedia: function () { }, - resetMedia: function () { }, - setMedia: function () { }, - setupMediaElement: function () { } - }; - return Fake; - } - var _mediaManagerCounter = 0; - /** - * @constructor - */ - function MediaManagerBase(options) { - this._options = Core.extend({ - dialogTitle: Language.get('wcf.media.manager'), - imagesOnly: false, - minSearchLength: 3 - }, options); - this._id = 'mediaManager' + _mediaManagerCounter++; - this._listItems = new Dictionary(); - this._media = new Dictionary(); - this._mediaManagerMediaList = null; - this._search = null; - this._upload = null; - this._forceClipboard = false; - this._hadInitiallyMarkedItems = false; - this._pagination = null; - if (Permission.get('admin.content.cms.canManageMedia')) { - this._mediaEditor = new MediaEditor(this); + Core = tslib_1.__importStar(Core); + Language = tslib_1.__importStar(Language); + Permission = tslib_1.__importStar(Permission); + DomChangeListener = tslib_1.__importStar(DomChangeListener); + EventHandler = tslib_1.__importStar(EventHandler); + DomTraverse = tslib_1.__importStar(DomTraverse); + DomUtil = tslib_1.__importStar(DomUtil); + UiDialog = tslib_1.__importStar(UiDialog); + Clipboard = tslib_1.__importStar(Clipboard); + Pagination_1 = tslib_1.__importDefault(Pagination_1); + UiNotification = tslib_1.__importStar(UiNotification); + StringUtil = tslib_1.__importStar(StringUtil); + Search_1 = tslib_1.__importDefault(Search_1); + Upload_1 = tslib_1.__importDefault(Upload_1); + Editor_1 = tslib_1.__importDefault(Editor_1); + MediaClipboard = tslib_1.__importStar(MediaClipboard); + let mediaManagerCounter = 0; + class MediaManager { + constructor(options) { + this._forceClipboard = false; + this._hadInitiallyMarkedItems = false; + this._id = `mediaManager${mediaManagerCounter++}`; + this._listItems = new Map(); + this._media = new Map(); + this._mediaEditor = null; + this._mediaManagerMediaList = null; + this._pagination = null; + this._search = null; + this._upload = null; + this._options = Core.extend({ + dialogTitle: Language.get("wcf.media.manager"), + imagesOnly: false, + minSearchLength: 3, + }, options); + if (Permission.get("admin.content.cms.canManageMedia")) { + this._mediaEditor = new Editor_1.default(this); + } + DomChangeListener.add("WoltLabSuite/Core/Media/Manager", () => this._addButtonEventListeners()); + EventHandler.add("com.woltlab.wcf.media.upload", "success", (data) => this._openEditorAfterUpload(data)); } - DomChangeListener.add('WoltLabSuite/Core/Media/Manager', this._addButtonEventListeners.bind(this)); - EventHandler.add('com.woltlab.wcf.media.upload', 'success', this._openEditorAfterUpload.bind(this)); - } - MediaManagerBase.prototype = { /** * Adds click event listeners to media buttons. */ - _addButtonEventListeners: function () { - if (!this._mediaManagerMediaList) + _addButtonEventListeners() { + if (!this._mediaManagerMediaList || !Permission.get("admin.content.cms.canManageMedia")) return; - var listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI'); - for (var i = 0, length = listItems.length; i < length; i++) { - var listItem = listItems[i]; - if (Permission.get('admin.content.cms.canManageMedia')) { - var editIcon = elByClass('jsMediaEditButton', listItem)[0]; - if (editIcon) { - editIcon.classList.remove('jsMediaEditButton'); - editIcon.addEventListener('click', this._editMedia.bind(this)); - } + DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => { + const editIcon = listItem.querySelector(".jsMediaEditButton"); + if (editIcon) { + editIcon.classList.remove("jsMediaEditButton"); + editIcon.addEventListener("click", (ev) => this._editMedia(ev)); } - } - }, + }); + } /** * Is called when a new category is selected. */ - _categoryChange: function () { + _categoryChange() { this._search.search(); - }, + } /** * Handles clicks on the media manager button. - * - * @param {object} event event object */ - _click: function (event) { + _click(event) { event.preventDefault(); UiDialog.open(this); - }, + } /** * Is called if the media manager dialog is closed. */ - _dialogClose: function () { + _dialogClose() { // only show media clipboard if editor is open - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { - Clipboard.hideEditor('com.woltlab.wcf.media'); + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { + Clipboard.hideEditor("com.woltlab.wcf.media"); } - }, + } /** * Initializes the dialog when first loaded. - * - * @param {string} content dialog content - * @param {object} data AJAX request's response data */ - _dialogInit: function (content, data) { + _dialogInit(content, data) { // store media data locally - var media = data.returnValues.media || {}; - for (var mediaId in media) { - if (objOwns(media, mediaId)) { - this._media.set(~~mediaId, media[mediaId]); - } - } + Object.entries(data.returnValues.media || {}).forEach(([mediaId, media]) => { + this._media.set(~~mediaId, media); + }); this._initPagination(~~data.returnValues.pageCount); - this._hadInitiallyMarkedItems = data.returnValues.hasMarkedItems; - }, + this._hadInitiallyMarkedItems = data.returnValues.hasMarkedItems > 0; + } /** * Returns all data to setup the media manager dialog. - * - * @return {object} dialog setup data */ - _dialogSetup: function () { + _dialogSetup() { return { id: this._id, options: { - onClose: this._dialogClose.bind(this), - onShow: this._dialogShow.bind(this), - title: this._options.dialogTitle + onClose: () => this._dialogClose(), + onShow: () => this._dialogShow(), + title: this._options.dialogTitle, }, source: { - after: this._dialogInit.bind(this), + after: (content, data) => this._dialogInit(content, data), data: { - actionName: 'getManagementDialog', - className: 'wcf\\data\\media\\MediaAction', + actionName: "getManagementDialog", + className: "wcf\\data\\media\\MediaAction", parameters: { mode: this.getMode(), - imagesOnly: this._options.imagesOnly - } - } - } + imagesOnly: this._options.imagesOnly, + }, + }, + }, }; - }, + } /** * Is called if the media manager dialog is shown. */ - _dialogShow: function () { + _dialogShow() { if (!this._mediaManagerMediaList) { - var dialog = this.getDialog(); - this._mediaManagerMediaList = elByClass('mediaManagerMediaList', dialog)[0]; - this._mediaCategorySelect = elBySel('.mediaManagerCategoryList > select', dialog); + const dialog = this.getDialog(); + this._mediaManagerMediaList = dialog.querySelector(".mediaManagerMediaList"); + this._mediaCategorySelect = dialog.querySelector(".mediaManagerCategoryList > select"); if (this._mediaCategorySelect) { - this._mediaCategorySelect.addEventListener('change', this._categoryChange.bind(this)); + this._mediaCategorySelect.addEventListener("change", this._categoryChange.bind(this)); } // store list items locally - var listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI'); - for (var i = 0, length = listItems.length; i < length; i++) { - var listItem = listItems[i]; - this._listItems.set(~~elData(listItem, 'object-id'), listItem); - } - if (Permission.get('admin.content.cms.canManageMedia')) { - var uploadButton = elByClass('mediaManagerMediaUploadButton', UiDialog.getDialog(this).dialog)[0]; - this._upload = new MediaUpload(DomUtil.identify(uploadButton), DomUtil.identify(this._mediaManagerMediaList), { - mediaManager: this + const listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI"); + listItems.forEach((listItem) => { + this._listItems.set(~~listItem.dataset.objectId, listItem); + }); + if (Permission.get("admin.content.cms.canManageMedia")) { + const uploadButton = UiDialog.getDialog(this).dialog.querySelector(".mediaManagerMediaUploadButton"); + this._upload = new Upload_1.default(DomUtil.identify(uploadButton), DomUtil.identify(this._mediaManagerMediaList), { + mediaManager: this, }); - var deleteAction = new WCF.Action.Delete('wcf\\data\\media\\MediaAction', '.mediaFile'); - deleteAction._didTriggerEffect = function (element) { - this.removeMedia(elData(element[0], 'object-id')); - }.bind(this); + // eslint-disable-next-line + //@ts-ignore + const deleteAction = new WCF.Action.Delete("wcf\\data\\media\\MediaAction", ".mediaFile"); + deleteAction._didTriggerEffect = (element) => this.removeMedia(element[0].dataset.objectId); } - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { - MediaClipboard.init('menuManagerDialog-' + this.getMode(), this._hadInitiallyMarkedItems ? true : false, this); + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { + MediaClipboard.init("menuManagerDialog-" + this.getMode(), this._hadInitiallyMarkedItems ? true : false, this); } else { this._removeClipboardCheckboxes(); } - this._search = new MediaManagerSearch(this); + this._search = new Search_1.default(this); if (!listItems.length) { this._search.hideSearch(); } } // only show media clipboard if editor is open - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { - Clipboard.showEditor('com.woltlab.wcf.media'); + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { + Clipboard.showEditor(); } - }, + } /** * Opens the media editor for a media file. - * - * @param {Event} event event object for clicks on edit icons */ - _editMedia: function (event) { - if (!Permission.get('admin.content.cms.canManageMedia')) { + _editMedia(event) { + if (!Permission.get("admin.content.cms.canManageMedia")) { throw new Error("You are not allowed to edit media files."); } UiDialog.close(this); - this._mediaEditor.edit(this._media.get(~~elData(event.currentTarget, 'object-id'))); - }, + const target = event.currentTarget; + this._mediaEditor.edit(this._media.get(~~target.dataset.objectId)); + } /** * Re-opens the manager dialog after closing the editor dialog. */ - _editorClose: function () { + _editorClose() { UiDialog.open(this); - }, + } /** - * Re-opens the manager dialog and updates the media data after - * successfully editing a media file. - * - * @param {object} media updated media file data - * @param {integer} oldCategoryId old category id + * Re-opens the manager dialog and updates the media data after successfully editing a media file. */ - _editorSuccess: function (media, oldCategoryId) { + _editorSuccess(media, oldCategoryId) { // if the category changed of media changed and category // is selected, check if media list needs to be refreshed if (this._mediaCategorySelect) { - var selectedCategoryId = ~~this._mediaCategorySelect.value; + const selectedCategoryId = ~~this._mediaCategorySelect.value; if (selectedCategoryId) { - var newCategoryId = ~~media.categoryID; - if (oldCategoryId != newCategoryId && (oldCategoryId == selectedCategoryId || newCategoryId == selectedCategoryId)) { + const newCategoryId = ~~media.categoryID; + if (oldCategoryId != newCategoryId && + (oldCategoryId == selectedCategoryId || newCategoryId == selectedCategoryId)) { this._search.search(); } } } UiDialog.open(this); this._media.set(~~media.mediaID, media); - var listItem = this._listItems.get(~~media.mediaID); - var p = elByClass('mediaTitle', listItem)[0]; + const listItem = this._listItems.get(~~media.mediaID); + const p = listItem.querySelector(".mediaTitle"); if (media.isMultilingual) { - if (media.title && media.title[LANGUAGE_ID]) { - p.textContent = media.title[LANGUAGE_ID]; + if (media.title && media.title[window.LANGUAGE_ID]) { + p.textContent = media.title[window.LANGUAGE_ID]; } else { p.textContent = media.filename; @@ -252,113 +214,97 @@ define([ p.textContent = media.filename; } } - var thumbnail = elByClass('mediaThumbnail', listItem)[0]; + const thumbnail = listItem.querySelector(".mediaThumbnail"); thumbnail.innerHTML = media.elementTag; // Bust browser cache by adding additional parameter. - var imgs = elByTag('img', thumbnail); - if (imgs.length) { - imgs[0].src += '&refresh=' + Date.now(); + const img = thumbnail.querySelector("img"); + if (img) { + img.src += `&refresh=${Date.now()}`; } - }, + } /** * Initializes the dialog pagination. - * - * @param {integer} pageCount - * @param {integer} pageNo */ - _initPagination: function (pageCount, pageNo) { + _initPagination(pageCount, pageNo) { if (pageNo === undefined) pageNo = 1; if (pageCount > 1) { - var newPagination = elCreate('div'); - newPagination.className = 'paginationBottom jsPagination'; - DomUtil.replaceElement(elBySel('.jsPagination', UiDialog.getDialog(this).content), newPagination); - this._pagination = new UiPagination(newPagination, { + const newPagination = document.createElement("div"); + newPagination.className = "paginationBottom jsPagination"; + DomUtil.replaceElement(UiDialog.getDialog(this).content.querySelector(".jsPagination"), newPagination); + this._pagination = new Pagination_1.default(newPagination, { activePage: pageNo, callbackSwitch: this._search.search.bind(this._search), - maxPage: pageCount + maxPage: pageCount, }); } else if (this._pagination) { - elHide(this._pagination.getElement()); + this._pagination.getElement().style.display = "none"; } - }, + } /** * Removes all media clipboard checkboxes. */ - _removeClipboardCheckboxes: function () { - var checkboxes = elByClass('mediaCheckbox', this._mediaManagerMediaList); - while (checkboxes.length) { - elRemove(checkboxes[0]); - } - }, + _removeClipboardCheckboxes() { + this._mediaManagerMediaList.querySelectorAll(".mediaCheckbox").forEach((el) => el.remove()); + } /** * Opens the media editor after uploading a single file. * - * @param {object} data upload event data - * @since 5.2 + * @since 5.2 */ - _openEditorAfterUpload: function (data) { + _openEditorAfterUpload(data) { if (data.upload === this._upload && !data.isMultiFileUpload && !this._upload.hasPendingUploads()) { - var keys = Object.keys(data.media); + const keys = Object.keys(data.media); if (keys.length) { UiDialog.close(this); this._mediaEditor.edit(this._media.get(~~data.media[keys[0]].mediaID)); } } - }, + } /** * Sets the displayed media (after a search). - * - * @param {Dictionary} media media to be set as active */ - _setMedia: function (media) { - if (Core.isPlainObject(media)) { - this._media = Dictionary.fromObject(media); - } - else { - this._media = media; - } - var info = DomTraverse.nextByClass(this._mediaManagerMediaList, 'info'); + _setMedia(media) { + this._media = new Map(); + Object.entries(media).forEach(([mediaId, media]) => { + this._media.set(~~mediaId, media); + }); + let info = DomTraverse.nextByClass(this._mediaManagerMediaList, "info"); if (this._media.size) { if (info) { - elHide(info); + info.style.display = "none"; } } else { if (info === null) { - info = elCreate('p'); - info.className = 'info'; - info.textContent = Language.get('wcf.media.search.noResults'); + info = document.createElement("p"); + info.className = "info"; + info.textContent = Language.get("wcf.media.search.noResults"); } - elShow(info); + info.style.display = "block"; DomUtil.insertAfter(info, this._mediaManagerMediaList); } - var mediaListItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI'); - for (var i = 0, length = mediaListItems.length; i < length; i++) { - var listItem = mediaListItems[i]; - if (!this._media.has(elData(listItem, 'object-id'))) { - elHide(listItem); + DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => { + if (!this._media.has(~~listItem.dataset.objectId)) { + listItem.style.display = "none"; } else { - elShow(listItem); + listItem.style.display = "block"; } - } + }); DomChangeListener.trigger(); - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { Clipboard.reload(); } else { this._removeClipboardCheckboxes(); } - }, + } /** * Adds a media file to the manager. - * - * @param {object} media data of the media file - * @param {Element} listItem list item representing the file */ - addMedia: function (media, listItem) { + addMedia(media, listItem) { if (!media.languageID) media.isMultilingual = 1; this._media.set(~~media.mediaID, media); @@ -366,67 +312,54 @@ define([ if (this._listItems.size === 1) { this._search.showSearch(); } - }, + } /** * Is called after the media files with the given ids have been deleted via clipboard. - * - * @param {int[]} mediaIds ids of deleted media files */ - clipboardDeleteMedia: function (mediaIds) { - for (var i = 0, length = mediaIds.length; i < length; i++) { - this.removeMedia(~~mediaIds[i], true); - } + clipboardDeleteMedia(mediaIds) { + mediaIds.forEach((mediaId) => { + this.removeMedia(~~mediaId); + }); UiNotification.show(); - }, + } /** * Returns the id of the currently selected category or `0` if no category is selected. - * - * @return {integer} */ - getCategoryId: function () { + getCategoryId() { if (this._mediaCategorySelect) { - return this._mediaCategorySelect.value; + return ~~this._mediaCategorySelect.value; } return 0; - }, + } /** * Returns the media manager dialog element. - * - * @return {Element} media manager dialog */ - getDialog: function () { + getDialog() { return UiDialog.getDialog(this).dialog; - }, + } /** * Returns the mode of the media manager. - * - * @return {string} */ - getMode: function () { - return ''; - }, + getMode() { + return ""; + } /** * Returns the media manager option with the given name. - * - * @param {string} name option name - * @return {mixed} option value or null */ - getOption: function (name) { + getOption(name) { if (this._options[name]) { return this._options[name]; } return null; - }, + } /** * Removes a media file. - * - * @param {int} mediaId id of the removed media file */ - removeMedia: function (mediaId) { + removeMedia(mediaId) { if (this._listItems.has(mediaId)) { // remove list item try { - elRemove(this._listItems.get(mediaId)); + this._listItems.get(mediaId).remove(); } catch (e) { // ignore errors if item has already been removed like by WCF.Action.Delete @@ -434,88 +367,82 @@ define([ this._listItems.delete(mediaId); this._media.delete(mediaId); } - }, + } /** * Changes the displayed media to the previously displayed media. */ - resetMedia: function () { + resetMedia() { // calling WoltLabSuite/Core/Media/Manager/Search.search() reloads the first page of the dialog this._search.search(); - }, + } /** * Sets the media files currently displayed. - * - * @param {object} media media data - * @param {string} template - * @param {object} additionalData */ - setMedia: function (media, template, additionalData) { - var hasMedia = false; - for (var mediaId in media) { - if (objOwns(media, mediaId)) { - hasMedia = true; - } - } - var newListItems = []; + setMedia(media, template, additionalData) { + const hasMedia = Object.entries(media).length > 0; if (hasMedia) { - var ul = elCreate('ul'); + const ul = document.createElement("ul"); ul.innerHTML = template; - var listItems = DomTraverse.childrenByTag(ul, 'LI'); - for (var i = 0, length = listItems.length; i < length; i++) { - var listItem = listItems[i]; - if (!this._listItems.has(~~elData(listItem, 'object-id'))) { - this._listItems.set(elData(listItem, 'object-id'), listItem); + DomTraverse.childrenByTag(ul, "LI").forEach((listItem) => { + if (!this._listItems.has(~~listItem.dataset.objectId)) { + this._listItems.set(~~listItem.dataset.objectId, listItem); this._mediaManagerMediaList.appendChild(listItem); } - } + }); } this._initPagination(additionalData.pageCount, additionalData.pageNo); this._setMedia(media); - }, + } /** * Sets up a new media element. - * - * @param {object} media data of the media file - * @param {HTMLElement} mediaElement element representing the media file */ - setupMediaElement: function (media, mediaElement) { - var mediaInformation = DomTraverse.childByClass(mediaElement, 'mediaInformation'); - var buttonGroupNavigation = elCreate('nav'); - buttonGroupNavigation.className = 'jsMobileNavigation buttonGroupNavigation'; + setupMediaElement(media, mediaElement) { + const mediaInformation = DomTraverse.childByClass(mediaElement, "mediaInformation"); + const buttonGroupNavigation = document.createElement("nav"); + buttonGroupNavigation.className = "jsMobileNavigation buttonGroupNavigation"; mediaInformation.parentNode.appendChild(buttonGroupNavigation); - var buttons = elCreate('ul'); - buttons.className = 'buttonList iconList'; + const buttons = document.createElement("ul"); + buttons.className = "buttonList iconList"; buttonGroupNavigation.appendChild(buttons); - var listItem = elCreate('li'); - listItem.className = 'mediaCheckbox'; + const listItem = document.createElement("li"); + listItem.className = "mediaCheckbox"; buttons.appendChild(listItem); - var a = elCreate('a'); + const a = document.createElement("a"); listItem.appendChild(a); - var label = elCreate('label'); + const label = document.createElement("label"); a.appendChild(label); - var checkbox = elCreate('input'); - checkbox.className = 'jsClipboardItem'; - elAttr(checkbox, 'type', 'checkbox'); - elData(checkbox, 'object-id', media.mediaID); + const checkbox = document.createElement("input"); + checkbox.className = "jsClipboardItem"; + checkbox.type = "checkbox"; + checkbox.dataset.objectId = media.mediaID; label.appendChild(checkbox); - if (Permission.get('admin.content.cms.canManageMedia')) { - listItem = elCreate('li'); - listItem.className = 'jsMediaEditButton'; - elData(listItem, 'object-id', media.mediaID); - buttons.appendChild(listItem); - listItem.innerHTML = ' '; - listItem = elCreate('li'); - listItem.className = 'jsDeleteButton'; - elData(listItem, 'object-id', media.mediaID); + if (Permission.get("admin.content.cms.canManageMedia")) { + const editButton = document.createElement("li"); + editButton.className = "jsMediaEditButton"; + editButton.dataset.objectId = media.mediaID; + buttons.appendChild(editButton); + editButton.innerHTML = ` + + + + `; + const deleteButton = document.createElement("li"); + deleteButton.className = "jsDeleteButton"; + deleteButton.dataset.objectId = media.mediaID; // use temporary title to not unescape html in filename - var uuid = Core.getUuid(); - elData(listItem, 'confirm-message-html', StringUtil.unescapeHTML(Language.get('wcf.media.delete.confirmMessage', { - title: uuid - })).replace(uuid, StringUtil.escapeHTML(media.filename))); - buttons.appendChild(listItem); - listItem.innerHTML = ' '; + const uuid = Core.getUuid(); + deleteButton.dataset.confirmMessageHtml = StringUtil.unescapeHTML(Language.get("wcf.media.delete.confirmMessage", { + title: uuid, + })).replace(uuid, StringUtil.escapeHTML(media.filename)); + buttons.appendChild(deleteButton); + deleteButton.innerHTML = ` + + + + `; } } - }; - return MediaManagerBase; + } + Core.enableLegacyInheritance(MediaManager); + return MediaManager; }); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Manager/Base.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Manager/Base.js deleted file mode 100644 index 8146ca0931..0000000000 --- a/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Manager/Base.js +++ /dev/null @@ -1,619 +0,0 @@ -/** - * Provides the media manager dialog. - * - * @author Matthias Schmidt - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @module WoltLabSuite/Core/Media/Manager/Base - */ -define( - [ - 'Core', 'Dictionary', 'Dom/ChangeListener', 'Dom/Traverse', - 'Dom/Util', 'EventHandler', 'Language', 'List', - 'Permission', 'Ui/Dialog', 'Ui/Notification', 'WoltLabSuite/Core/Controller/Clipboard', - 'WoltLabSuite/Core/Media/Editor', 'WoltLabSuite/Core/Media/Upload', 'WoltLabSuite/Core/Media/Manager/Search', 'StringUtil', - 'WoltLabSuite/Core/Ui/Pagination', - 'WoltLabSuite/Core/Media/Clipboard' - ], - function( - Core, Dictionary, DomChangeListener, DomTraverse, - DomUtil, EventHandler, Language, List, - Permission, UiDialog, UiNotification, Clipboard, - MediaEditor, MediaUpload, MediaManagerSearch, StringUtil, - UiPagination, - MediaClipboard - ) -{ - "use strict"; - - if (!COMPILER_TARGET_DEFAULT) { - var Fake = function() {}; - Fake.prototype = { - _addButtonEventListeners: function() {}, - _click: function() {}, - _dialogClose: function() {}, - _dialogInit: function() {}, - _dialogSetup: function() {}, - _dialogShow: function() {}, - _editMedia: function() {}, - _editorClose: function() {}, - _editorSuccess: function() {}, - _removeClipboardCheckboxes: function() {}, - _setMedia: function() {}, - addMedia: function() {}, - clipboardDeleteMedia: function() {}, - getDialog: function() {}, - getMode: function() {}, - getOption: function() {}, - removeMedia: function() {}, - resetMedia: function() {}, - setMedia: function() {}, - setupMediaElement: function() {} - }; - return Fake; - } - - var _mediaManagerCounter = 0; - - /** - * @constructor - */ - function MediaManagerBase(options) { - this._options = Core.extend({ - dialogTitle: Language.get('wcf.media.manager'), - imagesOnly: false, - minSearchLength: 3 - }, options); - - this._id = 'mediaManager' + _mediaManagerCounter++; - this._listItems = new Dictionary(); - this._media = new Dictionary(); - this._mediaManagerMediaList = null; - this._search = null; - this._upload = null; - this._forceClipboard = false; - this._hadInitiallyMarkedItems = false; - this._pagination = null; - - if (Permission.get('admin.content.cms.canManageMedia')) { - this._mediaEditor = new MediaEditor(this); - } - - DomChangeListener.add('WoltLabSuite/Core/Media/Manager', this._addButtonEventListeners.bind(this)); - - EventHandler.add('com.woltlab.wcf.media.upload', 'success', this._openEditorAfterUpload.bind(this)); - } - MediaManagerBase.prototype = { - /** - * Adds click event listeners to media buttons. - */ - _addButtonEventListeners: function() { - if (!this._mediaManagerMediaList) return; - - var listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI'); - for (var i = 0, length = listItems.length; i < length; i++) { - var listItem = listItems[i]; - - if (Permission.get('admin.content.cms.canManageMedia')) { - var editIcon = elByClass('jsMediaEditButton', listItem)[0]; - if (editIcon) { - editIcon.classList.remove('jsMediaEditButton'); - editIcon.addEventListener('click', this._editMedia.bind(this)); - } - } - } - }, - - /** - * Is called when a new category is selected. - */ - _categoryChange: function() { - this._search.search(); - }, - - /** - * Handles clicks on the media manager button. - * - * @param {object} event event object - */ - _click: function(event) { - event.preventDefault(); - - UiDialog.open(this); - }, - - /** - * Is called if the media manager dialog is closed. - */ - _dialogClose: function() { - // only show media clipboard if editor is open - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { - Clipboard.hideEditor('com.woltlab.wcf.media'); - } - }, - - /** - * Initializes the dialog when first loaded. - * - * @param {string} content dialog content - * @param {object} data AJAX request's response data - */ - _dialogInit: function(content, data) { - // store media data locally - var media = data.returnValues.media || { }; - for (var mediaId in media) { - if (objOwns(media, mediaId)) { - this._media.set(~~mediaId, media[mediaId]); - } - } - - this._initPagination(~~data.returnValues.pageCount); - - this._hadInitiallyMarkedItems = data.returnValues.hasMarkedItems; - }, - - /** - * Returns all data to setup the media manager dialog. - * - * @return {object} dialog setup data - */ - _dialogSetup: function() { - return { - id: this._id, - options: { - onClose: this._dialogClose.bind(this), - onShow: this._dialogShow.bind(this), - title: this._options.dialogTitle - }, - source: { - after: this._dialogInit.bind(this), - data: { - actionName: 'getManagementDialog', - className: 'wcf\\data\\media\\MediaAction', - parameters: { - mode: this.getMode(), - imagesOnly: this._options.imagesOnly - } - } - } - }; - }, - - /** - * Is called if the media manager dialog is shown. - */ - _dialogShow: function() { - if (!this._mediaManagerMediaList) { - var dialog = this.getDialog(); - - this._mediaManagerMediaList = elByClass('mediaManagerMediaList', dialog)[0]; - - this._mediaCategorySelect = elBySel('.mediaManagerCategoryList > select', dialog); - if (this._mediaCategorySelect) { - this._mediaCategorySelect.addEventListener('change', this._categoryChange.bind(this)); - } - - // store list items locally - var listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI'); - for (var i = 0, length = listItems.length; i < length; i++) { - var listItem = listItems[i]; - - this._listItems.set(~~elData(listItem, 'object-id'), listItem); - } - - if (Permission.get('admin.content.cms.canManageMedia')) { - var uploadButton = elByClass('mediaManagerMediaUploadButton', UiDialog.getDialog(this).dialog)[0]; - this._upload = new MediaUpload(DomUtil.identify(uploadButton), DomUtil.identify(this._mediaManagerMediaList), { - mediaManager: this - }); - - var deleteAction = new WCF.Action.Delete('wcf\\data\\media\\MediaAction', '.mediaFile'); - deleteAction._didTriggerEffect = function(element) { - this.removeMedia(elData(element[0], 'object-id')); - }.bind(this); - } - - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { - MediaClipboard.init( - 'menuManagerDialog-' + this.getMode(), - this._hadInitiallyMarkedItems ? true : false, - this - ); - } - else { - this._removeClipboardCheckboxes(); - } - - this._search = new MediaManagerSearch(this); - - if (!listItems.length) { - this._search.hideSearch(); - } - } - - // only show media clipboard if editor is open - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { - Clipboard.showEditor('com.woltlab.wcf.media'); - } - }, - - /** - * Opens the media editor for a media file. - * - * @param {Event} event event object for clicks on edit icons - */ - _editMedia: function(event) { - if (!Permission.get('admin.content.cms.canManageMedia')) { - throw new Error("You are not allowed to edit media files."); - } - - UiDialog.close(this); - - this._mediaEditor.edit(this._media.get(~~elData(event.currentTarget, 'object-id'))); - }, - - /** - * Re-opens the manager dialog after closing the editor dialog. - */ - _editorClose: function() { - UiDialog.open(this); - }, - - /** - * Re-opens the manager dialog and updates the media data after - * successfully editing a media file. - * - * @param {object} media updated media file data - * @param {integer} oldCategoryId old category id - */ - _editorSuccess: function(media, oldCategoryId) { - // if the category changed of media changed and category - // is selected, check if media list needs to be refreshed - if (this._mediaCategorySelect) { - var selectedCategoryId = ~~this._mediaCategorySelect.value; - - if (selectedCategoryId) { - var newCategoryId = ~~media.categoryID; - - if (oldCategoryId != newCategoryId && (oldCategoryId == selectedCategoryId || newCategoryId == selectedCategoryId)) { - this._search.search(); - } - } - } - - UiDialog.open(this); - - this._media.set(~~media.mediaID, media); - - var listItem = this._listItems.get(~~media.mediaID); - var p = elByClass('mediaTitle', listItem)[0]; - if (media.isMultilingual) { - if (media.title && media.title[LANGUAGE_ID]) { - p.textContent = media.title[LANGUAGE_ID]; - } - else { - p.textContent = media.filename; - } - } - else { - if (media.title && media.title[media.languageID]) { - p.textContent = media.title[media.languageID]; - } - else { - p.textContent = media.filename; - } - } - - var thumbnail = elByClass('mediaThumbnail', listItem)[0]; - thumbnail.innerHTML = media.elementTag; - // Bust browser cache by adding additional parameter. - var imgs = elByTag('img', thumbnail); - if (imgs.length) { - imgs[0].src += '&refresh=' + Date.now(); - } - }, - - /** - * Initializes the dialog pagination. - * - * @param {integer} pageCount - * @param {integer} pageNo - */ - _initPagination: function(pageCount, pageNo) { - if (pageNo === undefined) pageNo = 1; - - if (pageCount > 1) { - var newPagination = elCreate('div'); - newPagination.className = 'paginationBottom jsPagination'; - DomUtil.replaceElement(elBySel('.jsPagination', UiDialog.getDialog(this).content), newPagination); - - this._pagination = new UiPagination(newPagination, { - activePage: pageNo, - callbackSwitch: this._search.search.bind(this._search), - maxPage: pageCount - }); - } - else if (this._pagination) { - elHide(this._pagination.getElement()); - } - }, - - /** - * Removes all media clipboard checkboxes. - */ - _removeClipboardCheckboxes: function() { - var checkboxes = elByClass('mediaCheckbox', this._mediaManagerMediaList); - while (checkboxes.length) { - elRemove(checkboxes[0]); - } - }, - - /** - * Opens the media editor after uploading a single file. - * - * @param {object} data upload event data - * @since 5.2 - */ - _openEditorAfterUpload: function(data) { - if (data.upload === this._upload && !data.isMultiFileUpload && !this._upload.hasPendingUploads()) { - var keys = Object.keys(data.media); - - if (keys.length) { - UiDialog.close(this); - - this._mediaEditor.edit(this._media.get(~~data.media[keys[0]].mediaID)); - } - } - }, - - /** - * Sets the displayed media (after a search). - * - * @param {Dictionary} media media to be set as active - */ - _setMedia: function(media) { - if (Core.isPlainObject(media)) { - this._media = Dictionary.fromObject(media); - } - else { - this._media = media; - } - - var info = DomTraverse.nextByClass(this._mediaManagerMediaList, 'info'); - - if (this._media.size) { - if (info) { - elHide(info); - } - } - else { - if (info === null) { - info = elCreate('p'); - info.className = 'info'; - info.textContent = Language.get('wcf.media.search.noResults'); - } - - elShow(info); - DomUtil.insertAfter(info, this._mediaManagerMediaList); - } - - var mediaListItems = DomTraverse.childrenByTag(this._mediaManagerMediaList, 'LI'); - for (var i = 0, length = mediaListItems.length; i < length; i++) { - var listItem = mediaListItems[i]; - - if (!this._media.has(elData(listItem, 'object-id'))) { - elHide(listItem); - } - else { - elShow(listItem); - } - } - - DomChangeListener.trigger(); - - if (Permission.get('admin.content.cms.canManageMedia') || this._forceClipboard) { - Clipboard.reload(); - } - else { - this._removeClipboardCheckboxes(); - } - }, - - /** - * Adds a media file to the manager. - * - * @param {object} media data of the media file - * @param {Element} listItem list item representing the file - */ - addMedia: function(media, listItem) { - if (!media.languageID) media.isMultilingual = 1; - - this._media.set(~~media.mediaID, media); - this._listItems.set(~~media.mediaID, listItem); - - if (this._listItems.size === 1) { - this._search.showSearch(); - } - }, - - /** - * Is called after the media files with the given ids have been deleted via clipboard. - * - * @param {int[]} mediaIds ids of deleted media files - */ - clipboardDeleteMedia: function(mediaIds) { - for (var i = 0, length = mediaIds.length; i < length; i++) { - this.removeMedia(~~mediaIds[i], true); - } - - UiNotification.show(); - }, - - /** - * Returns the id of the currently selected category or `0` if no category is selected. - * - * @return {integer} - */ - getCategoryId: function() { - if (this._mediaCategorySelect) { - return this._mediaCategorySelect.value; - } - - return 0; - }, - - /** - * Returns the media manager dialog element. - * - * @return {Element} media manager dialog - */ - getDialog: function() { - return UiDialog.getDialog(this).dialog; - }, - - /** - * Returns the mode of the media manager. - * - * @return {string} - */ - getMode: function() { - return ''; - }, - - /** - * Returns the media manager option with the given name. - * - * @param {string} name option name - * @return {mixed} option value or null - */ - getOption: function(name) { - if (this._options[name]) { - return this._options[name]; - } - - return null; - }, - - /** - * Removes a media file. - * - * @param {int} mediaId id of the removed media file - */ - removeMedia: function(mediaId) { - if (this._listItems.has(mediaId)) { - // remove list item - try { - elRemove(this._listItems.get(mediaId)); - } - catch (e) { - // ignore errors if item has already been removed like by WCF.Action.Delete - } - - this._listItems.delete(mediaId); - this._media.delete(mediaId); - } - }, - - /** - * Changes the displayed media to the previously displayed media. - */ - resetMedia: function() { - // calling WoltLabSuite/Core/Media/Manager/Search.search() reloads the first page of the dialog - this._search.search(); - }, - - /** - * Sets the media files currently displayed. - * - * @param {object} media media data - * @param {string} template - * @param {object} additionalData - */ - setMedia: function(media, template, additionalData) { - var hasMedia = false; - for (var mediaId in media) { - if (objOwns(media, mediaId)) { - hasMedia = true; - } - } - - var newListItems = []; - if (hasMedia) { - var ul = elCreate('ul'); - ul.innerHTML = template; - - var listItems = DomTraverse.childrenByTag(ul, 'LI'); - for (var i = 0, length = listItems.length; i < length; i++) { - var listItem = listItems[i]; - if (!this._listItems.has(~~elData(listItem, 'object-id'))) { - this._listItems.set(elData(listItem, 'object-id'), listItem); - - this._mediaManagerMediaList.appendChild(listItem); - } - } - } - - this._initPagination(additionalData.pageCount, additionalData.pageNo); - - this._setMedia(media); - }, - - /** - * Sets up a new media element. - * - * @param {object} media data of the media file - * @param {HTMLElement} mediaElement element representing the media file - */ - setupMediaElement: function(media, mediaElement) { - var mediaInformation = DomTraverse.childByClass(mediaElement, 'mediaInformation'); - - var buttonGroupNavigation = elCreate('nav'); - buttonGroupNavigation.className = 'jsMobileNavigation buttonGroupNavigation'; - mediaInformation.parentNode.appendChild(buttonGroupNavigation); - - var buttons = elCreate('ul'); - buttons.className = 'buttonList iconList'; - buttonGroupNavigation.appendChild(buttons); - - var listItem = elCreate('li'); - listItem.className = 'mediaCheckbox'; - buttons.appendChild(listItem); - - var a = elCreate('a'); - listItem.appendChild(a); - - var label = elCreate('label'); - a.appendChild(label); - - var checkbox = elCreate('input'); - checkbox.className = 'jsClipboardItem'; - elAttr(checkbox, 'type', 'checkbox'); - elData(checkbox, 'object-id', media.mediaID); - label.appendChild(checkbox); - - if (Permission.get('admin.content.cms.canManageMedia')) { - listItem = elCreate('li'); - listItem.className = 'jsMediaEditButton'; - elData(listItem, 'object-id', media.mediaID); - buttons.appendChild(listItem); - - listItem.innerHTML = ' '; - - listItem = elCreate('li'); - listItem.className = 'jsDeleteButton'; - elData(listItem, 'object-id', media.mediaID); - - // use temporary title to not unescape html in filename - var uuid = Core.getUuid(); - elData(listItem, 'confirm-message-html', StringUtil.unescapeHTML(Language.get('wcf.media.delete.confirmMessage', { - title: uuid - })).replace(uuid, StringUtil.escapeHTML(media.filename))); - buttons.appendChild(listItem); - - listItem.innerHTML = ' '; - } - } - }; - - return MediaManagerBase; -}); diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Manager/Base.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Manager/Base.ts new file mode 100644 index 0000000000..9ea0747974 --- /dev/null +++ b/wcfsetup/install/files/ts/WoltLabSuite/Core/Media/Manager/Base.ts @@ -0,0 +1,550 @@ +/** + * Provides the media manager dialog. + * + * @author Matthias Schmidt + * @copyright 2001-2020 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Media/Manager/Base + */ + +import * as Core from "../../Core"; +import { Media, MediaManagerOptions, MediaEditorCallbackObject, MediaUploadSuccessEventData } from "../Data"; +import * as Language from "../../Language"; +import * as Permission from "../../Permission"; +import * as DomChangeListener from "../../Dom/Change/Listener"; +import * as EventHandler from "../../Event/Handler"; +import * as DomTraverse from "../../Dom/Traverse"; +import * as DomUtil from "../../Dom/Util"; +import * as UiDialog from "../../Ui/Dialog"; +import { DialogCallbackSetup, DialogCallbackObject } from "../../Ui/Dialog/Data"; +import * as Clipboard from "../../Controller/Clipboard"; +import UiPagination from "../../Ui/Pagination"; +import * as UiNotification from "../../Ui/Notification"; +import * as StringUtil from "../../StringUtil"; +import MediaManagerSearch from "./Search"; +import MediaUpload from "../Upload"; +import MediaEditor from "../Editor"; +import * as MediaClipboard from "../Clipboard"; + +let mediaManagerCounter = 0; + +type DialogInitAjaxResponseData = { + returnValues: { + hasMarkedItems: number; + media: object; + pageCount: number; + }; +}; + +type SetMediaAdditionalData = { + pageCount: number; + pageNo: number; +}; + +abstract class MediaManager + implements DialogCallbackObject, MediaEditorCallbackObject { + protected _forceClipboard = false; + protected _hadInitiallyMarkedItems = false; + protected readonly _id = `mediaManager${mediaManagerCounter++}`; + protected readonly _listItems = new Map(); + protected _media = new Map(); + protected _mediaCategorySelect: HTMLSelectElement | null; + protected readonly _mediaEditor: MediaEditor | null = null; + protected _mediaManagerMediaList: HTMLElement | null = null; + protected _pagination: UiPagination | null = null; + protected _search: MediaManagerSearch | null = null; + protected _upload: any = null; + protected readonly _options: TOptions; + + constructor(options: Partial) { + this._options = Core.extend( + { + dialogTitle: Language.get("wcf.media.manager"), + imagesOnly: false, + minSearchLength: 3, + }, + options, + ) as TOptions; + + if (Permission.get("admin.content.cms.canManageMedia")) { + this._mediaEditor = new MediaEditor(this); + } + + DomChangeListener.add("WoltLabSuite/Core/Media/Manager", () => this._addButtonEventListeners()); + + EventHandler.add("com.woltlab.wcf.media.upload", "success", (data: MediaUploadSuccessEventData) => + this._openEditorAfterUpload(data), + ); + } + + /** + * Adds click event listeners to media buttons. + */ + protected _addButtonEventListeners(): void { + if (!this._mediaManagerMediaList || !Permission.get("admin.content.cms.canManageMedia")) return; + + DomTraverse.childrenByTag(this._mediaManagerMediaList, "LI").forEach((listItem) => { + const editIcon = listItem.querySelector(".jsMediaEditButton"); + if (editIcon) { + editIcon.classList.remove("jsMediaEditButton"); + editIcon.addEventListener("click", (ev: MouseEvent) => this._editMedia(ev)); + } + }); + } + + /** + * Is called when a new category is selected. + */ + protected _categoryChange(): void { + this._search!.search(); + } + + /** + * Handles clicks on the media manager button. + */ + protected _click(event: MouseEvent): void { + event.preventDefault(); + + UiDialog.open(this); + } + + /** + * Is called if the media manager dialog is closed. + */ + protected _dialogClose(): void { + // only show media clipboard if editor is open + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { + Clipboard.hideEditor("com.woltlab.wcf.media"); + } + } + + /** + * Initializes the dialog when first loaded. + */ + protected _dialogInit(content: HTMLElement, data: DialogInitAjaxResponseData): void { + // store media data locally + Object.entries(data.returnValues.media || {}).forEach(([mediaId, media]) => { + this._media.set(~~mediaId, media); + }); + + this._initPagination(~~data.returnValues.pageCount); + + this._hadInitiallyMarkedItems = data.returnValues.hasMarkedItems > 0; + } + + /** + * Returns all data to setup the media manager dialog. + */ + public _dialogSetup(): ReturnType { + return { + id: this._id, + options: { + onClose: () => this._dialogClose(), + onShow: () => this._dialogShow(), + title: this._options.dialogTitle, + }, + source: { + after: (content: HTMLElement, data: DialogInitAjaxResponseData) => this._dialogInit(content, data), + data: { + actionName: "getManagementDialog", + className: "wcf\\data\\media\\MediaAction", + parameters: { + mode: this.getMode(), + imagesOnly: this._options.imagesOnly, + }, + }, + }, + }; + } + + /** + * Is called if the media manager dialog is shown. + */ + protected _dialogShow(): void { + if (!this._mediaManagerMediaList) { + const dialog = this.getDialog(); + + this._mediaManagerMediaList = dialog.querySelector(".mediaManagerMediaList"); + + this._mediaCategorySelect = dialog.querySelector(".mediaManagerCategoryList > select"); + if (this._mediaCategorySelect) { + this._mediaCategorySelect.addEventListener("change", this._categoryChange.bind(this)); + } + + // store list items locally + const listItems = DomTraverse.childrenByTag(this._mediaManagerMediaList!, "LI"); + listItems.forEach((listItem: HTMLLIElement) => { + this._listItems.set(~~listItem.dataset.objectId!, listItem); + }); + + if (Permission.get("admin.content.cms.canManageMedia")) { + const uploadButton = UiDialog.getDialog(this)!.dialog.querySelector(".mediaManagerMediaUploadButton")!; + this._upload = new MediaUpload(DomUtil.identify(uploadButton), DomUtil.identify(this._mediaManagerMediaList!), { + mediaManager: this, + }); + + // eslint-disable-next-line + //@ts-ignore + const deleteAction = new WCF.Action.Delete("wcf\\data\\media\\MediaAction", ".mediaFile"); + deleteAction._didTriggerEffect = (element) => this.removeMedia(element[0].dataset.objectId); + } + + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { + MediaClipboard.init("menuManagerDialog-" + this.getMode(), this._hadInitiallyMarkedItems ? true : false, this); + } else { + this._removeClipboardCheckboxes(); + } + + this._search = new MediaManagerSearch(this); + + if (!listItems.length) { + this._search.hideSearch(); + } + } + + // only show media clipboard if editor is open + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { + Clipboard.showEditor(); + } + } + + /** + * Opens the media editor for a media file. + */ + protected _editMedia(event: MouseEvent): void { + if (!Permission.get("admin.content.cms.canManageMedia")) { + throw new Error("You are not allowed to edit media files."); + } + + UiDialog.close(this); + + const target = event.currentTarget as HTMLElement; + + this._mediaEditor!.edit(this._media.get(~~target.dataset.objectId!)!); + } + + /** + * Re-opens the manager dialog after closing the editor dialog. + */ + _editorClose(): void { + UiDialog.open(this); + } + + /** + * Re-opens the manager dialog and updates the media data after successfully editing a media file. + */ + _editorSuccess(media: Media, oldCategoryId?: number): void { + // if the category changed of media changed and category + // is selected, check if media list needs to be refreshed + if (this._mediaCategorySelect) { + const selectedCategoryId = ~~this._mediaCategorySelect.value; + + if (selectedCategoryId) { + const newCategoryId = ~~media.categoryID; + + if ( + oldCategoryId != newCategoryId && + (oldCategoryId == selectedCategoryId || newCategoryId == selectedCategoryId) + ) { + this._search!.search(); + } + } + } + + UiDialog.open(this); + + this._media.set(~~media.mediaID, media); + + const listItem = this._listItems.get(~~media.mediaID)!; + const p = listItem.querySelector(".mediaTitle")!; + if (media.isMultilingual) { + if (media.title && media.title[window.LANGUAGE_ID]) { + p.textContent = media.title[window.LANGUAGE_ID]; + } else { + p.textContent = media.filename; + } + } else { + if (media.title && media.title[media.languageID!]) { + p.textContent = media.title[media.languageID!]; + } else { + p.textContent = media.filename; + } + } + + const thumbnail = listItem.querySelector(".mediaThumbnail")!; + thumbnail.innerHTML = media.elementTag; + // Bust browser cache by adding additional parameter. + const img = thumbnail.querySelector("img"); + if (img) { + img.src += `&refresh=${Date.now()}`; + } + } + + /** + * Initializes the dialog pagination. + */ + protected _initPagination(pageCount: number, pageNo?: number): void { + if (pageNo === undefined) pageNo = 1; + + if (pageCount > 1) { + const newPagination = document.createElement("div"); + newPagination.className = "paginationBottom jsPagination"; + DomUtil.replaceElement( + UiDialog.getDialog(this)!.content.querySelector(".jsPagination") as HTMLElement, + newPagination, + ); + + this._pagination = new UiPagination(newPagination, { + activePage: pageNo, + callbackSwitch: this._search!.search.bind(this._search), + maxPage: pageCount, + }); + } else if (this._pagination) { + this._pagination.getElement().style.display = "none"; + } + } + + /** + * Removes all media clipboard checkboxes. + */ + _removeClipboardCheckboxes(): void { + this._mediaManagerMediaList!.querySelectorAll(".mediaCheckbox").forEach((el) => el.remove()); + } + + /** + * Opens the media editor after uploading a single file. + * + * @since 5.2 + */ + _openEditorAfterUpload(data: MediaUploadSuccessEventData): void { + if (data.upload === this._upload && !data.isMultiFileUpload && !this._upload.hasPendingUploads()) { + const keys = Object.keys(data.media); + + if (keys.length) { + UiDialog.close(this); + + this._mediaEditor!.edit(this._media.get(~~data.media[keys[0]].mediaID)!); + } + } + } + + /** + * Sets the displayed media (after a search). + */ + _setMedia(media: object): void { + this._media = new Map(); + Object.entries(media).forEach(([mediaId, media]) => { + this._media.set(~~mediaId, media); + }); + + let info = DomTraverse.nextByClass(this._mediaManagerMediaList!, "info") as HTMLElement; + + if (this._media.size) { + if (info) { + info.style.display = "none"; + } + } else { + if (info === null) { + info = document.createElement("p"); + info.className = "info"; + info.textContent = Language.get("wcf.media.search.noResults"); + } + + info.style.display = "block"; + DomUtil.insertAfter(info, this._mediaManagerMediaList!); + } + + DomTraverse.childrenByTag(this._mediaManagerMediaList!, "LI").forEach((listItem) => { + if (!this._media.has(~~listItem.dataset.objectId!)) { + listItem.style.display = "none"; + } else { + listItem.style.display = "block"; + } + }); + + DomChangeListener.trigger(); + + if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) { + Clipboard.reload(); + } else { + this._removeClipboardCheckboxes(); + } + } + + /** + * Adds a media file to the manager. + */ + public addMedia(media: Media, listItem: HTMLLIElement): void { + if (!media.languageID) media.isMultilingual = 1; + + this._media.set(~~media.mediaID, media); + this._listItems.set(~~media.mediaID, listItem); + + if (this._listItems.size === 1) { + this._search!.showSearch(); + } + } + + /** + * Is called after the media files with the given ids have been deleted via clipboard. + */ + public clipboardDeleteMedia(mediaIds: number[]): void { + mediaIds.forEach((mediaId) => { + this.removeMedia(~~mediaId); + }); + + UiNotification.show(); + } + + /** + * Returns the id of the currently selected category or `0` if no category is selected. + */ + public getCategoryId(): number { + if (this._mediaCategorySelect) { + return ~~this._mediaCategorySelect.value; + } + + return 0; + } + + /** + * Returns the media manager dialog element. + */ + getDialog(): HTMLElement { + return UiDialog.getDialog(this)!.dialog; + } + + /** + * Returns the mode of the media manager. + */ + public getMode(): string { + return ""; + } + + /** + * Returns the media manager option with the given name. + */ + public getOption(name: string): any { + if (this._options[name]) { + return this._options[name]; + } + + return null; + } + + /** + * Removes a media file. + */ + public removeMedia(mediaId: number): void { + if (this._listItems.has(mediaId)) { + // remove list item + try { + this._listItems.get(mediaId)!.remove(); + } catch (e) { + // ignore errors if item has already been removed like by WCF.Action.Delete + } + + this._listItems.delete(mediaId); + this._media.delete(mediaId); + } + } + + /** + * Changes the displayed media to the previously displayed media. + */ + public resetMedia(): void { + // calling WoltLabSuite/Core/Media/Manager/Search.search() reloads the first page of the dialog + this._search!.search(); + } + + /** + * Sets the media files currently displayed. + */ + setMedia(media: object, template: string, additionalData: SetMediaAdditionalData): void { + const hasMedia = Object.entries(media).length > 0; + + if (hasMedia) { + const ul = document.createElement("ul"); + ul.innerHTML = template; + + DomTraverse.childrenByTag(ul, "LI").forEach((listItem) => { + if (!this._listItems.has(~~listItem.dataset.objectId!)) { + this._listItems.set(~~listItem.dataset.objectId!, listItem); + + this._mediaManagerMediaList!.appendChild(listItem); + } + }); + } + + this._initPagination(additionalData.pageCount, additionalData.pageNo); + + this._setMedia(media); + } + + /** + * Sets up a new media element. + */ + public setupMediaElement(media: Media, mediaElement: HTMLElement): void { + const mediaInformation = DomTraverse.childByClass(mediaElement, "mediaInformation")!; + + const buttonGroupNavigation = document.createElement("nav"); + buttonGroupNavigation.className = "jsMobileNavigation buttonGroupNavigation"; + mediaInformation.parentNode!.appendChild(buttonGroupNavigation); + + const buttons = document.createElement("ul"); + buttons.className = "buttonList iconList"; + buttonGroupNavigation.appendChild(buttons); + + const listItem = document.createElement("li"); + listItem.className = "mediaCheckbox"; + buttons.appendChild(listItem); + + const a = document.createElement("a"); + listItem.appendChild(a); + + const label = document.createElement("label"); + a.appendChild(label); + + const checkbox = document.createElement("input"); + checkbox.className = "jsClipboardItem"; + checkbox.type = "checkbox"; + checkbox.dataset.objectId = (media.mediaID as unknown) as string; + label.appendChild(checkbox); + + if (Permission.get("admin.content.cms.canManageMedia")) { + const editButton = document.createElement("li"); + editButton.className = "jsMediaEditButton"; + editButton.dataset.objectId = (media.mediaID as unknown) as string; + buttons.appendChild(editButton); + + editButton.innerHTML = ` + + + + `; + + const deleteButton = document.createElement("li"); + deleteButton.className = "jsDeleteButton"; + deleteButton.dataset.objectId = (media.mediaID as unknown) as string; + + // use temporary title to not unescape html in filename + const uuid = Core.getUuid(); + deleteButton.dataset.confirmMessageHtml = StringUtil.unescapeHTML( + Language.get("wcf.media.delete.confirmMessage", { + title: uuid, + }), + ).replace(uuid, StringUtil.escapeHTML(media.filename)); + buttons.appendChild(deleteButton); + + deleteButton.innerHTML = ` + + + + `; + } + } +} + +Core.enableLegacyInheritance(MediaManager); + +export = MediaManager;