Use `Ui/Object/Action` for media files
authorMatthias Schmidt <gravatronics@live.com>
Sun, 21 Mar 2021 09:42:34 +0000 (10:42 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Sun, 21 Mar 2021 09:42:34 +0000 (10:42 +0100)
14 files changed:
com.woltlab.wcf/templates/mediaListItems.tpl
com.woltlab.wcf/templates/mediaManager.tpl
ts/WoltLabSuite/Core/Controller/Media/List.ts
ts/WoltLabSuite/Core/Media/Manager/Base.ts
ts/WoltLabSuite/Core/Media/Upload.ts
ts/WoltLabSuite/Core/Ui/Empty.ts
ts/WoltLabSuite/Core/Ui/Object/Action.ts
wcfsetup/install/files/acp/templates/mediaList.tpl
wcfsetup/install/files/acp/templates/mediaListItems.tpl
wcfsetup/install/files/acp/templates/mediaManager.tpl
wcfsetup/install/files/js/WoltLabSuite/Core/Controller/Media/List.js
wcfsetup/install/files/js/WoltLabSuite/Core/Media/Manager/Base.js
wcfsetup/install/files/js/WoltLabSuite/Core/Media/Upload.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Object/Action.js

index 95fe0041b0eb27f1b4059ef980455779b58b72bc..7a1e6e0facedee20c0509dfa1349d77b07670bb9 100644 (file)
@@ -1,5 +1,5 @@
 {foreach from=$mediaList item=media}
-       <li class="jsClipboardObject mediaFile" data-object-id="{@$media->mediaID}">
+       <li class="jsClipboardObject mediaFile jsObjectActionObject" data-object-id="{@$media->getObjectID()}">
                <div class="mediaThumbnail">
                        {@$media->getElementTag(144)}
                </div>
@@ -21,7 +21,7 @@
                                        <li class="jsMediaEditButton" data-object-id="{@$media->mediaID}">
                                                <a><span class="icon icon16 fa-pencil jsTooltip" title="{lang}wcf.global.button.edit{/lang}"></span> <span class="invisible">{lang}wcf.global.button.edit{/lang}</span></a>
                                        </li>
-                                       <li class="jsDeleteButton" data-object-id="{@$media->mediaID}" data-confirm-message-html="{lang title=$__mediaTitle __encode=true}wcf.media.delete.confirmMessage{/lang}">
+                                       <li class="jsObjectAction" data-object-action="delete" data-confirm-message="{lang title=$__mediaTitle __encode=true}wcf.media.delete.confirmMessage{/lang}">
                                                <a><span class="icon icon16 fa-times jsTooltip" title="{lang}wcf.global.button.delete{/lang}"></span> <span class="invisible">{lang}wcf.global.button.delete{/lang}</span></a>
                                        </li>
                                {/if}
index 2dc7d4828ca242601524d949a99ba58fbfc07ea4..9fe55be085aa65277dbeeb45d000904f266432b2 100644 (file)
@@ -37,7 +37,7 @@
 
 <div class="jsClipboardContainer" data-type="com.woltlab.wcf.media">
        <input type="checkbox" class="jsClipboardMarkAll" style="display: none;">
-       <ul class="mediaManagerMediaList">
+       <ul class="mediaManagerMediaList jsObjectActionContainer" data-object-action-class-name="wcf\data\media\MediaAction">
                {include file='mediaListItems'}
        </ul>
 </div>
index c296837da530b2b56bada6d4d3a7c255bd3f8b10..56b26e4790f5fda268a2a326d79f90106fa593d2 100644 (file)
@@ -45,13 +45,6 @@ export function init(options: MediaListOptions): void {
     clipboardDeleteMedia: (mediaIds: number[]) => clipboardDeleteMedia(mediaIds),
   } as MediaManager);
 
-  EventHandler.add("com.woltlab.wcf.media.upload", "removedErroneousUploadRow", () => deleteCallback());
-
-  // eslint-disable-next-line
-  //@ts-ignore
-  const deleteAction = new WCF.Action.Delete("wcf\\data\\media\\MediaAction", ".jsMediaRow");
-  deleteAction.setCallback(deleteCallback);
-
   addButtonEventListeners();
 
   DomChangeListener.add("WoltLabSuite/Core/Controller/Media/List", () => addButtonEventListeners());
