This repository has been archived by the owner on Nov 28, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Added auto-scroll when dragging gallery images (#1083)
no issue Adds auto-scroll if the mouse is placed near the top or bottom of the window whilst dragging an image to re-order it within a gallery. Useful when the position you want to drag to is not currently on screen. - append drop indicator element to `.koenig-editor` element to account for scrolling (also fixes indicator positioning bug with current implementation if you use mouse-wheel or keyboard to scroll the page whilst dragging) - generalise `getParent` util to accept a - switch to using selectors rather than dataset for finding parent draggable/droppable/container - add a `ScrollHandler` class that is used by the `koenigDragDropHandler` service to trigger scrolling whilst dragging
- Loading branch information
1 parent
cce8738
commit f51c9dd
Showing
4 changed files
with
243 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,21 @@ | ||
import {dasherize} from '@ember/string'; | ||
|
||
// we use data attributes rather than classes even though they can be slower | ||
// because in many instances our draggable/droppable element's classes attribute | ||
// could be dynamically generated which could remove our DnD classes when changed | ||
|
||
export const CONTAINER_DATA_ATTR = 'koenigDndContainer'; | ||
export const CONTAINER_SELECTOR = `[data-${dasherize(CONTAINER_DATA_ATTR)}]`; | ||
|
||
export const DRAGGABLE_DATA_ATTR = 'koenigDndDraggable'; | ||
export const DRAGGABLE_SELECTOR = `[data-${dasherize(DRAGGABLE_DATA_ATTR)}]`; | ||
|
||
export const DROPPABLE_DATA_ATTR = 'koenigDndDroppable'; | ||
export const DROPPABLE_SELECTOR = `[data-${dasherize(DROPPABLE_DATA_ATTR)}]`; | ||
|
||
export const DROP_INDICATOR_ID = 'koenig-drag-drop-indicator'; | ||
export const DROP_INDICATOR_ZINDEX = 10000; | ||
|
||
export const GHOST_CONTAINER_ID = 'koenig-drag-drop-ghost-container'; | ||
|
||
export const GHOST_ZINDEX = DROP_INDICATOR_ZINDEX + 1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// adapted from draggable.js Scrollable plugin (MIT) | ||
// https://github.com/Shopify/draggable/blob/master/src/Draggable/Plugins/Scrollable/Scrollable.js | ||
import UAParser from 'ua-parser-js'; | ||
import { | ||
getDocumentScrollingElement, | ||
getParentScrollableElement | ||
} from './utils'; | ||
|
||
export const defaultOptions = { | ||
speed: 8, | ||
sensitivity: 50 | ||
}; | ||
|
||
export default class ScrollHandler { | ||
constructor() { | ||
this.options = Object.assign({}, defaultOptions); | ||
|
||
this.currentMousePosition = null; | ||
this.findScrollableElementFrame = null; | ||
this.scrollableElement = null; | ||
this.scrollAnimationFrame = null; | ||
|
||
// bind `this` so methods can be passed to requestAnimationFrame | ||
this._scroll = this._scroll.bind(this); | ||
|
||
// cache browser info to avoid parsing on every animation frame | ||
this.userAgent = new UAParser(); | ||
} | ||
|
||
dragStart(draggableInfo) { | ||
this.findScrollableElementFrame = requestAnimationFrame(() => { | ||
this.scrollableElement = this.getScrollableElement(draggableInfo.element); | ||
}); | ||
} | ||
|
||
dragMove(draggableInfo) { | ||
this.findScrollableElementFrame = requestAnimationFrame(() => { | ||
this.scrollableElement = this.getScrollableElement(draggableInfo.target); | ||
}); | ||
|
||
if (!this.scrollableElement) { | ||
return; | ||
} | ||
|
||
this.currentMousePosition = { | ||
clientX: draggableInfo.mousePosition.x, | ||
clientY: draggableInfo.mousePosition.y | ||
}; | ||
|
||
this.scrollAnimationFrame = requestAnimationFrame(this._scroll); | ||
} | ||
|
||
dragStop() { | ||
cancelAnimationFrame(this.scrollAnimationFrame); | ||
cancelAnimationFrame(this.findScrollableElementFrame); | ||
|
||
this.currentMousePosition = null; | ||
this.findScrollableElementFrame = null; | ||
this.scrollableElement = null; | ||
this.scrollAnimationFrame = null; | ||
} | ||
|
||
getScrollableElement(target) { | ||
let scrollableElement = getParentScrollableElement(target); | ||
|
||
// workaround for our particular scrolling setup | ||
// TODO: find a way to make this configurable | ||
if (scrollableElement === getDocumentScrollingElement()) { | ||
scrollableElement = document.querySelector('.gh-koenig-editor'); | ||
} | ||
|
||
return scrollableElement; | ||
} | ||
|
||
_scroll() { | ||
if (!this.scrollableElement || !this.currentMousePosition) { | ||
return; | ||
} | ||
|
||
cancelAnimationFrame(this.scrollAnimationFrame); | ||
|
||
let {speed, sensitivity} = this.options; | ||
|
||
let rect = this.scrollableElement.getBoundingClientRect(); | ||
|
||
let scrollableElement = this.scrollableElement; | ||
let clientX = this.currentMousePosition.clientX; | ||
let clientY = this.currentMousePosition.clientY; | ||
|
||
let {offsetHeight, offsetWidth} = scrollableElement; | ||
|
||
let topPosition = rect.top + offsetHeight - clientY; | ||
let bottomPosition = clientY - rect.top; | ||
let isSafari = this.userAgent.getBrowser().name === 'Safari'; | ||
|
||
// Safari will automatically scroll when the mouse is outside of the window | ||
// so we want to avoid our own scrolling in that situation to avoid jank | ||
if (topPosition < sensitivity && !(isSafari && topPosition < 0)) { | ||
scrollableElement.scrollTop += speed; | ||
} else if (bottomPosition < sensitivity && !(isSafari && bottomPosition < 0)) { | ||
scrollableElement.scrollTop -= speed; | ||
} | ||
|
||
if (rect.left + offsetWidth - clientX < sensitivity) { | ||
scrollableElement.scrollLeft += speed; | ||
} else if (clientX - rect.left < sensitivity) { | ||
scrollableElement.scrollLeft -= speed; | ||
} | ||
|
||
this.scrollAnimationFrame = requestAnimationFrame(this._scroll); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters