Export `Ui/Redactor/DragAndDrop` to TypeScript
authorAlexander Ebert <ebert@woltlab.com>
Wed, 4 Nov 2020 12:36:22 +0000 (13:36 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 4 Nov 2020 12:36:22 +0000 (13:36 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.js [deleted file]
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.ts [new file with mode: 0644]
wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/Editor.ts

index 42ef5b88115cf5b60f2a739a2d4974e02e148c05..f20bb51347cdaefe955cb7ab01b8938058d464cd 100644 (file)
  * Drag and Drop file uploads.
  *
  * @author      Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @module      WoltLabSuite/Core/Ui/Redactor/DragAndDrop
  */
-define(['Dictionary', 'EventHandler', 'Language'], function (Dictionary, EventHandler, Language) {
+define(["require", "exports", "tslib", "../../Event/Handler", "../../Language"], function (require, exports, tslib_1, EventHandler, Language) {
     "use strict";
-    if (!COMPILER_TARGET_DEFAULT) {
-        var Fake = function () { };
-        Fake.prototype = {
-            init: function () { },
-            _dragOver: function () { },
-            _drop: function () { },
-            _dragLeave: function () { },
-            _setup: function () { }
-        };
-        return Fake;
-    }
-    var _didInit = false;
-    var _dragArea = new Dictionary();
-    var _isDragging = false;
-    var _isFile = false;
-    var _timerLeave = null;
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.init = void 0;
+    EventHandler = tslib_1.__importStar(EventHandler);
+    Language = tslib_1.__importStar(Language);
+    let _didInit = false;
+    const _dragArea = new Map();
+    let _isDragging = false;
+    let _isFile = false;
+    let _timerLeave = null;
     /**
-     * @exports     WoltLabSuite/Core/Ui/Redactor/DragAndDrop
+     * Handles items dragged into the browser window.
      */
-    return {
-        /**
-         * Initializes drag and drop support for provided editor instance.
-         *
-         * @param       {$.Redactor}    editor          editor instance
-         */
-        init: function (editor) {
-            if (!_didInit) {
-                this._setup();
-            }
-            _dragArea.set(editor.uuid, {
-                editor: editor,
-                element: null
-            });
-        },
-        /**
-         * Handles items dragged into the browser window.
-         *
-         * @param       {Event}         event           drag event
-         */
-        _dragOver: function (event) {
-            event.preventDefault();
-            //noinspection JSUnresolvedVariable
-            if (!event.dataTransfer || !event.dataTransfer.types) {
-                return;
+    function _dragOver(event) {
+        event.preventDefault();
+        if (!event.dataTransfer || !event.dataTransfer.types) {
+            return;
+        }
+        let isFirefox = false;
+        Object.keys(event.dataTransfer).forEach((property) => {
+            if (property.startsWith("moz")) {
+                isFirefox = true;
             }
-            var isFirefox = false;
-            //noinspection JSUnresolvedVariable
-            for (var property in event.dataTransfer) {
-                //noinspection JSUnresolvedVariable
-                if (event.dataTransfer.hasOwnProperty(property) && property.match(/^moz/)) {
-                    isFirefox = true;
-                    break;
-                }
+        });
+        // IE and WebKit set 'Files', Firefox sets 'application/x-moz-file' for files being dragged
+        // and Safari just provides 'Files' along with a huge list of garbage
+        _isFile = false;
+        if (isFirefox) {
+            // Firefox sets the 'Files' type even if the user is just dragging an on-page element
+            if (event.dataTransfer.types[0] === "application/x-moz-file") {
+                _isFile = true;
             }
-            // IE and WebKit set 'Files', Firefox sets 'application/x-moz-file' for files being dragged
-            // and Safari just provides 'Files' along with a huge list of garbage
-            _isFile = false;
-            if (isFirefox) {
-                // Firefox sets the 'Files' type even if the user is just dragging an on-page element
-                //noinspection JSUnresolvedVariable
-                if (event.dataTransfer.types[0] === 'application/x-moz-file') {
+        }
+        else {
+            event.dataTransfer.types.forEach((type) => {
+                if (type === "Files") {
                     _isFile = true;
                 }
-            }
-            else {
-                //noinspection JSUnresolvedVariable
-                for (var i = 0; i < event.dataTransfer.types.length; i++) {
-                    //noinspection JSUnresolvedVariable
-                    if (event.dataTransfer.types[i] === 'Files') {
-                        _isFile = true;
-                        break;
-                    }
-                }
-            }
-            if (!_isFile) {
-                // user is just dragging around some garbage, ignore it
-                return;
-            }
-            if (_isDragging) {
-                // user is still dragging the file around
-                return;
-            }
-            _isDragging = true;
-            _dragArea.forEach((function (data, uuid) {
-                var editor = data.editor.$editor[0];
-                if (!editor.parentNode) {
-                    _dragArea.delete(uuid);
-                    return;
-                }
-                var element = data.element;
-                if (element === null) {
-                    element = elCreate('div');
-                    element.className = 'redactorDropArea';
-                    elData(element, 'element-id', data.editor.$element[0].id);
-                    elData(element, 'drop-here', Language.get('wcf.attachment.dragAndDrop.dropHere'));
-                    elData(element, 'drop-now', Language.get('wcf.attachment.dragAndDrop.dropNow'));
-                    element.addEventListener('dragover', function () { element.classList.add('active'); });
-                    element.addEventListener('dragleave', function () { element.classList.remove('active'); });
-                    element.addEventListener('drop', this._drop.bind(this));
-                    data.element = element;
-                }
-                editor.parentNode.insertBefore(element, editor);
-                element.style.setProperty('top', editor.offsetTop + 'px', '');
-            }).bind(this));
-        },
-        /**
-         * Handles items dropped onto an editor's drop area
-         *
-         * @param       {Event}         event           drop event
-         * @protected
-         */
-        _drop: function (event) {
-            if (!_isFile) {
-                return;
-            }
-            //noinspection JSUnresolvedVariable
-            if (!event.dataTransfer || !event.dataTransfer.files.length) {
+            });
+        }
+        if (!_isFile) {
+            // user is just dragging around some garbage, ignore it
+            return;
+        }
+        if (_isDragging) {
+            // user is still dragging the file around
+            return;
+        }
+        _isDragging = true;
+        _dragArea.forEach((data, uuid) => {
+            const editor = data.editor.$editor[0];
+            if (!editor.parentElement) {
+                _dragArea.delete(uuid);
                 return;
             }
-            event.preventDefault();
-            //noinspection JSCheckFunctionSignatures
-            var elementId = elData(event.currentTarget, 'element-id');
-            //noinspection JSUnresolvedVariable
-            for (var i = 0, length = event.dataTransfer.files.length; i < length; i++) {
-                //noinspection JSUnresolvedVariable
-                EventHandler.fire('com.woltlab.wcf.redactor2', 'dragAndDrop_' + elementId, {
-                    file: event.dataTransfer.files[i]
+            let element = data.element;
+            if (element === null) {
+                element = document.createElement("div");
+                element.className = "redactorDropArea";
+                element.dataset.elementId = data.editor.$element[0].id;
+                element.dataset.dropHere = Language.get("wcf.attachment.dragAndDrop.dropHere");
+                element.dataset.dropNow = Language.get("wcf.attachment.dragAndDrop.dropNow");
+                element.addEventListener("dragover", () => {
+                    element.classList.add("active");
                 });
+                element.addEventListener("dragleave", () => {
+                    element.classList.remove("active");
+                });
+                element.addEventListener("drop", (ev) => drop(ev));
+                data.element = element;
             }
-            // this will reset all drop areas
-            this._dragLeave();
-        },
-        /**
-         * Invoked whenever the item is no longer dragged or was dropped.
-         *
-         * @protected
-         */
-        _dragLeave: function () {
-            if (!_isDragging || !_isFile) {
-                return;
-            }
-            if (_timerLeave !== null) {
-                window.clearTimeout(_timerLeave);
-            }
-            _timerLeave = window.setTimeout(function () {
-                if (!_isDragging) {
-                    _dragArea.forEach(function (data) {
-                        if (data.element && data.element.parentNode) {
-                            data.element.classList.remove('active');
-                            elRemove(data.element);
-                        }
-                    });
-                }
-                _timerLeave = null;
-            }, 100);
-            _isDragging = false;
-        },
-        /**
-         * Handles the global drop event.
-         *
-         * @param       {Event}         event
-         * @protected
-         */
-        _globalDrop: function (event) {
-            if (event.target.closest('.redactor-layer') === null) {
-                var eventData = { cancelDrop: true, event: event };
-                _dragArea.forEach(function (data) {
-                    //noinspection JSUnresolvedVariable
-                    EventHandler.fire('com.woltlab.wcf.redactor2', 'dragAndDrop_globalDrop_' + data.editor.$element[0].id, eventData);
+            editor.parentElement.insertBefore(element, editor);
+            element.style.setProperty("top", `${editor.offsetTop}px`, "");
+        });
+    }
+    /**
+     * Handles items dropped onto an editor's drop area
+     */
+    function drop(event) {
+        if (!_isFile) {
+            return;
+        }
+        if (!event.dataTransfer || !event.dataTransfer.files.length) {
+            return;
+        }
+        event.preventDefault();
+        const target = event.currentTarget;
+        const elementId = target.dataset.elementId;
+        Array.from(event.dataTransfer.files).forEach((file) => {
+            EventHandler.fire("com.woltlab.wcf.redactor2", `dragAndDrop_${elementId}`, {
+                file,
+            });
+        });
+        // this will reset all drop areas
+        dragLeave();
+    }
+    /**
+     * Invoked whenever the item is no longer dragged or was dropped.
+     *
+     * @protected
+     */
+    function dragLeave() {
+        if (!_isDragging || !_isFile) {
+            return;
+        }
+        if (_timerLeave !== null) {
+            window.clearTimeout(_timerLeave);
+        }
+        _timerLeave = window.setTimeout(() => {
+            if (!_isDragging) {
+                _dragArea.forEach((data) => {
+                    if (data.element && data.element.parentElement) {
+                        data.element.classList.remove("active");
+                        data.element.remove();
+                    }
                 });
-                if (eventData.cancelDrop) {
-                    event.preventDefault();
-                }
             }
-            this._dragLeave(event);
-        },
-        /**
-         * Binds listeners to global events.
-         *
-         * @protected
-         */
-        _setup: function () {
-            // discard garbage event
-            window.addEventListener('dragend', function (event) { event.preventDefault(); });
-            window.addEventListener('dragover', this._dragOver.bind(this));
-            window.addEventListener('dragleave', this._dragLeave.bind(this));
-            window.addEventListener('drop', this._globalDrop.bind(this));
-            _didInit = true;
+            _timerLeave = null;
+        }, 100);
+        _isDragging = false;
+    }
+    /**
+     * Handles the global drop event.
+     */
+    function globalDrop(event) {
+        const target = event.target;
+        if (target.closest(".redactor-layer") === null) {
+            const eventData = { cancelDrop: true, event: event };
+            _dragArea.forEach((data) => {
+                EventHandler.fire("com.woltlab.wcf.redactor2", `dragAndDrop_globalDrop_${data.editor.$element[0].id}`, eventData);
+            });
+            if (eventData.cancelDrop) {
+                event.preventDefault();
+            }
         }
-    };
+        dragLeave();
+    }
+    /**
+     * Binds listeners to global events.
+     *
+     * @protected
+     */
+    function setup() {
+        // discard garbage event
+        window.addEventListener("dragend", (ev) => ev.preventDefault());
+        window.addEventListener("dragover", (ev) => _dragOver(ev));
+        window.addEventListener("dragleave", () => dragLeave());
+        window.addEventListener("drop", (ev) => globalDrop(ev));
+        _didInit = true;
+    }
+    /**
+     * Initializes drag and drop support for provided editor instance.
+     */
+    function init(editor) {
+        if (!_didInit) {
+            setup();
+        }
+        _dragArea.set(editor.uuid, {
+            editor: editor,
+            element: null,
+        });
+    }
+    exports.init = init;
 });
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.js b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.js
deleted file mode 100644 (file)
index f41f3d6..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/**
- * Drag and Drop file uploads.
- * 
- * @author      Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module      WoltLabSuite/Core/Ui/Redactor/DragAndDrop
- */
-define(['Dictionary', 'EventHandler', 'Language'], function (Dictionary, EventHandler, Language) {
-       "use strict";
-       
-       if (!COMPILER_TARGET_DEFAULT) {
-               var Fake = function() {};
-               Fake.prototype = {
-                       init: function() {},
-                       _dragOver: function() {},
-                       _drop: function() {},
-                       _dragLeave: function() {},
-                       _setup: function() {}
-               };
-               return Fake;
-       }
-       
-       var _didInit = false;
-       var _dragArea = new Dictionary();
-       var _isDragging = false;
-       var _isFile = false;
-       var _timerLeave = null;
-       
-       /**
-        * @exports     WoltLabSuite/Core/Ui/Redactor/DragAndDrop
-        */
-       return {
-               /**
-                * Initializes drag and drop support for provided editor instance.
-                * 
-                * @param       {$.Redactor}    editor          editor instance
-                */
-               init: function (editor) {
-                       if (!_didInit) {
-                               this._setup();
-                       }
-                       
-                       _dragArea.set(editor.uuid, {
-                               editor: editor,
-                               element: null
-                       });
-               },
-               
-               /**
-                * Handles items dragged into the browser window.
-                * 
-                * @param       {Event}         event           drag event
-                */
-               _dragOver: function (event) {
-                       event.preventDefault();
-                       
-                       //noinspection JSUnresolvedVariable
-                       if (!event.dataTransfer || !event.dataTransfer.types) {
-                               return;
-                       }
-                       
-                       var isFirefox = false;
-                       //noinspection JSUnresolvedVariable
-                       for (var property in event.dataTransfer) {
-                               //noinspection JSUnresolvedVariable
-                               if (event.dataTransfer.hasOwnProperty(property) && property.match(/^moz/)) {
-                                       isFirefox = true;
-                                       break;
-                               }
-                       }
-                       
-                       // IE and WebKit set 'Files', Firefox sets 'application/x-moz-file' for files being dragged
-                       // and Safari just provides 'Files' along with a huge list of garbage
-                       _isFile = false;
-                       if (isFirefox) {
-                               // Firefox sets the 'Files' type even if the user is just dragging an on-page element
-                               //noinspection JSUnresolvedVariable
-                               if (event.dataTransfer.types[0] === 'application/x-moz-file') {
-                                       _isFile = true;
-                               }
-                       }
-                       else {
-                               //noinspection JSUnresolvedVariable
-                               for (var i = 0; i < event.dataTransfer.types.length; i++) {
-                                       //noinspection JSUnresolvedVariable
-                                       if (event.dataTransfer.types[i] === 'Files') {
-                                               _isFile = true;
-                                               break;
-                                       }
-                               }
-                       }
-                       
-                       if (!_isFile) {
-                               // user is just dragging around some garbage, ignore it
-                               return;
-                       }
-                       
-                       if (_isDragging) {
-                               // user is still dragging the file around
-                               return;
-                       }
-                       
-                       _isDragging = true;
-                       
-                       _dragArea.forEach((function (data, uuid) {
-                               var editor = data.editor.$editor[0];
-                               if (!editor.parentNode) {
-                                       _dragArea.delete(uuid);
-                                       return;
-                               }
-                               
-                               var element = data.element;
-                               if (element === null) {
-                                       element = elCreate('div');
-                                       element.className = 'redactorDropArea';
-                                       elData(element, 'element-id', data.editor.$element[0].id);
-                                       elData(element, 'drop-here', Language.get('wcf.attachment.dragAndDrop.dropHere'));
-                                       elData(element, 'drop-now', Language.get('wcf.attachment.dragAndDrop.dropNow'));
-                                       
-                                       element.addEventListener('dragover', function () { element.classList.add('active'); });
-                                       element.addEventListener('dragleave', function () { element.classList.remove('active'); });
-                                       element.addEventListener('drop', this._drop.bind(this));
-                                       
-                                       data.element = element;
-                               }
-                               
-                               editor.parentNode.insertBefore(element, editor);
-                               element.style.setProperty('top', editor.offsetTop + 'px', '');
-                       }).bind(this));
-               },
-               
-               /**
-                * Handles items dropped onto an editor's drop area
-                * 
-                * @param       {Event}         event           drop event
-                * @protected
-                */
-               _drop: function (event) {
-                       if (!_isFile) {
-                               return;
-                       }
-                       
-                       //noinspection JSUnresolvedVariable
-                       if (!event.dataTransfer || !event.dataTransfer.files.length) {
-                               return;
-                       }
-                       
-                       event.preventDefault();
-                       
-                       //noinspection JSCheckFunctionSignatures
-                       var elementId = elData(event.currentTarget, 'element-id');
-                       
-                       //noinspection JSUnresolvedVariable
-                       for (var i = 0, length = event.dataTransfer.files.length; i < length; i++) {
-                               //noinspection JSUnresolvedVariable
-                               EventHandler.fire('com.woltlab.wcf.redactor2', 'dragAndDrop_' + elementId, {
-                                       file: event.dataTransfer.files[i]
-                               });
-                       }
-                       
-                       // this will reset all drop areas
-                       this._dragLeave();
-               },
-               
-               /**
-                * Invoked whenever the item is no longer dragged or was dropped.
-                * 
-                * @protected
-                */
-               _dragLeave: function () {
-                       if (!_isDragging || !_isFile) {
-                               return;
-                       }
-                       
-                       if (_timerLeave !== null) {
-                               window.clearTimeout(_timerLeave);
-                       }
-                       
-                       _timerLeave = window.setTimeout(function () {
-                               if (!_isDragging) {
-                                       _dragArea.forEach(function (data) {
-                                               if (data.element && data.element.parentNode) {
-                                                       data.element.classList.remove('active');
-                                                       elRemove(data.element);
-                                               }
-                                       });
-                               }
-                               
-                               _timerLeave = null;
-                       }, 100);
-                       
-                       _isDragging = false;
-               },
-               
-               /**
-                * Handles the global drop event.
-                * 
-                * @param       {Event}         event
-                * @protected
-                */
-               _globalDrop: function (event) {
-                       if (event.target.closest('.redactor-layer') === null) {
-                               var eventData = { cancelDrop: true, event: event };
-                               _dragArea.forEach(function(data) {
-                                       //noinspection JSUnresolvedVariable
-                                       EventHandler.fire('com.woltlab.wcf.redactor2', 'dragAndDrop_globalDrop_' + data.editor.$element[0].id, eventData);
-                               });
-                               
-                               if (eventData.cancelDrop) {
-                                       event.preventDefault();
-                               }
-                       }
-                       
-                       this._dragLeave(event);
-               },
-               
-               /**
-                * Binds listeners to global events.
-                * 
-                * @protected
-                */
-               _setup: function () {
-                       // discard garbage event
-                       window.addEventListener('dragend', function (event) { event.preventDefault(); });
-                       
-                       window.addEventListener('dragover', this._dragOver.bind(this));
-                       window.addEventListener('dragleave', this._dragLeave.bind(this));
-                       window.addEventListener('drop', this._globalDrop.bind(this));
-                       
-                       _didInit = true;
-               }
-       };
-});
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Ui/Redactor/DragAndDrop.ts
new file mode 100644 (file)
index 0000000..a78eaf8
--- /dev/null
@@ -0,0 +1,207 @@
+/**
+ * Drag and Drop file uploads.
+ *
+ * @author      Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license     GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module      WoltLabSuite/Core/Ui/Redactor/DragAndDrop
+ */
+
+import * as EventHandler from "../../Event/Handler";
+import * as Language from "../../Language";
+import { RedactorEditor } from "./Editor";
+
+type Uuid = string;
+
+interface EditorData {
+  editor: RedactorEditor;
+  element: HTMLElement | null;
+}
+
+let _didInit = false;
+const _dragArea = new Map<Uuid, EditorData>();
+let _isDragging = false;
+let _isFile = false;
+let _timerLeave: number | null = null;
+
+/**
+ * Handles items dragged into the browser window.
+ */
+function _dragOver(event: DragEvent): void {
+  event.preventDefault();
+
+  if (!event.dataTransfer || !event.dataTransfer.types) {
+    return;
+  }
+
+  let isFirefox = false;
+  Object.keys(event.dataTransfer).forEach((property) => {
+    if (property.startsWith("moz")) {
+      isFirefox = true;
+    }
+  });
+
+  // IE and WebKit set 'Files', Firefox sets 'application/x-moz-file' for files being dragged
+  // and Safari just provides 'Files' along with a huge list of garbage
+  _isFile = false;
+  if (isFirefox) {
+    // Firefox sets the 'Files' type even if the user is just dragging an on-page element
+    if (event.dataTransfer.types[0] === "application/x-moz-file") {
+      _isFile = true;
+    }
+  } else {
+    event.dataTransfer.types.forEach((type) => {
+      if (type === "Files") {
+        _isFile = true;
+      }
+    });
+  }
+
+  if (!_isFile) {
+    // user is just dragging around some garbage, ignore it
+    return;
+  }
+
+  if (_isDragging) {
+    // user is still dragging the file around
+    return;
+  }
+
+  _isDragging = true;
+
+  _dragArea.forEach((data, uuid) => {
+    const editor = data.editor.$editor[0];
+    if (!editor.parentElement) {
+      _dragArea.delete(uuid);
+      return;
+    }
+
+    let element: HTMLElement | null = data.element;
+    if (element === null) {
+      element = document.createElement("div");
+      element.className = "redactorDropArea";
+      element.dataset.elementId = data.editor.$element[0].id;
+      element.dataset.dropHere = Language.get("wcf.attachment.dragAndDrop.dropHere");
+      element.dataset.dropNow = Language.get("wcf.attachment.dragAndDrop.dropNow");
+
+      element.addEventListener("dragover", () => {
+        element!.classList.add("active");
+      });
+      element.addEventListener("dragleave", () => {
+        element!.classList.remove("active");
+      });
+      element.addEventListener("drop", (ev) => drop(ev));
+
+      data.element = element;
+    }
+
+    editor.parentElement.insertBefore(element, editor);
+    element.style.setProperty("top", `${editor.offsetTop}px`, "");
+  });
+}
+
+/**
+ * Handles items dropped onto an editor's drop area
+ */
+function drop(event: DragEvent): void {
+  if (!_isFile) {
+    return;
+  }
+
+  if (!event.dataTransfer || !event.dataTransfer.files.length) {
+    return;
+  }
+
+  event.preventDefault();
+
+  const target = event.currentTarget as HTMLElement;
+  const elementId = target.dataset.elementId!;
+
+  Array.from(event.dataTransfer.files).forEach((file) => {
+    EventHandler.fire("com.woltlab.wcf.redactor2", `dragAndDrop_${elementId}`, {
+      file,
+    });
+  });
+
+  // this will reset all drop areas
+  dragLeave();
+}
+
+/**
+ * Invoked whenever the item is no longer dragged or was dropped.
+ *
+ * @protected
+ */
+function dragLeave() {
+  if (!_isDragging || !_isFile) {
+    return;
+  }
+
+  if (_timerLeave !== null) {
+    window.clearTimeout(_timerLeave);
+  }
+
+  _timerLeave = window.setTimeout(() => {
+    if (!_isDragging) {
+      _dragArea.forEach((data) => {
+        if (data.element && data.element.parentElement) {
+          data.element.classList.remove("active");
+          data.element.remove();
+        }
+      });
+    }
+
+    _timerLeave = null;
+  }, 100);
+
+  _isDragging = false;
+}
+
+/**
+ * Handles the global drop event.
+ */
+function globalDrop(event: DragEvent): void {
+  const target = event.target as HTMLElement;
+  if (target.closest(".redactor-layer") === null) {
+    const eventData = { cancelDrop: true, event: event };
+    _dragArea.forEach((data) => {
+      EventHandler.fire("com.woltlab.wcf.redactor2", `dragAndDrop_globalDrop_${data.editor.$element[0].id}`, eventData);
+    });
+
+    if (eventData.cancelDrop) {
+      event.preventDefault();
+    }
+  }
+
+  dragLeave();
+}
+
+/**
+ * Binds listeners to global events.
+ *
+ * @protected
+ */
+function setup() {
+  // discard garbage event
+  window.addEventListener("dragend", (ev) => ev.preventDefault());
+
+  window.addEventListener("dragover", (ev) => _dragOver(ev));
+  window.addEventListener("dragleave", () => dragLeave());
+  window.addEventListener("drop", (ev) => globalDrop(ev));
+
+  _didInit = true;
+}
+
+/**
+ * Initializes drag and drop support for provided editor instance.
+ */
+export function init(editor: RedactorEditor): void {
+  if (!_didInit) {
+    setup();
+  }
+
+  _dragArea.set(editor.uuid, {
+    editor: editor,
+    element: null,
+  });
+}
index 757f4d958ea4f30f748a5306b131eb3638a44f04..dbc413cf841486a332e9aa9f8e452821b85a834c 100644 (file)
@@ -1,4 +1,5 @@
 export interface RedactorEditor {
+  uuid: string;
   $editor: JQuery;
   $element: JQuery;