index ad0212e9c863f25f10b222480bfc34890d85d3ab..e1f4f178e1cf744e0d092322d43f43a14f6769e2 100644 (file)
@@ -25,6 +25,7 @@ import MediaManagerSearch from "./Search";
 import MediaUpload from "../Upload";
 import MediaEditor from "../Editor";
 import * as MediaClipboard from "../Clipboard";
+import { ObjectActionData } from "../../Ui/Object/Data";
 
 let mediaManagerCounter = 0;
 
@@ -185,10 +186,9 @@ abstract class MediaManager<TOptions extends MediaManagerOptions = MediaManagerO
           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);
+        EventHandler.add("WoltLabSuite/Core/Ui/Object/Action", "delete", (data: ObjectActionData) =>
+          this.removeMedia(~~data.objectElement.dataset.objectId!),
+        );
       }
 
       if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
@@ -523,12 +523,12 @@ abstract class MediaManager<TOptions extends MediaManagerOptions = MediaManagerO
         </a>`;
 
       const deleteButton = document.createElement("li");
-      deleteButton.className = "jsDeleteButton";
-      deleteButton.dataset.objectId = media.mediaID.toString();
+      deleteButton.classList.add("jsObjectAction");
+      deleteButton.dataset.objectAction = "delete";
 
       // use temporary title to not unescape html in filename
       const uuid = Core.getUuid();
-      deleteButton.dataset.confirmMessageHtml = StringUtil.unescapeHTML(
+      deleteButton.dataset.confirmMessage = StringUtil.unescapeHTML(
         Language.get("wcf.media.delete.confirmMessage", {
           title: uuid,
         }),
index b0c13b10b4b5d7173821e2ccb950cb2f4edbbc65..bc90b9ef78d7243acd373136c561726e7ab8e916 100644 (file)
@@ -87,12 +87,11 @@ class MediaUpload<TOptions extends MediaUploadOptions = MediaUploadOptions> exte
           cell.querySelectorAll("[data-object-id]").forEach((el: HTMLElement) => DomUtil.hide(el));
 
           cell.querySelector(".mediaEditButton")!.classList.add("jsMediaEditButton");
-          (cell.querySelector(".jsDeleteButton") as HTMLElement).dataset.confirmMessageHtml = Language.get(
-            "wcf.media.delete.confirmMessage",
-            {
-              title: file.name,
-            },
-          );
+          (cell.querySelector(
+            ".jsObjectAction[data-object-action='delete']",
+          ) as HTMLElement).dataset.confirmMessage = 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");
@@ -210,6 +209,7 @@ class MediaUpload<TOptions extends MediaUploadOptions = MediaUploadOptions> exte
       if (file.tagName === "TR") {
         if (media) {
           // update object id
+          file.dataset.objectId = media.mediaID.toString();
           file.querySelectorAll("[data-object-id]").forEach((el: HTMLElement) => {
             el.dataset.objectId = media.mediaID.toString();
             el.style.removeProperty("display");
@@ -259,7 +259,7 @@ class MediaUpload<TOptions extends MediaUploadOptions = MediaUploadOptions> exte
           const fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaThumbnail")!, "SPAN")!;
           this._replaceFileIcon(fileIcon, media, 144);
 
-          file.className = "jsClipboardObject mediaFile";
+          file.classList.add("jsClipboardObject", "mediaFile", "jsObjectActionObject");
           file.dataset.objectId = media.mediaID.toString();
 
           if (this._mediaManager) {
index 8f025ed1ea2d61ec7b5eca35c874b4d7d3d34ba7..6898602dc5a002fe8612bd365bc106a0614bd8ab 100644 (file)
@@ -36,6 +36,7 @@ function observeElements(): void {
     });
   });
 }
+
 export function setup(): void {
   observeElements();
   DomChangeListener.add("WoltLabSuite/Core/Ui/Empty", () => observeElements());
index f5d965e9da6c2a0f90c72a445c4eb2137078c83c..6c1d35fc519d5b698efb56ba0302132d28fb2e59 100644 (file)
@@ -14,6 +14,7 @@ import { ObjectActionData } from "./Data";
 import * as UiConfirmation from "../Confirmation";
 import * as Language from "../../Language";
 import * as StringUtil from "../../StringUtil";
+import DomChangeListener from "../../Dom/Change/Listener";
 
 const containerSelector = ".jsObjectActionContainer[data-object-action-class-name]";
 const objectSelector = ".jsObjectActionObject[data-object-id]";
@@ -89,12 +90,21 @@ function processAction(actionElement: HTMLElement, data: ResponseData | Database
   } as ObjectActionData);
 }
 
-export function setup(): void {
+const actions = new Set<HTMLElement>();
+
+function registerElements(): void {
   document
     .querySelectorAll(`${containerSelector} ${objectSelector} ${actionSelector}`)
     .forEach((action: HTMLElement) => {
-      action.addEventListener("click", (ev) => executeAction(ev));
+      if (!actions.has(action)) {
+        action.addEventListener("click", (ev) => executeAction(ev));
+
+        actions.add(action);
+      }
     });
+}
 
-  // TODO: handle elements added later on
+export function setup(): void {
+  registerElements();
+  DomChangeListener.add("WoltLabSuite/Core/Ui/Empty", () => registerElements());
 }
index d185200341e40319c91c9beb0cf497a28c863db7..ea0e64ee3b24680a187da355d2781cf3ec634164 100644 (file)
 {/hascontent}
 
 <div class="section tabularBox"{if !$objects|count} style="display: none;{/if}">
-       <table class="table jsClipboardContainer" data-type="com.woltlab.wcf.media">
+       <table class="table jsClipboardContainer jsObjectActionContainer" data-object-action-class-name="wcf\data\media\MediaAction" data-type="com.woltlab.wcf.media">
                <thead>
                        <tr>
                                <th class="columnMark"><label><input type="checkbox" class="jsClipboardMarkAll"></label></th>
                        </tr>
                </thead>
                
-               <tbody id="mediaListTableBody" data-no-items-info="noItemsInfo">
+               <tbody class="jsReloadPageWhenEmpty" id="mediaListTableBody" data-no-items-info="noItemsInfo">
                        {foreach from=$objects item=media}
-                               <tr class="jsMediaRow jsClipboardObject">
+                               <tr class="jsMediaRow jsClipboardObject jsObjectActionObject" data-object-id="{@$media->getObjectID()}">
                                        <td class="columnMark"><input type="checkbox" class="jsClipboardItem" data-object-id="{@$media->mediaID}"></td>
                                        <td class="columnIcon">
                                                <span class="icon icon16 fa-pencil mediaEditButton jsMediaEditButton jsTooltip pointer" title="{lang}wcf.global.button.edit{/lang}" data-object-id="{@$media->mediaID}"></span>
-                                               <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$media->mediaID}" data-confirm-message-html="{lang title=$media->filename __encode=true}wcf.media.delete.confirmMessage{/lang}"></span>
+                                               {objectAction action="delete" objectTitle=$media->filename}
                                                
                                                {event name='rowButtons'}
                                        </td>
                                        {event name='columns'}
                                </tr>
                        {foreachelse}
-                               <tr class="jsMediaRow jsClipboardObject">
+                               <tr class="jsMediaRow jsClipboardObject jsObjectActionObject" data-object-id="0">
                                        <td class="columnMark"><input type="checkbox" class="jsClipboardItem" data-object-id="0"></td>
                                        <td class="columnIcon">
                                                <span class="icon icon16 fa-pencil mediaEditButton jsMediaEditButton jsTooltip pointer" title="{lang}wcf.global.button.edit{/lang}" data-object-id="0"></span>
-                                               <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="0"></span>
+                                               {objectAction action="delete" confirmMessage=""}
                                                
                                                {event name='rowButtons'}
                                        </td>
index 189b3b4f57f4984ad5ad3e8d39d7b84d280ea03e..8943c87e303cb306d2e8814309ff696e770aaf2f 100644 (file)
@@ -1,5 +1,5 @@
 {foreach from=$mediaList item=media}
-       <li class="jsClipboardObject mediaFile" data-object-id="{@$media->mediaID}">
+       <li class="jsClipboardObject mediaFile jsObjectActionObject" data-object-id="{@$media->getObjectID()}">
                <div class="mediaThumbnail">
                        {@$media->getElementTag(144)}
                </div>
@@ -21,7 +21,7 @@
                                        <li class="jsMediaEditButton" data-object-id="{@$media->mediaID}">
                                                <a><span class="icon icon16 fa-pencil jsTooltip" title="{lang}wcf.global.button.edit{/lang}"></span> <span class="invisible">{lang}wcf.global.button.edit{/lang}</span></a>
                                        </li>
-                                       <li class="jsDeleteButton" data-object-id="{@$media->mediaID}" data-confirm-message-html="{lang title=$__mediaTitle __encode=true}wcf.media.delete.confirmMessage{/lang}">
+                                       <li class="jsObjectAction" data-object-action="delete" data-confirm-message="{lang title=$__mediaTitle __encode=true}wcf.media.delete.confirmMessage{/lang}">
                                                <a><span class="icon icon16 fa-times jsTooltip" title="{lang}wcf.global.button.delete{/lang}"></span> <span class="invisible">{lang}wcf.global.button.delete{/lang}</span></a>
                                        </li>
                                {/if}
index 2dc7d4828ca242601524d949a99ba58fbfc07ea4..9fe55be085aa65277dbeeb45d000904f266432b2 100644 (file)
@@ -37,7 +37,7 @@
 
 <div class="jsClipboardContainer" data-type="com.woltlab.wcf.media">
        <input type="checkbox" class="jsClipboardMarkAll" style="display: none;">
-       <ul class="mediaManagerMediaList">
+       <ul class="mediaManagerMediaList jsObjectActionContainer" data-object-action-class-name="wcf\data\media\MediaAction">
                {include file='mediaListItems'}
        </ul>
 </div>
index 3431bca9fe076bab6f645afa88a0e95d1c2d4778..a032a41dd6429d68266af50f579734baee289298 100644 (file)
@@ -37,11 +37,6 @@ define(["require", "exports", "tslib", "../../Media/List/Upload", "../../Media/C
         MediaClipboard.init("wcf\\acp\\page\\MediaListPage", options.hasMarkedItems || false, {
             clipboardDeleteMedia: (mediaIds) => clipboardDeleteMedia(mediaIds),
         });
-        EventHandler.add("com.woltlab.wcf.media.upload", "removedErroneousUploadRow", () => deleteCallback());
-        // eslint-disable-next-line
-        //@ts-ignore
-        const deleteAction = new WCF.Action.Delete("wcf\\data\\media\\MediaAction", ".jsMediaRow");
-        deleteAction.setCallback(deleteCallback);
         addButtonEventListeners();
         DomChangeListener.add("WoltLabSuite/Core/Controller/Media/List", () => addButtonEventListeners());
         EventHandler.add("com.woltlab.wcf.media.upload", "success", (data) => openEditorAfterUpload(data));
index b672d5adbe9002dc91c25ed5782007e8c89693fe..58f030eda9417ae27bad6acc17d21b4a5d7a5a19 100644 (file)
@@ -140,10 +140,7 @@ define(["require", "exports", "tslib", "../../Core", "../../Language", "../../Pe
                     this._upload = new Upload_1.default(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);
+                    EventHandler.add("WoltLabSuite/Core/Ui/Object/Action", "delete", (data) => this.removeMedia(~~data.objectElement.dataset.objectId));
                 }
                 if (Permission.get("admin.content.cms.canManageMedia") || this._forceClipboard) {
                     MediaClipboard.init("menuManagerDialog-" + this.getMode(), this._hadInitiallyMarkedItems ? true : false, this);
@@ -424,11 +421,11 @@ define(["require", "exports", "tslib", "../../Core", "../../Language", "../../Pe
           <span class="invisible">${Language.get("wcf.global.button.edit")}</span>
         </a>`;
                 const deleteButton = document.createElement("li");
