Allow intermediate owners to drop ownership of the page overlay
authorAlexander Ebert <ebert@woltlab.com>
Wed, 16 Aug 2023 13:22:57 +0000 (15:22 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 16 Aug 2023 13:22:57 +0000 (15:22 +0200)
Fixes WoltLab/editor#85

ts/WoltLabSuite/Core/Helper/PageOverlay.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Helper/PageOverlay.js

index b2bf4c0521318119666d7b300837a523fabda13c..b692396eb404857b08cb1694480a52afa1768a9f 100644 (file)
@@ -21,30 +21,36 @@ export function adoptPageOverlayContainer(element: HTMLElement): void {
  * in reverse order to ensure the correct placement.
  */
 export function releasePageOverlayContainer(element: HTMLElement): void {
-  const currentParent = adoptiveParents.pop();
-  if (element !== currentParent) {
-    // TODO: `cause` is cast to `any` as a work-around for TS2322
-    //       https://github.com/microsoft/TypeScript/pull/49639
-    throw new Error("Invalid call, cannot release the page overlay while it is still adopted by another element.", {
+  if (!adoptiveParents.includes(element)) {
+    throw new Error("Cannot release the page overlay from a container that (no longer) adopts it.", {
       cause: {
-        currentParent,
         element,
-      } as any,
+      },
     });
   }
 
-  const previousParent = adoptiveParents[adoptiveParents.length - 1];
-  if (previousParent === undefined) {
-    // TODO: `cause` is cast to `any` as a work-around for TS2322
-    //       https://github.com/microsoft/TypeScript/pull/49639
+  const index = adoptiveParents.indexOf(element);
+  if (index === 0) {
     throw new Error("Cannot release the page overlay, there is no previous owner.", {
       cause: {
         element,
-      } as any,
+      },
     });
   }
 
-  previousParent.append(container);
+  if (index === adoptiveParents.length - 1) {
+    adoptiveParents.pop();
+
+    const previousParent = adoptiveParents[adoptiveParents.length - 1];
+    previousParent.append(container);
+
+    return;
+  }
+
+  // `element` was an intermediate owner but is no longer holding a reference
+  // to it. This can happen when there are nested dialogs and the parent dialog
+  // is disposed while the new dialog is being shown.
+  adoptiveParents.splice(index, 1);
 }
 
 /**
index 57eb0a8fabbf024d8a3c558676c57db894ca7e36..c728f9a57ae5cfb93663cdaa9e25fa9468299471 100644 (file)
@@ -22,28 +22,31 @@ define(["require", "exports"], function (require, exports) {
      * in reverse order to ensure the correct placement.
      */
     function releasePageOverlayContainer(element) {
-        const currentParent = adoptiveParents.pop();
-        if (element !== currentParent) {
-            // TODO: `cause` is cast to `any` as a work-around for TS2322
-            //       https://github.com/microsoft/TypeScript/pull/49639
-            throw new Error("Invalid call, cannot release the page overlay while it is still adopted by another element.", {
+        if (!adoptiveParents.includes(element)) {
+            throw new Error("Cannot release the page overlay from a container that (no longer) adopts it.", {
                 cause: {
-                    currentParent,
                     element,
                 },
             });
         }
-        const previousParent = adoptiveParents[adoptiveParents.length - 1];
-        if (previousParent === undefined) {
-            // TODO: `cause` is cast to `any` as a work-around for TS2322
-            //       https://github.com/microsoft/TypeScript/pull/49639
+        const index = adoptiveParents.indexOf(element);
+        if (index === 0) {
             throw new Error("Cannot release the page overlay, there is no previous owner.", {
                 cause: {
                     element,
                 },
             });
         }
-        previousParent.append(container);
+        if (index === adoptiveParents.length - 1) {
+            adoptiveParents.pop();
+            const previousParent = adoptiveParents[adoptiveParents.length - 1];
+            previousParent.append(container);
+            return;
+        }
+        // `element` was an intermediate owner but is no longer holding a reference
+        // to it. This can happen when there are nested dialogs and the parent dialog
+        // is disposed while the new dialog is being shown.
+        adoptiveParents.splice(index, 1);
     }
     exports.releasePageOverlayContainer = releasePageOverlayContainer;
     /**