From 8642a56c3737406acb53dddcd5efd07330042ea9 Mon Sep 17 00:00:00 2001 From: Thimo Kraemer Date: Sun, 4 Nov 2018 15:43:47 +0100 Subject: [PATCH] Added DND plugin --- dnd.js | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 dnd.js diff --git a/dnd.js b/dnd.js new file mode 100644 index 0000000..c491426 --- /dev/null +++ b/dnd.js @@ -0,0 +1,358 @@ +/* + dnd.js - KSS HTML5 Drag and Drop plugin + + Copyright (c) 2018, joonis new media + Author: Thimo Kraemer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. +*/ + +/******************************************************************************************* + * DND Plugin + * + * Based on the original Kukit plugin and modified to work with KSS-RPC. + * Should be reviewed in general. + * + * Brief documentation + * ------------------- + * + * This plugin provides HTML5 DND functionality and is not meant to move some + * elements around the screen. The latter can be realized with the core KSS + * functionality. + * + * Main events to use: + * + * - "dragstart" on dragable elements + * - "drop" on target elements + * + * All bindings are done automatically (no need to set *draggable* attributes, etc). + * In *dragstart* events the most important thing is to set the drag data with the + * KSS action *setDragData*: + * + * .my-draggable:dragstart { + * kss-action-client: setDragData; + * type: "text/plain"; + * value: outerHTML(); + * } + * + * In *drop* events you can access the data with the paramater provider "dragData": + * + * #my-drop-target:drop { + * kss-action-client: appendHTML: + * html: dragData("text/plain"); + * } + * + * An element is only dropable if all required drag data types are available. + * That is all requested types in *drop* must have been specified in *dragstart* + * previously. Dropping data from external resources is possible as well with + * the exception of files which isn't implemented yet. + * + ******************************************************************************************/ + +kss.dnd = { + _dropEffect: 'move', + _isValidDropTarget: false, + _dataTransfer: null +}; + +// A wrapper around the original dataTransfer object of a DND event. +// It enables the possibility to use any data type within the document, +// even if not supported by the browser (eg. IE<10). +kss.dnd.DataTransfer = function() { + + this.initialize = function(dataTransfer, external) { + this.data = {}; + this.dataTransfer = dataTransfer; + this.external = external || false; + if (external) { + // IE<10 doesn't provide the "types" attribute, + // so we assume that we have a text and url value. + // Anyway the only two supported types by IE<10. + this.types = dataTransfer.types || ['text/plain', 'text/uri-list']; + } + else { + this.types = []; + } + }; + + this.normalizeType = function(type) { + // Type mapping for backwards compatibility (IE<10) + var map = {'text': 'text/plain', 'url': 'text/uri-list'}; + type = type.toLowerCase(); + return map[type] || type; + }; + + this.setData = function(type, value) { + type = this.normalizeType(type); + this.types.push(type); + this.data[type] = value; + // required by IE + if (type == 'text/plain') { + this.dataTransfer.setData('Text', value); + } + else if (type == 'text/uri-list') { + this.dataTransfer.setData('url', value); + } + try { + this.dataTransfer.setData(type, value); + } + catch (exc) {} + }; + + this.getData = function(type) { + type = this.normalizeType(type); + var value = this.data[type]; + if (!value) { + // required by IE + if (type == 'text/plain') { + value = this.dataTransfer.getData('Text'); + } + else if (type == 'text/uri-list') { + value = this.dataTransfer.getData('url'); + } + } + if (!value) { + try { + value = this.dataTransfer.getData(type); + } + catch (exc) {} + } + return value || ''; + }; + + this.initialize.apply(this, arguments); +}; + + +kss.dnd.isValidDropTarget = function(handler) { + var dnd = kss.dnd; + var dataTransfer = dnd._dataTransfer; + if (!dataTransfer || dnd._dropEffect == 'none') { + dnd._isValidDropTarget = false; + } + else if (handler) { + // We want to know all required data types of each action that + // is processed when an object is dropped. For that we evaluate + // all parameter providers that contain the provider "dragData". + // The real job is then done by the parameter provider "dragData" + // itself, see below. + handler._requiredDragDataTypes = []; + kss.each(handler.rule.actions, function(action) { + kss.each(action.props, function(value) { + if (/\bdragData\s*\(/.test(value)) { + handler._evalParam(value); + } + }); + kss.each(action.params, function(value) { + if (/\bdragData\s*\(/.test(value)) { + handler._evalParam(value); + } + }); + }); + var requiredDragData = handler._requiredDragDataTypes; + delete handler._requiredDragDataTypes; + // Now check if all requested data types are available. + // Only in this case we declare it as a valid drop target. + var isValid = true; + for (var i=0; i