-                deleteButton.className = "jsDeleteButton";
-                deleteButton.dataset.objectId = media.mediaID.toString();
+                deleteButton.classList.add("jsObjectAction");
+                deleteButton.dataset.objectAction = "delete";
                 // use temporary title to not unescape html in filename
                 const uuid = Core.getUuid();
-                deleteButton.dataset.confirmMessageHtml = StringUtil.unescapeHTML(Language.get("wcf.media.delete.confirmMessage", {
+                deleteButton.dataset.confirmMessage = StringUtil.unescapeHTML(Language.get("wcf.media.delete.confirmMessage", {
                     title: uuid,
                 })).replace(uuid, StringUtil.escapeHTML(media.filename));
                 buttons.appendChild(deleteButton);
index 1a72cd6bab63117fd565fa1a16361e94d219ca47..deabea952ffa1cfc5946d3089447dd4d7279826d 100644 (file)
@@ -63,7 +63,7 @@ define(["require", "exports", "tslib", "../Upload", "../Core", "../Dom/Util", ".
                     else if (cell.classList.contains("columnIcon")) {
                         cell.querySelectorAll("[data-object-id]").forEach((el) => DomUtil.hide(el));
                         cell.querySelector(".mediaEditButton").classList.add("jsMediaEditButton");
-                        cell.querySelector(".jsDeleteButton").dataset.confirmMessageHtml = Language.get("wcf.media.delete.confirmMessage", {
+                        cell.querySelector(".jsObjectAction[data-object-action='delete']").dataset.confirmMessage = Language.get("wcf.media.delete.confirmMessage", {
                             title: file.name,
                         });
                     }
@@ -167,6 +167,7 @@ define(["require", "exports", "tslib", "../Upload", "../Core", "../Dom/Util", ".
                 if (file.tagName === "TR") {
                     if (media) {
                         // update object id
+                        file.dataset.objectId = media.mediaID.toString();
                         file.querySelectorAll("[data-object-id]").forEach((el) => {
                             el.dataset.objectId = media.mediaID.toString();
                             el.style.removeProperty("display");
@@ -205,7 +206,7 @@ define(["require", "exports", "tslib", "../Upload", "../Core", "../Dom/Util", ".
                     if (media) {
                         const fileIcon = DomTraverse.childByTag(DomTraverse.childByClass(file, "mediaThumbnail"), "SPAN");
                         this._replaceFileIcon(fileIcon, media, 144);
-                        file.className = "jsClipboardObject mediaFile";
+                        file.classList.add("jsClipboardObject", "mediaFile", "jsObjectActionObject");
                         file.dataset.objectId = media.mediaID.toString();
                         if (this._mediaManager) {
                             this._mediaManager.setupMediaElement(media, file);
index 5aca3d4f7d24691e42f1cddb0e650dacc268c8a0..45e4cef49006cb665b32ee1572d40623699004c2 100644 (file)
@@ -6,7 +6,7 @@
  * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @module  WoltLabSuite/Core/Ui/Object/Action
  */
-define(["require", "exports", "tslib", "../../Ajax", "../../Event/Handler", "../Confirmation", "../../Language", "../../StringUtil"], function (require, exports, tslib_1, Ajax, EventHandler, UiConfirmation, Language, StringUtil) {
+define(["require", "exports", "tslib", "../../Ajax", "../../Event/Handler", "../Confirmation", "../../Language", "../../StringUtil", "../../Dom/Change/Listener"], function (require, exports, tslib_1, Ajax, EventHandler, UiConfirmation, Language, StringUtil, Listener_1) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.setup = void 0;
@@ -15,6 +15,7 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Event/Handler", "../
     UiConfirmation = tslib_1.__importStar(UiConfirmation);
     Language = tslib_1.__importStar(Language);
     StringUtil = tslib_1.__importStar(StringUtil);
+    Listener_1 = tslib_1.__importDefault(Listener_1);
     const containerSelector = ".jsObjectActionContainer[data-object-action-class-name]";
     const objectSelector = ".jsObjectActionObject[data-object-id]";
     const actionSelector = ".jsObjectAction[data-object-action]";
@@ -80,13 +81,20 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Event/Handler", "../
             objectElement: actionElement.closest(objectSelector),
         });
     }
-    function setup() {
+    const actions = new Set();
+    function registerElements() {
         document
             .querySelectorAll(`${containerSelector} ${objectSelector} ${actionSelector}`)
             .forEach((action) => {
-            action.addEventListener("click", (ev) => executeAction(ev));
+            if (!actions.has(action)) {
+                action.addEventListener("click", (ev) => executeAction(ev));
+                actions.add(action);
+            }
         });
-        // TODO: handle elements added later on
+    }
+    function setup() {
+        registerElements();
+        Listener_1.default.add("WoltLabSuite/Core/Ui/Empty", () => registerElements());
     }
     exports.setup = setup;
 });