-
Notifications
You must be signed in to change notification settings - Fork 0
Library: DnD start()
start() module is a function, which initializes a DOM node for DnD operations. After that, a user can interact with the DOM node as a container of items, which can be picked up and dragged.
The demo: https://researchnow.github.io/reno/pages/dnd.html
In a module-enabled environment (like Babel) it can be accessed like that:
import start from '@researchnow/reno/src/utils/dnd/start';In global-based environments (like a browser) it is frequently mapped to Reno.utils.dnd.start.
The function takes the following arguments:
-
containeris a DOM node, which contains DnD items. -
optionsis an object, which contains properties guiding DnD operations:-
filteris a filter object used byon()to detect clickable items. The default:'.reno-dnd-item'.- Usually it is a CSS selector for matches(). Every mouse-down is tested if it is done on a DOM node that satisfies the selector.
- In complex cases it can be a function. See
on()documentation for details.
-
initis a function to initialize aMoveobject (described below) when a user starts a DnD operation.- It takes one argument: a newly-created
Moveobject. - The default: a no-op function.
- It takes one argument: a newly-created
-
destroyis a function to clean up when a DnD operation is finished. The default: a no-op function. -
avatarClassis a CSS class to use for an avatar (a dragged element created after a DnD operation was started). It is used by the default avatar creator (seemakeAvatarbelow). The default:'reno-dnd-avatar'. -
makeAvataris a function, which takes aMoveobject (contains the clicked DOM node), and produces a new DOM node, which will be dragged. It should be absolutely positioned and in a proper place. The default is a function, which clones the clicked DOM node, and does all prep and positioning. -
movingis a function, which takes aMoveobject and amousemoveevent object. It updates a position of the avatar by updating theMoveobject. The default: a function that linearly "moves" the avatar:const moving = (mover, e) => { mover.x += e.pageX - mover.mouseX; mover.y += e.pageY - mover.mouseY; };
-
overis a function, which is called after repositioning the avatar to reflect changes (if any) to underlying ("under the avatar") DOM nodes. It is called with a single argument: aMoveobject. The default: a no-op function. -
dropis a function, which is called when a user "dropped" the avatar. It is called with a single argument: aMoveobject. The default: a no-op function. -
targetis a CSS selector to find valid DnD drop targets. The default:'.reno-dnd-item'.- Used by common's init().
-
The returned value is a handle from on(), which is set up to handle mousedown event. It is an object with following methods:
-
remove()removes an event handler canceling future DnD operations. -
pause()pauses an event handler temporarily. -
resume()resumes an event handler.
This is an object created when a user initiated a DnD operation. It is used to hold all relevant information and passed through to various callback functions defined in options.
Callbacks can use the following public properties:
-
containeris a DOM node passed tostart()described above. -
optionsis an object passed tostart()described above. It can be used to pass custom options as well. -
nodeis a DOM node, which is being dragged. -
mouseXandmouseYare the previous mouse position. It can be used to calculate how the avatar was moved. -
avataris a DOM node, which is actually being moved instead ofnode. It is produced bymakeAvataroption described above.
Callbacks may define their own properties and methods if needed.
When a user initiates a DnD operation by pressing a mouse button down certain DOM nodes will be ignored:
- A valid node should satisfy a
filterrequirement, e.g., it should havereno-dnd-itemCSS class. - It should not be a form element or a link element.
- It should not have
reno-dnd-ignoreCSS class.
The DnD package does not produce HTML but consumes whatever a markup produced by a user. During a DnD operation, CSS classes can be updated, and an avatar is created, which is usually attached to a body.
The following CSS classes are used by the DnD package:
- User-supplied mark-up classes:
-
reno-dnd-itemmarks a draggable object. It can be used to visually highlight what can be dragged to avoid user's confusion.- This class is a default filter described above. It can be overridden or ignored.
-
reno-dnd-ignoremarks an otherwise valid node as non-draggable.
-
- The dragged node:
-
reno-dnd-draggedis assigned to the dragged item. It can be used to highlight what is being dragged.
-
- Other items:
-
reno-dnd-overis assigned by default callbacks to drop targets, which are under the avatar at the moment.
-
- Avatar:
-
reno-dnd-avataris assigned to the avatar.
-
- Container:
-
reno-dnd-dragged-containeris assigned to a container, which contains the dragged node. It can be used to highlight the container.
-
- Body (more specifically
document.documentElement):-
reno-dnd-in-flightis assigned when a DnD operation is in progress. It can be used to tone down the web page while dragging.
-
Rearrange a vertical list:
<div id="v">
<div class="reno-dnd-item">One</div>
<div class="reno-dnd-item">Two</div>
<div class="reno-dnd-item">Three</div>
<div class="reno-dnd-item">Four</div>
<div class="reno-dnd-item">Five</div>
</div>The code supports drops and restricts a horizontal movement.
Reno.utils.dnd.start(document.getElementById('v'), {
init: Reno.utils.dnd.init,
over: Reno.utils.dnd.over,
drop: Reno.utils.dnd.rearrangeable.dropY,
moving: Reno.utils.dnd.movingY
});Group items:
<div id="g">
<div class="reno-dnd-item reno-dnd-target">One</div>
<div class="reno-dnd-item reno-dnd-target">Two</div>
<div class="reno-dnd-item reno-dnd-target">Three</div>
<div class="reno-dnd-item reno-dnd-target">Four</div>
<div class="reno-dnd-item reno-dnd-target">Five</div>
</div>The corresponding code:
Reno.utils.dnd.start(document.getElementById('g'), {
target: '.reno-dnd-target',
init: mover => {
Reno.utils.dnd.init(mover);
mover.avatar.classList.remove('reno-dnd-target');
},
over: Reno.utils.dnd.over,
drop: mover => {
if (mover.previousOverItem) {
if (mover.previousOverItem !== mover.node) {
let target = mover.previousOverItem;
if (target.classList.contains('reno-dnd-item')) {
target = target.ownerDocument.createElement('div');
target.classList.add('reno-dnd-target');
mover.previousOverItem.classList.remove('reno-dnd-target');
mover.previousOverItem.parentNode.replaceChild(
target, mover.previousOverItem);
target.appendChild(mover.previousOverItem);
}
mover.node.classList.remove('reno-dnd-target');
target.appendChild(mover.node);
}
} else {
const parent = mover.node.parentNode;
mover.container.appendChild(mover.node);
mover.node.classList.add('reno-dnd-target');
if (!parent.firstElementChild) {
parent.parentNode.removeChild(parent);
}
}
}
});The results can be seen in the demo page: https://researchnow.github.io/reno/pages/dnd.html