mirror of
https://github.com/zadam/trilium.git
synced 2024-09-25 10:06:01 +08:00
581 lines
19 KiB
JavaScript
581 lines
19 KiB
JavaScript
/*!
|
|
* jquery.fancytree.dnd5.js
|
|
*
|
|
* Drag-and-drop support (native HTML5).
|
|
* (Extension module for jquery.fancytree.js: https://github.com/mar10/fancytree/)
|
|
*
|
|
* Copyright (c) 2008-2017, Martin Wendt (http://wwWendt.de)
|
|
*
|
|
* Released under the MIT license
|
|
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
|
*
|
|
* @version 2.22.5
|
|
* @date 2017-05-11T17:01:53Z
|
|
*/
|
|
|
|
|
|
/*
|
|
#TODO
|
|
- glyph
|
|
|
|
Compatiblity when dragging between *separate* windows:
|
|
|
|
Drag from Chrome Edge FF IE11 Safari
|
|
To Chrome ok ok ok NO ?
|
|
Edge ok ok ok NO ?
|
|
FF ok ok ok NO ?
|
|
IE 11 ok ok ok ok ?
|
|
Safari ? ? ? ? ok
|
|
|
|
*/
|
|
|
|
;(function($, window, document, undefined) {
|
|
|
|
"use strict";
|
|
|
|
/* *****************************************************************************
|
|
* Private functions and variables
|
|
*/
|
|
var
|
|
classDragSource = "fancytree-drag-source",
|
|
classDragRemove = "fancytree-drag-remove",
|
|
classDropAccept = "fancytree-drop-accept",
|
|
classDropAfter = "fancytree-drop-after",
|
|
classDropBefore = "fancytree-drop-before",
|
|
classDropOver = "fancytree-drop-over",
|
|
classDropReject = "fancytree-drop-reject",
|
|
classDropTarget = "fancytree-drop-target",
|
|
nodeMimeType = "application/x-fancytree-node",
|
|
$dropMarker = null,
|
|
SOURCE_NODE = null,
|
|
DRAG_ENTER_RESPONSE = null,
|
|
LAST_HIT_MODE = null;
|
|
|
|
/* Convert number to string and prepend +/-; return empty string for 0.*/
|
|
function offsetString(n){
|
|
return n === 0 ? "" : (( n > 0 ) ? ("+" + n) : ("" + n));
|
|
}
|
|
|
|
/* Convert a dragEnter() or dragOver() response to a canonical form.
|
|
* Return false or plain object
|
|
* @param {string|object|boolean} r
|
|
* @return {object|false}
|
|
*/
|
|
function normalizeDragEnterResponse(r) {
|
|
var res;
|
|
|
|
if( !r ){
|
|
return false;
|
|
}
|
|
if ( $.isPlainObject(r) ) {
|
|
res = {
|
|
over: !!r.over,
|
|
before: !!r.before,
|
|
after: !!r.after
|
|
};
|
|
}else if ( $.isArray(r) ) {
|
|
res = {
|
|
over: ($.inArray("over", r) >= 0),
|
|
before: ($.inArray("before", r) >= 0),
|
|
after: ($.inArray("after", r) >= 0)
|
|
};
|
|
}else{
|
|
res = {
|
|
over: ((r === true) || (r === "over")),
|
|
before: ((r === true) || (r === "before")),
|
|
after: ((r === true) || (r === "after"))
|
|
};
|
|
}
|
|
if( Object.keys(res).length === 0 ) {
|
|
return false;
|
|
}
|
|
// if( Object.keys(res).length === 1 ) {
|
|
// res.unique = res[0];
|
|
// }
|
|
return res;
|
|
}
|
|
|
|
/* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
|
|
function autoScroll(tree, event) {
|
|
var spOfs, scrollTop, delta,
|
|
dndOpts = tree.options.dnd5,
|
|
sp = tree.$scrollParent[0],
|
|
sensitivity = dndOpts.scrollSensitivity,
|
|
speed = dndOpts.scrollSpeed,
|
|
scrolled = 0;
|
|
|
|
if ( sp !== document && sp.tagName !== "HTML" ) {
|
|
spOfs = tree.$scrollParent.offset();
|
|
scrollTop = sp.scrollTop;
|
|
if ( spOfs.top + sp.offsetHeight - event.pageY < sensitivity ) {
|
|
delta = (sp.scrollHeight - tree.$scrollParent.innerHeight() - scrollTop);
|
|
// console.log ("sp.offsetHeight: " + sp.offsetHeight
|
|
// + ", spOfs.top: " + spOfs.top
|
|
// + ", scrollTop: " + scrollTop
|
|
// + ", innerHeight: " + tree.$scrollParent.innerHeight()
|
|
// + ", scrollHeight: " + sp.scrollHeight
|
|
// + ", delta: " + delta
|
|
// );
|
|
if( delta > 0 ) {
|
|
sp.scrollTop = scrolled = scrollTop + speed;
|
|
}
|
|
} else if ( scrollTop > 0 && event.pageY - spOfs.top < sensitivity ) {
|
|
sp.scrollTop = scrolled = scrollTop - speed;
|
|
}
|
|
} else {
|
|
scrollTop = $(document).scrollTop();
|
|
if (scrollTop > 0 && event.pageY - scrollTop < sensitivity) {
|
|
scrolled = scrollTop - speed;
|
|
$(document).scrollTop(scrolled);
|
|
} else if ($(window).height() - (event.pageY - scrollTop) < sensitivity) {
|
|
scrolled = scrollTop + speed;
|
|
$(document).scrollTop(scrolled);
|
|
}
|
|
}
|
|
if( scrolled ) {
|
|
tree.debug("autoScroll: " + scrolled + "px");
|
|
}
|
|
return scrolled;
|
|
}
|
|
|
|
/* Handle dragover event (fired every x ms) and return hitMode. */
|
|
function handleDragOver(event, data) {
|
|
// Implement auto-scrolling
|
|
if ( data.options.dnd5.scroll ) {
|
|
autoScroll(data.tree, event);
|
|
}
|
|
// Bail out with previous response if we get an invalid dragover
|
|
if( !data.node ) {
|
|
data.tree.warn("Ignore dragover for non-node"); //, event, data);
|
|
return LAST_HIT_MODE;
|
|
}
|
|
|
|
var markerOffsetX, nodeOfs, relPosY, //res,
|
|
// eventHash = getEventHash(event),
|
|
hitMode = null,
|
|
tree = data.tree,
|
|
options = tree.options,
|
|
dndOpts = options.dnd5,
|
|
targetNode = data.node,
|
|
sourceNode = data.otherNode,
|
|
markerAt = "center",
|
|
// glyph = options.glyph || null,
|
|
// $source = sourceNode ? $(sourceNode.span) : null,
|
|
$target = $(targetNode.span),
|
|
$targetTitle = $target.find("span.fancytree-title");
|
|
|
|
if(DRAG_ENTER_RESPONSE === false){
|
|
tree.warn("Ignore dragover, since dragenter returned false"); //, event, data);
|
|
// $.error("assert failed: dragenter returned false");
|
|
return false;
|
|
} else if(typeof DRAG_ENTER_RESPONSE === "string") {
|
|
$.error("assert failed: dragenter returned string");
|
|
// Use hitMode from onEnter if provided.
|
|
// hitMode = DRAG_ENTER_RESPONSE;
|
|
} else {
|
|
// Calculate hitMode from relative cursor position.
|
|
nodeOfs = $target.offset();
|
|
relPosY = (event.pageY - nodeOfs.top) / $target.height();
|
|
|
|
if( DRAG_ENTER_RESPONSE.after && relPosY > 0.75 ){
|
|
hitMode = "after";
|
|
} else if(!DRAG_ENTER_RESPONSE.over && DRAG_ENTER_RESPONSE.after && relPosY > 0.5 ){
|
|
hitMode = "after";
|
|
} else if(DRAG_ENTER_RESPONSE.before && relPosY <= 0.25) {
|
|
hitMode = "before";
|
|
} else if(!DRAG_ENTER_RESPONSE.over && DRAG_ENTER_RESPONSE.before && relPosY <= 0.5) {
|
|
hitMode = "before";
|
|
} else if(DRAG_ENTER_RESPONSE.over) {
|
|
hitMode = "over";
|
|
}
|
|
// Prevent no-ops like 'before source node'
|
|
// TODO: these are no-ops when moving nodes, but not in copy mode
|
|
if( dndOpts.preventVoidMoves ){
|
|
if(targetNode === sourceNode){
|
|
targetNode.debug("drop over source node prevented");
|
|
hitMode = null;
|
|
}else if(hitMode === "before" && sourceNode && targetNode === sourceNode.getNextSibling()){
|
|
targetNode.debug("drop after source node prevented");
|
|
hitMode = null;
|
|
}else if(hitMode === "after" && sourceNode && targetNode === sourceNode.getPrevSibling()){
|
|
targetNode.debug("drop before source node prevented");
|
|
hitMode = null;
|
|
}else if(hitMode === "over" && sourceNode && sourceNode.parent === targetNode && sourceNode.isLastSibling() ){
|
|
targetNode.debug("drop last child over own parent prevented");
|
|
hitMode = null;
|
|
}
|
|
}
|
|
}
|
|
// Let callback modify the calculated hitMode
|
|
data.hitMode = hitMode;
|
|
if(hitMode && dndOpts.dragOver){
|
|
// TODO: http://code.google.com/p/dynatree/source/detail?r=625
|
|
dndOpts.dragOver(targetNode, data);
|
|
hitMode = data.hitMode;
|
|
}
|
|
// LAST_DROP_EFFECT = data.dataTransfer.dropEffect;
|
|
// LAST_EFFECT_ALLOWED = data.dataTransfer.effectAllowed;
|
|
LAST_HIT_MODE = hitMode;
|
|
//
|
|
if( hitMode === "after" || hitMode === "before" || hitMode === "over" ){
|
|
markerOffsetX = dndOpts.dropMarkerOffsetX || 0;
|
|
switch(hitMode){
|
|
case "before":
|
|
markerAt = "top";
|
|
markerOffsetX += (dndOpts.dropMarkerInsertOffsetX || 0);
|
|
break;
|
|
case "after":
|
|
markerAt = "bottom";
|
|
markerOffsetX += (dndOpts.dropMarkerInsertOffsetX || 0);
|
|
break;
|
|
}
|
|
|
|
$dropMarker
|
|
.toggleClass(classDropAfter, hitMode === "after")
|
|
.toggleClass(classDropOver, hitMode === "over")
|
|
.toggleClass(classDropBefore, hitMode === "before")
|
|
.show()
|
|
.position($.ui.fancytree.fixPositionOptions({
|
|
my: "left" + offsetString(markerOffsetX) + " center",
|
|
at: "left " + markerAt,
|
|
of: $targetTitle
|
|
}));
|
|
} else {
|
|
$dropMarker.hide();
|
|
// console.log("hide dropmarker")
|
|
}
|
|
// if( $source ){
|
|
// $source.toggleClass(classDragRemove, isMove);
|
|
// }
|
|
$(targetNode.span)
|
|
.toggleClass(classDropTarget, hitMode === "after" || hitMode === "before" || hitMode === "over")
|
|
.toggleClass(classDropAfter, hitMode === "after")
|
|
.toggleClass(classDropBefore, hitMode === "before")
|
|
.toggleClass(classDropAccept, hitMode === "over")
|
|
.toggleClass(classDropReject, hitMode === false);
|
|
|
|
return hitMode;
|
|
}
|
|
|
|
/* *****************************************************************************
|
|
*
|
|
*/
|
|
|
|
$.ui.fancytree.registerExtension({
|
|
name: "dnd5",
|
|
version: "2.22.5",
|
|
// Default options for this extension.
|
|
options: {
|
|
autoExpandMS: 1500, // Expand nodes after n milliseconds of hovering
|
|
setTextTypeJson: false, // Allow dragging of nodes to different IE windows
|
|
preventForeignNodes: false, // Prevent dropping nodes from different Fancytrees
|
|
preventNonNodes: false, // Prevent dropping items other than Fancytree nodes
|
|
preventRecursiveMoves: true, // Prevent dropping nodes on own descendants
|
|
preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
|
|
scroll: true, // Enable auto-scrolling while dragging
|
|
scrollSensitivity: 20, // Active top/bottom margin in pixel
|
|
scrollSpeed: 5, // Pixel per event
|
|
dropMarkerOffsetX: -24, // absolute position offset for .fancytree-drop-marker relatively to ..fancytree-title (icon/img near a node accepting drop)
|
|
dropMarkerInsertOffsetX: -16,// additional offset for drop-marker with hitMode = "before"/"after"
|
|
// Events (drag support)
|
|
dragStart: null, // Callback(sourceNode, data), return true, to enable dnd drag
|
|
dragDrag: $.noop, // Callback(sourceNode, data)
|
|
dragEnd: $.noop, // Callback(sourceNode, data)
|
|
// Events (drop support)
|
|
dragEnter: null, // Callback(targetNode, data), return true, to enable dnd drop
|
|
dragOver: $.noop, // Callback(targetNode, data)
|
|
dragExpand: $.noop, // Callback(targetNode, data), return false to prevent autoExpand
|
|
dragDrop: $.noop, // Callback(targetNode, data)
|
|
dragLeave: $.noop // Callback(targetNode, data)
|
|
},
|
|
|
|
treeInit: function(ctx){
|
|
var tree = ctx.tree,
|
|
opts = ctx.options,
|
|
dndOpts = opts.dnd5,
|
|
getNode = $.ui.fancytree.getNode;
|
|
|
|
if( $.inArray("dnd", opts.extensions) >= 0 ) {
|
|
$.error("Extensions 'dnd' and 'dnd5' are mutually exclusive.");
|
|
}
|
|
if( dndOpts.dragStop ) {
|
|
$.error("dragStop is not used by ext-dnd5. Use dragEnd instead.");
|
|
}
|
|
|
|
// Implement `opts.createNode` event to add the 'draggable' attribute
|
|
// #680: this must happen before calling super.treeInit()
|
|
if( dndOpts.dragStart ) {
|
|
$.ui.fancytree.overrideMethod(ctx.options, "createNode", function(event, data) {
|
|
// Default processing if any
|
|
this._super.apply(this, arguments);
|
|
|
|
data.node.span.draggable = true;
|
|
});
|
|
}
|
|
this._superApply(arguments);
|
|
|
|
this.$container.addClass("fancytree-ext-dnd5");
|
|
|
|
// Store the current scroll parent, which may be the tree
|
|
// container, any enclosing div, or the document
|
|
this.$scrollParent = this.$container.children(":first").scrollParent();
|
|
|
|
$dropMarker = $("#fancytree-drop-marker");
|
|
if( !$dropMarker.length ) {
|
|
$dropMarker = $("<div id='fancytree-drop-marker'></div>")
|
|
.hide()
|
|
.css({
|
|
"z-index": 1000,
|
|
// Drop marker should not steal dragenter/dragover events:
|
|
"pointer-events": "none"
|
|
}).prependTo("body");
|
|
// if( glyph ) {
|
|
// instData.$dropMarker
|
|
// .addClass(glyph.map.dropMarker);
|
|
// }
|
|
}
|
|
// Enable drag support if dragStart() is specified:
|
|
if( dndOpts.dragStart ) {
|
|
// Bind drag event handlers
|
|
tree.$container.on("dragstart drag dragend", function(event){
|
|
var json,
|
|
node = getNode(event),
|
|
dataTransfer = event.dataTransfer || event.originalEvent.dataTransfer,
|
|
isMove = dataTransfer.dropEffect === "move",
|
|
$source = node ? $(node.span) : null,
|
|
data = {
|
|
node: node,
|
|
tree: tree,
|
|
options: tree.options,
|
|
originalEvent: event,
|
|
dataTransfer: dataTransfer,
|
|
// dropEffect: undefined, // set by dragend
|
|
isCancelled: undefined // set by dragend
|
|
};
|
|
|
|
switch( event.type ) {
|
|
|
|
case "dragstart":
|
|
$(node.span).addClass(classDragSource);
|
|
|
|
// Store current source node in different formats
|
|
SOURCE_NODE = node;
|
|
|
|
// Set payload
|
|
// Note:
|
|
// Transfer data is only accessible on dragstart and drop!
|
|
// For all other events the formats and kinds in the drag
|
|
// data store list of items representing dragged data can be
|
|
// enumerated, but the data itself is unavailable and no new
|
|
// data can be added.
|
|
json = JSON.stringify(node.toDict());
|
|
try {
|
|
dataTransfer.setData(nodeMimeType, json);
|
|
dataTransfer.setData("text/html", $(node.span).html());
|
|
dataTransfer.setData("text/plain", node.title);
|
|
} catch(ex) {
|
|
// IE only accepts 'text' type
|
|
tree.warn("Could not set data (IE only accepts 'text') - " + ex);
|
|
}
|
|
// We always need to set the 'text' type if we want to drag
|
|
// Because IE 11 only accepts this single type.
|
|
// If we pass JSON here, IE can can access all node properties,
|
|
// even when the source lives in another window. (D'n'd inside
|
|
// the same window will always work.)
|
|
// The drawback is, that in this case ALL browsers will see
|
|
// the JSON representation as 'text', so dragging
|
|
// to a text field will insert the JSON string instead of
|
|
// the node title.
|
|
if( dndOpts.setTextTypeJson ) {
|
|
dataTransfer.setData("text", json);
|
|
} else {
|
|
dataTransfer.setData("text", node.title);
|
|
}
|
|
|
|
// Set the allowed and current drag mode (move, copy, or link)
|
|
dataTransfer.effectAllowed = "all"; // "copyMove"
|
|
// dataTransfer.dropEffect = "move";
|
|
|
|
// Set the title as drag image (otherwise it would contain the expander)
|
|
if( dataTransfer.setDragImage ) {
|
|
// IE 11 does not support this
|
|
dataTransfer.setDragImage($(node.span).find(".fancytree-title")[0], -10, -10);
|
|
// dataTransfer.setDragImage($(node.span)[0], -10, -10);
|
|
}
|
|
// Let user modify above settings
|
|
return dndOpts.dragStart(node, data) !== false;
|
|
|
|
case "drag":
|
|
// Called every few miliseconds
|
|
$source.toggleClass(classDragRemove, isMove);
|
|
dndOpts.dragDrag(node, data);
|
|
break;
|
|
|
|
case "dragend":
|
|
$(node.span).removeClass(classDragSource + " " + classDragRemove);
|
|
SOURCE_NODE = null;
|
|
DRAG_ENTER_RESPONSE = null;
|
|
// data.dropEffect = dataTransfer.dropEffect;
|
|
data.isCancelled = (dataTransfer.dropEffect === "none");
|
|
$dropMarker.hide();
|
|
dndOpts.dragEnd(node, data);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
// Enable drop support if dragEnter() is specified:
|
|
if( dndOpts.dragEnter ) {
|
|
// Bind drop event handlers
|
|
tree.$container.on("dragenter dragover dragleave drop", function(event){
|
|
var json, nodeData, r, res,
|
|
allowDrop = null,
|
|
node = getNode(event),
|
|
dataTransfer = event.dataTransfer || event.originalEvent.dataTransfer,
|
|
// glyph = opts.glyph || null,
|
|
data = {
|
|
node: node,
|
|
tree: tree,
|
|
options: tree.options,
|
|
hitMode: DRAG_ENTER_RESPONSE,
|
|
originalEvent: event,
|
|
dataTransfer: dataTransfer,
|
|
otherNode: SOURCE_NODE || null,
|
|
otherNodeData: null, // set by drop event
|
|
dropEffect: undefined, // set by drop event
|
|
isCancelled: undefined // set by drop event
|
|
};
|
|
|
|
switch( event.type ) {
|
|
|
|
case "dragenter":
|
|
// The dragenter event is fired when a dragged element or
|
|
// text selection enters a valid drop target.
|
|
|
|
if( !node ) {
|
|
// Sometimes we get dragenter for the container element
|
|
tree.debug("Ignore non-node " + event.type + ": " + event.target.tagName + "." + event.target.className);
|
|
DRAG_ENTER_RESPONSE = false;
|
|
break;
|
|
}
|
|
|
|
$(node.span)
|
|
.addClass(classDropOver)
|
|
.removeClass(classDropAccept + " " + classDropReject);
|
|
|
|
if( dndOpts.preventNonNodes && !nodeData ) {
|
|
node.debug("Reject dropping a non-node");
|
|
DRAG_ENTER_RESPONSE = false;
|
|
break;
|
|
} else if( dndOpts.preventForeignNodes && (!SOURCE_NODE || SOURCE_NODE.tree !== node.tree ) ) {
|
|
node.debug("Reject dropping a foreign node");
|
|
DRAG_ENTER_RESPONSE = false;
|
|
break;
|
|
}
|
|
|
|
// NOTE: dragenter is fired BEFORE the dragleave event
|
|
// of the previous element!
|
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=19041
|
|
setTimeout(function(){
|
|
// node.info("DELAYED " + event.type, event.target, DRAG_ENTER_RESPONSE);
|
|
// Auto-expand node (only when 'over' the node, not 'before', or 'after')
|
|
if( dndOpts.autoExpandMS &&
|
|
node.hasChildren() !== false && !node.expanded &&
|
|
(!dndOpts.dragExpand || dndOpts.dragExpand(node, data) !== false)
|
|
) {
|
|
node.scheduleAction("expand", dndOpts.autoExpandMS);
|
|
}
|
|
}, 0);
|
|
|
|
$dropMarker.show();
|
|
|
|
// Call dragEnter() to figure out if (and where) dropping is allowed
|
|
if( dndOpts.preventRecursiveMoves && node.isDescendantOf(data.otherNode) ){
|
|
res = false;
|
|
}else{
|
|
r = dndOpts.dragEnter(node, data);
|
|
res = normalizeDragEnterResponse(r);
|
|
}
|
|
DRAG_ENTER_RESPONSE = res;
|
|
|
|
allowDrop = res && ( res.over || res.before || res.after );
|
|
break;
|
|
|
|
case "dragover":
|
|
// The dragover event is fired when an element or text
|
|
// selection is being dragged over a valid drop target
|
|
// (every few hundred milliseconds).
|
|
LAST_HIT_MODE = handleDragOver(event, data);
|
|
allowDrop = !!LAST_HIT_MODE;
|
|
break;
|
|
|
|
case "dragleave":
|
|
// NOTE: dragleave is fired AFTER the dragenter event of the
|
|
// FOLLOWING element.
|
|
if( !node ) {
|
|
tree.debug("Ignore non-node " + event.type + ": " + event.target.tagName + "." + event.target.className);
|
|
break;
|
|
}
|
|
if( !$(node.span).hasClass(classDropOver) ) {
|
|
node.debug("Ignore dragleave (multi)"); //, event.currentTarget);
|
|
break;
|
|
}
|
|
$(node.span).removeClass(classDropOver + " " + classDropAccept + " " + classDropReject);
|
|
node.scheduleAction("cancel");
|
|
dndOpts.dragLeave(node, data);
|
|
$dropMarker.hide();
|
|
break;
|
|
|
|
case "drop":
|
|
// Data is only readable in the (dragenter and) drop event:
|
|
|
|
if( $.inArray(nodeMimeType, dataTransfer.types) >= 0 ) {
|
|
nodeData = dataTransfer.getData(nodeMimeType);
|
|
tree.info(event.type + ": getData('application/x-fancytree-node'): '" + nodeData + "'");
|
|
}
|
|
if( !nodeData ) {
|
|
// 1. Source is not a Fancytree node, or
|
|
// 2. If the FT mime type was set, but returns '', this
|
|
// is probably IE 11 (which only supports 'text')
|
|
nodeData = dataTransfer.getData("text");
|
|
tree.info(event.type + ": getData('text'): '" + nodeData + "'");
|
|
}
|
|
if( nodeData ) {
|
|
try {
|
|
// 'text' type may contain JSON if IE is involved
|
|
// and setTextTypeJson option was set
|
|
json = JSON.parse(nodeData);
|
|
if( json.title !== undefined ) {
|
|
data.otherNodeData = json;
|
|
}
|
|
} catch(ex) {
|
|
// assume 'text' type contains plain text, so `otherNodeData`
|
|
// should not be set
|
|
}
|
|
}
|
|
tree.debug(event.type + ": nodeData: '" + nodeData + "', otherNodeData: ", data.otherNodeData);
|
|
|
|
$(node.span).removeClass(classDropOver + " " + classDropAccept + " " + classDropReject);
|
|
$dropMarker.hide();
|
|
|
|
data.hitMode = LAST_HIT_MODE;
|
|
data.dropEffect = dataTransfer.dropEffect;
|
|
data.isCancelled = data.dropEffect === "none";
|
|
|
|
// Let user implement the actual drop operation
|
|
dndOpts.dragDrop(node, data);
|
|
|
|
// Prevent browser's default drop handling
|
|
event.preventDefault();
|
|
break;
|
|
}
|
|
// Dnd API madness: we must PREVENT default handling to enable dropping
|
|
if( allowDrop ) {
|
|
event.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}(jQuery, window, document));
|