Skip to content
Snippets Groups Projects
Commit 8bb9bed9 authored by Benjamin Kott's avatar Benjamin Kott Committed by Benni Mack
Browse files

[BUGFIX] Correct drag/drop preview position in firefox

Firefox does not update the cursor position on the drag event.
To workaround this issue we are moving the preview update to the
dragover event.

Resolves: #100458
Releases: main
Change-Id: I70eed5196ca68fe2c42c984eeafbf4896e48c683
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/78472


Tested-by: default avatarBenni Mack <benni@typo3.org>
Reviewed-by: default avatarJochen <rothjochen@gmail.com>
Reviewed-by: default avatarBenni Mack <benni@typo3.org>
Tested-by: default avatarcore-ci <typo3@b13.com>
Tested-by: default avatarJochen <rothjochen@gmail.com>
parent 5fe67e8b
Branches
Tags
No related merge requests found
......@@ -81,19 +81,6 @@ class FileListDragDrop {
new RegularEvent('drag', (event: DragEvent): void => {
event.stopPropagation();
if (event.screenX === 0 && event.screenY === 0) {
return;
}
const preview = this.rootDocument.getElementById(this.dragPreviewId);
const calculatedPosition = this.determinePreviewPosition(event);
const currentPosition = preview.getBoundingClientRect();
if (calculatedPosition.left === currentPosition.left && calculatedPosition.top === currentPosition.top) {
return;
}
this.updatePreviewPosition(preview, calculatedPosition);
}, { capture: true, passive: true }).delegateTo(document, selector);
new RegularEvent('dragover', (event: DragEvent, target: HTMLElement): void => {
......@@ -125,6 +112,23 @@ class FileListDragDrop {
event.stopPropagation();
target.classList.remove('success');
}, { capture: true, passive: true }).delegateTo(document, selector);
new RegularEvent('dragover', (event: DragEvent) : void => {
if (event.screenX === 0 && event.screenY === 0) {
return;
}
const preview = this.rootDocument.getElementById(this.dragPreviewId);
if (!preview) {
return;
}
const calculatedPosition = this.determinePreviewPosition(event);
const currentPosition = preview.getBoundingClientRect();
if (calculatedPosition.left === currentPosition.left && calculatedPosition.top === currentPosition.top) {
return;
}
this.updatePreviewPosition(preview, calculatedPosition);
}, { capture: true, passive: true }).bindTo(window);
}
private createPreview(selectedItems: ResourceInterface[]): HTMLDivElement {
......@@ -165,7 +169,7 @@ class FileListDragDrop {
return preview;
}
private updatePreviewPosition(preview: HTMLElement, position: Coordinates) {
private updatePreviewPosition(preview: HTMLElement, position: Coordinates): void {
if (this.currentAnimationRequestId) {
window.cancelAnimationFrame(this.currentAnimationRequestId);
}
......
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
import RegularEvent from"@typo3/core/event/regular-event.js";import Viewport from"@typo3/backend/viewport.js";import{MultiRecordSelectionSelectors}from"@typo3/backend/multi-record-selection.js";import{FileListActionSelector,FileListActionUtility}from"@typo3/filelist/file-list-actions.js";export var FileListDragDropEvent;!function(e){e.transfer="typo3:filelist:resource:dragdrop:transfer"}(FileListDragDropEvent||(FileListDragDropEvent={}));class FileListDragDrop{constructor(){this.dragPreviewId="dragpreview",this.currentAnimationRequestId=null,this.previewSize=32,this.rootDocument=top.document;const e=FileListActionSelector.elementSelector+'[draggable="true"]',t=new Image;t.src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=",new RegularEvent("dragstart",((e,r)=>{const i=[],o=document.querySelectorAll(MultiRecordSelectionSelectors.checkboxSelector+":checked");if(o.length)o.forEach((e=>{if(e.checked){const t=e.closest(FileListActionSelector.elementSelector);t.dataset.filelistDragdropTransferItem="true";const r=FileListActionUtility.getResourceForElement(t);i.push(r)}}));else{const e=r.closest(FileListActionSelector.elementSelector);e.dataset.filelistDragdropTransferItem="true";const t=FileListActionUtility.getResourceForElement(e);i.push(t)}const n=this.createPreview(i);e.dataTransfer.setDragImage(t,0,0),e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("application/json",JSON.stringify(i));const s=this.determinePreviewPosition(e);this.updatePreviewPosition(n,s)})).delegateTo(document,e),new RegularEvent("drag",(e=>{if(e.stopPropagation(),0===e.screenX&&0===e.screenY)return;const t=this.rootDocument.getElementById(this.dragPreviewId),r=this.determinePreviewPosition(e),i=t.getBoundingClientRect();r.left===i.left&&r.top===i.top||this.updatePreviewPosition(t,r)}),{capture:!0,passive:!0}).delegateTo(document,e),new RegularEvent("dragover",((e,t)=>{e.stopPropagation();const r=FileListActionUtility.getResourceForElement(t);this.isDropAllowedOnResoruce(r)&&(e.dataTransfer.dropEffect="move",e.preventDefault(),t.classList.add("success"))}),{capture:!0}).delegateTo(document,e),new RegularEvent("drop",((e,t)=>{e.stopPropagation();const r={action:"transfer",resources:JSON.parse(e.dataTransfer.getData("application/json")??"{}"),target:FileListActionUtility.getResourceForElement(t)};top.document.dispatchEvent(new CustomEvent(FileListDragDropEvent.transfer,{detail:r}))}),{capture:!0,passive:!0}).delegateTo(document,e),new RegularEvent("dragend",(e=>{e.stopPropagation(),this.reset()}),{capture:!0,passive:!0}).delegateTo(document,e),new RegularEvent("dragleave",((e,t)=>{e.stopPropagation(),t.classList.remove("success")}),{capture:!0,passive:!0}).delegateTo(document,e)}createPreview(e){this.rootDocument.getElementById(this.dragPreviewId)?.remove();const t=document.createElement("div");t.id=this.dragPreviewId,t.setAttribute("inert","true"),t.classList.add("resource-dragpreview"),this.rootDocument.body.appendChild(t);const r=e.filter((e=>null!==e.thumbnail)).slice(0,3);if(r.length>0){const e=document.createElement("div");e.classList.add("resource-dragpreview-thumbnails"),t.appendChild(e),r.forEach((t=>{const r=new Image;r.src=t.thumbnail,r.height=this.previewSize,r.width=this.previewSize,e.appendChild(r)}))}const i=e.length-r.length;if(i>0){const e=document.createElement("div");e.classList.add("resource-dragpreview-counter"),e.textContent=(r.length>0?"+":"")+i.toString(),t.appendChild(e)}return t}updatePreviewPosition(e,t){this.currentAnimationRequestId&&window.cancelAnimationFrame(this.currentAnimationRequestId),this.currentAnimationRequestId=window.requestAnimationFrame((()=>{e.style.transform="translate("+Math.round(t.left)+"px, "+Math.round(t.top)+"px)"}))}determinePreviewPosition(e){let t=e.clientX+16,r=e.clientY+16;const i=Viewport.ContentContainer.get();if(e.view===i){const e=i.frameElement.getBoundingClientRect();t+=e.left,r+=e.top}return{left:t,top:r}}reset(){document.querySelectorAll(FileListActionSelector.elementSelector).forEach((e=>{delete e.dataset.filelistDragdropTransferItem,e.classList.remove("success")})),this.rootDocument.getElementById(this.dragPreviewId)?.remove()}isDropAllowedOnResoruce(e){return!("filelistDragdropTransferItem"in document.querySelector(FileListActionSelector.elementSelector+'[data-filelist-identifier="'+e.identifier+'"]').dataset)&&"folder"===e.type}}export default new FileListDragDrop;
\ No newline at end of file
import RegularEvent from"@typo3/core/event/regular-event.js";import Viewport from"@typo3/backend/viewport.js";import{MultiRecordSelectionSelectors}from"@typo3/backend/multi-record-selection.js";import{FileListActionSelector,FileListActionUtility}from"@typo3/filelist/file-list-actions.js";export var FileListDragDropEvent;!function(e){e.transfer="typo3:filelist:resource:dragdrop:transfer"}(FileListDragDropEvent||(FileListDragDropEvent={}));class FileListDragDrop{constructor(){this.dragPreviewId="dragpreview",this.currentAnimationRequestId=null,this.previewSize=32,this.rootDocument=top.document;const e=FileListActionSelector.elementSelector+'[draggable="true"]',t=new Image;t.src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=",new RegularEvent("dragstart",((e,r)=>{const i=[],o=document.querySelectorAll(MultiRecordSelectionSelectors.checkboxSelector+":checked");if(o.length)o.forEach((e=>{if(e.checked){const t=e.closest(FileListActionSelector.elementSelector);t.dataset.filelistDragdropTransferItem="true";const r=FileListActionUtility.getResourceForElement(t);i.push(r)}}));else{const e=r.closest(FileListActionSelector.elementSelector);e.dataset.filelistDragdropTransferItem="true";const t=FileListActionUtility.getResourceForElement(e);i.push(t)}const n=this.createPreview(i);e.dataTransfer.setDragImage(t,0,0),e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("application/json",JSON.stringify(i));const s=this.determinePreviewPosition(e);this.updatePreviewPosition(n,s)})).delegateTo(document,e),new RegularEvent("drag",(e=>{e.stopPropagation()}),{capture:!0,passive:!0}).delegateTo(document,e),new RegularEvent("dragover",((e,t)=>{e.stopPropagation();const r=FileListActionUtility.getResourceForElement(t);this.isDropAllowedOnResoruce(r)&&(e.dataTransfer.dropEffect="move",e.preventDefault(),t.classList.add("success"))}),{capture:!0}).delegateTo(document,e),new RegularEvent("drop",((e,t)=>{e.stopPropagation();const r={action:"transfer",resources:JSON.parse(e.dataTransfer.getData("application/json")??"{}"),target:FileListActionUtility.getResourceForElement(t)};top.document.dispatchEvent(new CustomEvent(FileListDragDropEvent.transfer,{detail:r}))}),{capture:!0,passive:!0}).delegateTo(document,e),new RegularEvent("dragend",(e=>{e.stopPropagation(),this.reset()}),{capture:!0,passive:!0}).delegateTo(document,e),new RegularEvent("dragleave",((e,t)=>{e.stopPropagation(),t.classList.remove("success")}),{capture:!0,passive:!0}).delegateTo(document,e),new RegularEvent("dragover",(e=>{if(0===e.screenX&&0===e.screenY)return;const t=this.rootDocument.getElementById(this.dragPreviewId);if(!t)return;const r=this.determinePreviewPosition(e),i=t.getBoundingClientRect();r.left===i.left&&r.top===i.top||this.updatePreviewPosition(t,r)}),{capture:!0,passive:!0}).bindTo(window)}createPreview(e){this.rootDocument.getElementById(this.dragPreviewId)?.remove();const t=document.createElement("div");t.id=this.dragPreviewId,t.setAttribute("inert","true"),t.classList.add("resource-dragpreview"),this.rootDocument.body.appendChild(t);const r=e.filter((e=>null!==e.thumbnail)).slice(0,3);if(r.length>0){const e=document.createElement("div");e.classList.add("resource-dragpreview-thumbnails"),t.appendChild(e),r.forEach((t=>{const r=new Image;r.src=t.thumbnail,r.height=this.previewSize,r.width=this.previewSize,e.appendChild(r)}))}const i=e.length-r.length;if(i>0){const e=document.createElement("div");e.classList.add("resource-dragpreview-counter"),e.textContent=(r.length>0?"+":"")+i.toString(),t.appendChild(e)}return t}updatePreviewPosition(e,t){this.currentAnimationRequestId&&window.cancelAnimationFrame(this.currentAnimationRequestId),this.currentAnimationRequestId=window.requestAnimationFrame((()=>{e.style.transform="translate("+Math.round(t.left)+"px, "+Math.round(t.top)+"px)"}))}determinePreviewPosition(e){let t=e.clientX+16,r=e.clientY+16;const i=Viewport.ContentContainer.get();if(e.view===i){const e=i.frameElement.getBoundingClientRect();t+=e.left,r+=e.top}return{left:t,top:r}}reset(){document.querySelectorAll(FileListActionSelector.elementSelector).forEach((e=>{delete e.dataset.filelistDragdropTransferItem,e.classList.remove("success")})),this.rootDocument.getElementById(this.dragPreviewId)?.remove()}isDropAllowedOnResoruce(e){return!("filelistDragdropTransferItem"in document.querySelector(FileListActionSelector.elementSelector+'[data-filelist-identifier="'+e.identifier+'"]').dataset)&&"folder"===e.type}}export default new FileListDragDrop;
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment