From b267a71f2db3418d81b1aeb674d373a43b9fa6de Mon Sep 17 00:00:00 2001 From: Saq Imtiaz Date: Sun, 16 May 2021 15:01:46 +0200 Subject: [PATCH] Dropzone: persistent dragover state fix (#5688) --- core/modules/widgets/dropzone.js | 52 ++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/core/modules/widgets/dropzone.js b/core/modules/widgets/dropzone.js index 70bd2bf2e..1200441ff 100644 --- a/core/modules/widgets/dropzone.js +++ b/core/modules/widgets/dropzone.js @@ -37,6 +37,7 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) { this.execute(); // Create element var domNode = this.document.createElement("div"); + this.domNode = domNode; domNode.className = this.dropzoneClass || "tc-dropzone"; // Add event handlers if(this.dropzoneEnable) { @@ -47,10 +48,8 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) { {name: "drop", handlerObject: this, handlerMethod: "handleDropEvent"}, {name: "paste", handlerObject: this, handlerMethod: "handlePasteEvent"}, {name: "dragend", handlerObject: this, handlerMethod: "handleDragEndEvent"} - ]); + ]); } - domNode.addEventListener("click",function (event) { - },false); // Insert element parent.insertBefore(domNode,nextSibling); this.renderChildren(domNode,null); @@ -59,12 +58,46 @@ DropZoneWidget.prototype.render = function(parent,nextSibling) { this.currentlyEntered = []; }; +// Handler for transient event listeners added when the dropzone has an active drag in progress +DropZoneWidget.prototype.handleEvent = function(event) { + if(event.type === "click") { + if(this.currentlyEntered.length) { + this.resetState(); + } + } else if(event.type === "dragenter") { + if(event.target && event.target !== this.domNode && !$tw.utils.domContains(this.domNode,event.target)) { + this.resetState(); + } + } else if(event.type === "dragleave") { + // Check if drag left the window + if(event.relatedTarget === null || (event.relatedTarget && event.relatedTarget.nodeName === "HTML")) { + this.resetState(); + } + } +}; + +// Reset the state of the dropzone after a drag has ended +DropZoneWidget.prototype.resetState = function() { + $tw.utils.removeClass(this.domNode,"tc-dragover"); + this.currentlyEntered = []; + this.document.body.removeEventListener("click",this,true); + this.document.body.removeEventListener("dragenter",this,true); + this.document.body.removeEventListener("dragleave",this,true); + this.dragInProgress = false; +}; + DropZoneWidget.prototype.enterDrag = function(event) { if(this.currentlyEntered.indexOf(event.target) === -1) { this.currentlyEntered.push(event.target); } - // If we're entering for the first time we need to apply highlighting - $tw.utils.addClass(this.domNodes[0],"tc-dragover"); + if(!this.dragInProgress) { + this.dragInProgress = true; + // If we're entering for the first time we need to apply highlighting + $tw.utils.addClass(this.domNodes[0],"tc-dragover"); + this.document.body.addEventListener("click",this,true); + this.document.body.addEventListener("dragenter",this,true); + this.document.body.addEventListener("dragleave",this,true); + } }; DropZoneWidget.prototype.leaveDrag = function(event) { @@ -74,12 +107,11 @@ DropZoneWidget.prototype.leaveDrag = function(event) { } // Remove highlighting if we're leaving externally if(this.currentlyEntered.length === 0) { - $tw.utils.removeClass(this.domNodes[0],"tc-dragover"); + this.resetState(); } }; DropZoneWidget.prototype.handleDragEnterEvent = function(event) { - // Check for this window being the source of the drag if($tw.dragInProgress) { return false; } @@ -109,7 +141,7 @@ DropZoneWidget.prototype.handleDragLeaveEvent = function(event) { }; DropZoneWidget.prototype.handleDragEndEvent = function(event) { - $tw.utils.removeClass(this.domNodes[0],"tc-dragover"); + this.resetState(); }; DropZoneWidget.prototype.filterByContentTypes = function(tiddlerFieldsArray) { @@ -117,7 +149,7 @@ DropZoneWidget.prototype.filterByContentTypes = function(tiddlerFieldsArray) { filtered = [], types = []; $tw.utils.each(tiddlerFieldsArray,function(tiddlerFields) { - types.push(tiddlerFields.type); + types.push(tiddlerFields.type || ""); }); filteredTypes = this.wiki.filterTiddlers(this.contentTypesFilter,this,this.wiki.makeTiddlerIterator(types)); $tw.utils.each(tiddlerFieldsArray,function(tiddlerFields) { @@ -157,7 +189,7 @@ DropZoneWidget.prototype.handleDropEvent = function(event) { var self = this, dataTransfer = event.dataTransfer; // Remove highlighting - $tw.utils.removeClass(this.domNodes[0],"tc-dragover"); + this.resetState(); // Import any files in the drop var numFiles = 0; if(dataTransfer.files) {