Reverse the event logic
authorAlexander Ebert <ebert@woltlab.com>
Thu, 19 Dec 2024 19:14:42 +0000 (20:14 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 19 Dec 2024 19:14:42 +0000 (20:14 +0100)
This also avoids calling into `$moveTo` from within the `change` event which could cause a nasty loop.

ts/WoltLabSuite/Core/Component/Image/Cropper.ts
wcfsetup/install/files/js/WoltLabSuite/Core/Component/Image/Cropper.js

index 85d8319da6c9faeeddf3324e9005cffa923fa2f0..3b230dc3e639732c12fcd16386026afbd286aec6 100644 (file)
@@ -200,35 +200,11 @@ abstract class ImageCropper {
 
     this.centerSelection();
 
-    // Limit the selection to the canvas boundaries
-    this.cropperSelection!.addEventListener("change", (event: CustomEvent) => {
-      // see https://fengyuanchen.github.io/cropperjs/v2/api/cropper-selection.html#limit-boundaries
-      const cropperCanvasRect = this.cropperCanvas!.getBoundingClientRect();
-      const selection = event.detail as Selection;
-
-      const maxSelection: Selection = {
-        x: 0,
-        y: 0,
-        width: cropperCanvasRect.width,
-        height: cropperCanvasRect.height,
-      };
-
-      if (!inSelection(selection, maxSelection)) {
-        event.preventDefault();
-
-        // Try to clamp the position to the boundaries.
-        this.cropperSelection!.$moveTo(
-          clampValue(selection.x, selection.width, maxSelection.width),
-          clampValue(selection.y, selection.height, maxSelection.height),
-        );
-      }
-    });
-
-    // Limit the selection to the min/max size
     this.cropperSelection!.addEventListener("change", (event: CustomEvent) => {
       const selection = event.detail as Selection;
       this.cropperCanvasRect = this.cropperCanvas!.getBoundingClientRect();
 
+      // Limit the selection to the min/max size.
       const selectionRatio = Math.min(
         this.cropperCanvasRect.width / this.width,
         this.cropperCanvasRect.height / this.height,
@@ -246,6 +222,33 @@ abstract class ImageCropper {
 
       if (width < minWidth || height < minHeight || width > maxWidth || height > maxHeight) {
         event.preventDefault();
+
+        // Stop the event handling here otherwise the following code would try
+        // to adjust the position on an invalid size that could potentially
+        // violate the boundaries.
+        return;
+      }
+
+      // Limit the selection to the canvas boundaries.
+      // see https://fengyuanchen.github.io/cropperjs/v2/api/cropper-selection.html#limit-boundaries
+      const maxSelection: Selection = {
+        x: 0,
+        y: 0,
+        width: this.cropperCanvasRect!.width,
+        height: this.cropperCanvasRect!.height,
+      };
+
+      if (!inSelection(selection, maxSelection)) {
+        event.preventDefault();
+
+        // Clamp the position to the boundaries of the canvas.
+        this.cropperSelection!.x = clampValue(selection.x, selection.width, maxSelection.width);
+        this.cropperSelection!.y = clampValue(selection.y, selection.height, maxSelection.height);
+
+        this.cropperSelection!.width = selection.width;
+        this.cropperSelection!.height = selection.height;
+
+        this.cropperSelection!.$render();
       }
     });
   }
index 6f209bc62d8e19629821c3230aff652f7d79b85a..28648311ed1b9f5f00930195e9b1c07022465d12 100644 (file)
@@ -150,27 +150,10 @@ define(["require", "exports", "tslib", "WoltLabSuite/Core/Image/Resizer", "WoltL
                 this.cropperImage.$rotate(`${this.orientation}deg`);
             }
             this.centerSelection();
-            // Limit the selection to the canvas boundaries
-            this.cropperSelection.addEventListener("change", (event) => {
-                // see https://fengyuanchen.github.io/cropperjs/v2/api/cropper-selection.html#limit-boundaries
-                const cropperCanvasRect = this.cropperCanvas.getBoundingClientRect();
-                const selection = event.detail;
-                const maxSelection = {
-                    x: 0,
-                    y: 0,
-                    width: cropperCanvasRect.width,
-                    height: cropperCanvasRect.height,
-                };
-                if (!inSelection(selection, maxSelection)) {
-                    event.preventDefault();
-                    // Try to clamp the position to the boundaries.
-                    this.cropperSelection.$moveTo(clampValue(selection.x, selection.width, maxSelection.width), clampValue(selection.y, selection.height, maxSelection.height));
-                }
-            });
-            // Limit the selection to the min/max size
             this.cropperSelection.addEventListener("change", (event) => {
                 const selection = event.detail;
                 this.cropperCanvasRect = this.cropperCanvas.getBoundingClientRect();
+                // Limit the selection to the min/max size.
                 const selectionRatio = Math.min(this.cropperCanvasRect.width / this.width, this.cropperCanvasRect.height / this.height);
                 // Round all values to integers to avoid dealing with the wonderful world
                 // of IEEE 754 numbers.
@@ -182,6 +165,27 @@ define(["require", "exports", "tslib", "WoltLabSuite/Core/Image/Resizer", "WoltL
                 const height = Math.round(selection.height);
                 if (width < minWidth || height < minHeight || width > maxWidth || height > maxHeight) {
                     event.preventDefault();
+                    // Stop the event handling here otherwise the following code would try
+                    // to adjust the position on an invalid size that could potentially
+                    // violate the boundaries.
+                    return;
+                }
+                // Limit the selection to the canvas boundaries.
+                // see https://fengyuanchen.github.io/cropperjs/v2/api/cropper-selection.html#limit-boundaries
+                const maxSelection = {
+                    x: 0,
+                    y: 0,
+                    width: this.cropperCanvasRect.width,
+                    height: this.cropperCanvasRect.height,
+                };
+                if (!inSelection(selection, maxSelection)) {
+                    event.preventDefault();
+                    // Clamp the position to the boundaries of the canvas.
+                    this.cropperSelection.x = clampValue(selection.x, selection.width, maxSelection.width);
+                    this.cropperSelection.y = clampValue(selection.y, selection.height, maxSelection.height);
+                    this.cropperSelection.width = selection.width;
+                    this.cropperSelection.height = selection.height;
+                    this.cropperSelection.$render();
                 }
             });
         }