Change cover photo instantly when a new file is uploaded or deleted
authorCyperghost <olaf_schmitz_1@t-online.de>
Wed, 18 Dec 2024 10:13:17 +0000 (11:13 +0100)
committerCyperghost <olaf_schmitz_1@t-online.de>
Wed, 18 Dec 2024 10:13:17 +0000 (11:13 +0100)
com.woltlab.wcf/templates/userProfileHeader.tpl
ts/WoltLabSuite/Core/Component/User/CoverPhoto.ts
wcfsetup/install/files/acp/templates/userAdd.tpl
wcfsetup/install/files/js/WoltLabSuite/Core/Component/User/CoverPhoto.js
wcfsetup/install/files/lib/data/user/cover/photo/DefaultUserCoverPhoto.class.php
wcfsetup/install/files/lib/data/user/cover/photo/IUserCoverPhoto.class.php
wcfsetup/install/files/lib/data/user/cover/photo/UserCoverPhoto.class.php

index e9dcca9213dc8bb71499efa77aa97fe3e475d026..cdc58d0d8008118d126ec9d85f1ad300676b6c6a 100644 (file)
@@ -21,7 +21,7 @@
 >
        <div class="userProfileHeader__coverPhotoContainer">
                <div class="userProfileHeader__coverPhoto">
-                       <img src="{$view->user->getCoverPhoto()->getURL()}" class="userProfileHeader__coverPhotoImage">
+                       <img src="{$view->user->getCoverPhoto()->getURL()}" data-object-id="{$view->user->getCoverPhoto()->getObjectID()}" class="userProfileHeader__coverPhotoImage">
                </div>
                
                <div class="userProfileHeader__manageButtons">
index 1bd2e52b898bea8e0cff527911a6bdbeaed6ff47..b19674a7d307cd27b87ae5a4ee58dd9088280c5d 100644 (file)
@@ -14,11 +14,12 @@ import { dialogFactory } from "WoltLabSuite/Core/Component/Dialog";
 import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
 import { show as showNotification } from "WoltLabSuite/Core/Ui/Notification";
 import * as FormBuilderManager from "WoltLabSuite/Core/Form/Builder/Manager";
-import WoltlabCoreFile from "WoltLabSuite/Core/Component/File/woltlab-core-file";
 import { fire as fireEvent } from "WoltLabSuite/Core/Event/Handler";
 import { getPhrase } from "WoltLabSuite/Core/Language";
 import DomUtil from "WoltLabSuite/Core/Dom/Util";
 import { escapeHTML } from "WoltLabSuite/Core/StringUtil";
+import { registerCallback } from "WoltLabSuite/Core/Form/Builder/Field/Controller/FileProcessor";
+import WoltlabCoreFile from "WoltLabSuite/Core/Component/File/woltlab-core-file";
 
 type ResponseGetForm = {
   dialog: string;
@@ -27,65 +28,18 @@ type ResponseGetForm = {
 };
 
 async function editCoverPhoto(button: HTMLElement): Promise<void> {
-  const defaultCoverPhoto = button.dataset.defaultCoverPhoto;
   const json = (await prepareRequest(button.dataset.editCoverPhoto!).get().fetchAsJson()) as ResponseGetForm;
   const dialog = dialogFactory().fromHtml(json.dialog).withoutControls();
-  const coverPhotoElement = getCoverPhotoElement();
-  const coverPhotoNotice = document.getElementById("coverPhotoNotice");
-  const oldCoverPhoto = getCoverPhotoUrl(coverPhotoElement);
 
   dialog.addEventListener("afterClose", () => {
-    const file = dialog.querySelector<WoltlabCoreFile>("woltlab-core-file");
-    const coverPhotoUrl = file?.link ?? defaultCoverPhoto ?? "";
-    const coverPhotoStyle = `url("${coverPhotoUrl}")`;
-
     if (FormBuilderManager.hasForm(json.formId)) {
       FormBuilderManager.unregisterForm(json.formId);
     }
-
-    if (oldCoverPhoto === coverPhotoUrl || oldCoverPhoto === coverPhotoStyle) {
-      // nothing changed
-      return;
-    }
-
-    if (coverPhotoElement instanceof HTMLImageElement && coverPhotoUrl) {
-      coverPhotoElement.src = coverPhotoUrl;
-    } else {
-      // ACP cover photo management
-      if (!coverPhotoElement && coverPhotoUrl) {
-        coverPhotoNotice!.parentElement!.appendChild(
-          DomUtil.createFragmentFromHtml(
-            `<div id="coverPhotoPreview" style="background-image: ${escapeHTML(coverPhotoStyle)};"></div>`,
-          ),
-        );
-        coverPhotoNotice!.remove();
-      } else if (coverPhotoElement && !coverPhotoUrl) {
-        coverPhotoElement.parentElement!.appendChild(
-          DomUtil.createFragmentFromHtml(
-            `<woltlab-core-notice id="coverPhotoNotice" type="info">${getPhrase("wcf.user.coverPhoto.noImage")}</woltlab-core-notice>`,
-          ),
-        );
-        coverPhotoElement.remove();
-      }
-    }
-
-    showNotification();
-    fireEvent("com.woltlab.wcf.user", "coverPhoto", {
-      url: coverPhotoUrl,
-    });
   });
 
   dialog.show(json.title);
 }
 
-function getCoverPhotoUrl(coverPhotoElement: HTMLElement | null): string | undefined {
-  if (coverPhotoElement instanceof HTMLImageElement) {
-    return coverPhotoElement.src;
-  } else {
-    return coverPhotoElement?.style.backgroundImage;
-  }
-}
-
 function getCoverPhotoElement(): HTMLElement | null {
   return (
     document.querySelector<HTMLElement>(".userProfileHeader__coverPhotoImage") ??
@@ -95,6 +49,55 @@ function getCoverPhotoElement(): HTMLElement | null {
 
 export function setup(): void {
   wheneverFirstSeen("[data-edit-cover-photo]", (button) => {
+    const defaultCoverPhoto = button.dataset.defaultCoverPhoto;
+
+    registerCallback("wcf\\action\\UserCoverPhotoAction_coverPhotoFileID", (fileId: number | undefined) => {
+      const coverPhotoElement = getCoverPhotoElement();
+
+      if (coverPhotoElement && parseInt(coverPhotoElement.dataset.objectId!) === fileId) {
+        // nothing changed
+        return;
+      }
+
+      const file = document.querySelector<WoltlabCoreFile>(
+        `#wcf\\\\action\\\\UserCoverPhotoAction_coverPhotoFileIDContainer woltlab-core-file[file-id="${fileId}"]`,
+      );
+      const coverPhotoNotice = document.getElementById("coverPhotoNotice");
+      const coverPhotoUrl = file?.link ?? defaultCoverPhoto ?? "";
+      const coverPhotoStyle = `url("${coverPhotoUrl}")`;
+
+      if (coverPhotoElement instanceof HTMLImageElement && coverPhotoUrl) {
+        coverPhotoElement.src = coverPhotoUrl;
+
+        coverPhotoElement.dataset.objectId = fileId?.toString() || "";
+      } else {
+        // ACP cover photo management
+        if (!coverPhotoElement && coverPhotoUrl) {
+          coverPhotoNotice!.parentElement!.appendChild(
+            DomUtil.createFragmentFromHtml(
+              `<div id="coverPhotoPreview" data-object-id="${fileId}" style="background-image: ${escapeHTML(coverPhotoStyle)};"></div>`,
+            ),
+          );
+          coverPhotoNotice!.remove();
+        } else if (coverPhotoElement && !coverPhotoUrl) {
+          coverPhotoElement.parentElement!.appendChild(
+            DomUtil.createFragmentFromHtml(
+              `<woltlab-core-notice id="coverPhotoNotice" type="info">${getPhrase("wcf.user.coverPhoto.noImage")}</woltlab-core-notice>`,
+            ),
+          );
+          coverPhotoElement.remove();
+        } else if (coverPhotoElement && coverPhotoUrl) {
+          coverPhotoElement.style.backgroundImage = coverPhotoStyle;
+          coverPhotoElement.dataset.objectId = fileId?.toString() || "";
+        }
+      }
+
+      showNotification();
+      fireEvent("com.woltlab.wcf.user", "coverPhoto", {
+        url: coverPhotoUrl,
+      });
+    });
+
     button.addEventListener(
       "click",
       promiseMutex(() => editCoverPhoto(button)),
index eb7b38bb4ea6c073de727f7e98ef807c1f7b6034..5fd96b3a774200d2fcfcacfe1317d847912b622e 100644 (file)
                                                <dt></dt>
                                                <dd>
                                                        {if $userCoverPhoto}
-                                                               <div id="coverPhotoPreview" style="background-image: url({$userCoverPhoto->getURL()})"></div>
+                                                               <div id="coverPhotoPreview" data-object-id="{$userCoverPhoto->getObjectID()}" style="background-image: url({$userCoverPhoto->getURL()})"></div>
                                                        {else}
                                                                <woltlab-core-notice id="coverPhotoNotice" type="info">{lang}wcf.user.coverPhoto.noImage{/lang}</woltlab-core-notice>
                                                        {/if}
index df15562c2876ea7e277d837e7e120c46f7386879..62c7ddc65df2b8bc0fcb96afd23006dca7d989b4 100644 (file)
@@ -7,65 +7,63 @@
  * @since     6.2
  * @woltlabExcludeBundle all
  */
-define(["require", "exports", "tslib", "WoltLabSuite/Core/Helper/PromiseMutex", "WoltLabSuite/Core/Helper/Selector", "WoltLabSuite/Core/Component/Dialog", "WoltLabSuite/Core/Ajax/Backend", "WoltLabSuite/Core/Ui/Notification", "WoltLabSuite/Core/Form/Builder/Manager", "WoltLabSuite/Core/Event/Handler", "WoltLabSuite/Core/Language", "WoltLabSuite/Core/Dom/Util", "WoltLabSuite/Core/StringUtil"], function (require, exports, tslib_1, PromiseMutex_1, Selector_1, Dialog_1, Backend_1, Notification_1, FormBuilderManager, Handler_1, Language_1, Util_1, StringUtil_1) {
+define(["require", "exports", "tslib", "WoltLabSuite/Core/Helper/PromiseMutex", "WoltLabSuite/Core/Helper/Selector", "WoltLabSuite/Core/Component/Dialog", "WoltLabSuite/Core/Ajax/Backend", "WoltLabSuite/Core/Ui/Notification", "WoltLabSuite/Core/Form/Builder/Manager", "WoltLabSuite/Core/Event/Handler", "WoltLabSuite/Core/Language", "WoltLabSuite/Core/Dom/Util", "WoltLabSuite/Core/StringUtil", "WoltLabSuite/Core/Form/Builder/Field/Controller/FileProcessor"], function (require, exports, tslib_1, PromiseMutex_1, Selector_1, Dialog_1, Backend_1, Notification_1, FormBuilderManager, Handler_1, Language_1, Util_1, StringUtil_1, FileProcessor_1) {
     "use strict";
     Object.defineProperty(exports, "__esModule", { value: true });
     exports.setup = setup;
     FormBuilderManager = tslib_1.__importStar(FormBuilderManager);
     Util_1 = tslib_1.__importDefault(Util_1);
     async function editCoverPhoto(button) {
-        const defaultCoverPhoto = button.dataset.defaultCoverPhoto;
         const json = (await (0, Backend_1.prepareRequest)(button.dataset.editCoverPhoto).get().fetchAsJson());
         const dialog = (0, Dialog_1.dialogFactory)().fromHtml(json.dialog).withoutControls();
-        const coverPhotoElement = getCoverPhotoElement();
-        const coverPhotoNotice = document.getElementById("coverPhotoNotice");
-        const oldCoverPhoto = getCoverPhotoUrl(coverPhotoElement);
         dialog.addEventListener("afterClose", () => {
-            const file = dialog.querySelector("woltlab-core-file");
-            const coverPhotoUrl = file?.link ?? defaultCoverPhoto ?? "";
-            const coverPhotoStyle = `url("${coverPhotoUrl}")`;
             if (FormBuilderManager.hasForm(json.formId)) {
                 FormBuilderManager.unregisterForm(json.formId);
             }
-            if (oldCoverPhoto === coverPhotoUrl || oldCoverPhoto === coverPhotoStyle) {
-                // nothing changed
-                return;
-            }
-            if (coverPhotoElement instanceof HTMLImageElement && coverPhotoUrl) {
-                coverPhotoElement.src = coverPhotoUrl;
-            }
-            else {
-                // ACP cover photo management
-                if (!coverPhotoElement && coverPhotoUrl) {
-                    coverPhotoNotice.parentElement.appendChild(Util_1.default.createFragmentFromHtml(`<div id="coverPhotoPreview" style="background-image: ${(0, StringUtil_1.escapeHTML)(coverPhotoStyle)};"></div>`));
-                    coverPhotoNotice.remove();
-                }
-                else if (coverPhotoElement && !coverPhotoUrl) {
-                    coverPhotoElement.parentElement.appendChild(Util_1.default.createFragmentFromHtml(`<woltlab-core-notice id="coverPhotoNotice" type="info">${(0, Language_1.getPhrase)("wcf.user.coverPhoto.noImage")}</woltlab-core-notice>`));
-                    coverPhotoElement.remove();
-                }
-            }
-            (0, Notification_1.show)();
-            (0, Handler_1.fire)("com.woltlab.wcf.user", "coverPhoto", {
-                url: coverPhotoUrl,
-            });
         });
         dialog.show(json.title);
     }
-    function getCoverPhotoUrl(coverPhotoElement) {
-        if (coverPhotoElement instanceof HTMLImageElement) {
-            return coverPhotoElement.src;
-        }
-        else {
-            return coverPhotoElement?.style.backgroundImage;
-        }
-    }
     function getCoverPhotoElement() {
         return (document.querySelector(".userProfileHeader__coverPhotoImage") ??
             document.getElementById("coverPhotoPreview"));
     }
     function setup() {
         (0, Selector_1.wheneverFirstSeen)("[data-edit-cover-photo]", (button) => {
+            const defaultCoverPhoto = button.dataset.defaultCoverPhoto;
+            (0, FileProcessor_1.registerCallback)("wcf\\action\\UserCoverPhotoAction_coverPhotoFileID", (fileId) => {
+                const coverPhotoElement = getCoverPhotoElement();
+                if (coverPhotoElement && parseInt(coverPhotoElement.dataset.objectId) === fileId) {
+                    // nothing changed
+                    return;
+                }
+                const file = document.querySelector(`#wcf\\\\action\\\\UserCoverPhotoAction_coverPhotoFileIDContainer woltlab-core-file[file-id="${fileId}"]`);
+                const coverPhotoNotice = document.getElementById("coverPhotoNotice");
+                const coverPhotoUrl = file?.link ?? defaultCoverPhoto ?? "";
+                const coverPhotoStyle = `url("${coverPhotoUrl}")`;
+                if (coverPhotoElement instanceof HTMLImageElement && coverPhotoUrl) {
+                    coverPhotoElement.src = coverPhotoUrl;
+                    coverPhotoElement.dataset.objectId = fileId?.toString() || "";
+                }
+                else {
+                    // ACP cover photo management
+                    if (!coverPhotoElement && coverPhotoUrl) {
+                        coverPhotoNotice.parentElement.appendChild(Util_1.default.createFragmentFromHtml(`<div id="coverPhotoPreview" data-object-id="${fileId}" style="background-image: ${(0, StringUtil_1.escapeHTML)(coverPhotoStyle)};"></div>`));
+                        coverPhotoNotice.remove();
+                    }
+                    else if (coverPhotoElement && !coverPhotoUrl) {
+                        coverPhotoElement.parentElement.appendChild(Util_1.default.createFragmentFromHtml(`<woltlab-core-notice id="coverPhotoNotice" type="info">${(0, Language_1.getPhrase)("wcf.user.coverPhoto.noImage")}</woltlab-core-notice>`));
+                        coverPhotoElement.remove();
+                    }
+                    else if (coverPhotoElement && coverPhotoUrl) {
+                        coverPhotoElement.style.backgroundImage = coverPhotoStyle;
+                        coverPhotoElement.dataset.objectId = fileId?.toString() || "";
+                    }
+                }
+                (0, Notification_1.show)();
+                (0, Handler_1.fire)("com.woltlab.wcf.user", "coverPhoto", {
+                    url: coverPhotoUrl,
+                });
+            });
             button.addEventListener("click", (0, PromiseMutex_1.promiseMutex)(() => editCoverPhoto(button)));
         });
     }
index 91660d31364cb200481d036a0ff2033ec6e0d4fc..00ad124e03a51a6b4a710ffe405771c161995546 100644 (file)
@@ -44,4 +44,10 @@ class DefaultUserCoverPhoto implements IUserCoverPhoto
     {
         return StyleHandler::getInstance()->getStyle()->getCoverPhoto($forceWebP);
     }
+
+    #[\Override]
+    public function getObjectID(): ?int
+    {
+        return null;
+    }
 }
index ef7c32cdf50be6779419d4675e5611be8c242213..ce1be6d9dd25b6f7c1f4085e952aa7db407f125b 100644 (file)
@@ -30,4 +30,9 @@ interface IUserCoverPhoto
      * Returns the file name of this cover photo.
      */
     public function getFilename(?bool $forceWebP = null): string;
+
+    /**
+     * Returns the object ID of this cover photo.
+     */
+    public function getObjectID(): ?int;
 }
index 87936fa97e18d43d415ff6977814948156481cf5..54aec222da51babaa6bcd81136aeab05bfdbd5bc 100644 (file)
@@ -56,6 +56,12 @@ final class UserCoverPhoto implements IUserCoverPhoto
         return $this->file->filename;
     }
 
+    #[\Override]
+    public function getObjectID(): ?int
+    {
+        return $this->file->fileID;
+    }
+
     /**
      * Returns the minimum and maximum dimensions for cover photos.
      */