diff options
Diffstat (limited to 'js/dojo/dojox/mdnd')
| -rw-r--r-- | js/dojo/dojox/mdnd/AreaManager.js | 709 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/AutoScroll.js | 197 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/DropIndicator.js | 85 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/LazyManager.js | 73 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/Moveable.js | 263 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/PureSource.js | 207 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/README | 94 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/adapter/DndFromDojo.js | 365 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/adapter/DndToDojo.js | 484 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/dropMode/DefaultDropMode.js | 338 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/dropMode/OverDropMode.js | 307 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/dropMode/VerticalDropMode.js | 348 | ||||
| -rw-r--r-- | js/dojo/dojox/mdnd/resources/dnd.css | 93 |
13 files changed, 3563 insertions, 0 deletions
diff --git a/js/dojo/dojox/mdnd/AreaManager.js b/js/dojo/dojox/mdnd/AreaManager.js new file mode 100644 index 0000000..e7c09e6 --- /dev/null +++ b/js/dojo/dojox/mdnd/AreaManager.js @@ -0,0 +1,709 @@ +//>>built +define("dojox/mdnd/AreaManager", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/connect","dojo/_base/window", + "dojo/_base/array","dojo/query","dojo/_base/html","./Moveable"],function(dojo){ + var am = dojo.declare( + "dojox.mdnd.AreaManager", + null, + { + // summary: + // Drag And Drop manager + + // autoRefresh: Boolean + // Enable the refresh of registered areas on drag start. + autoRefresh: true, + + + // areaClass: String + // CSS class enabled an area if areaClass is defined + areaClass: "dojoxDndArea", + + // dragHandleClass: String + // CSS class enabled a drag handle. + dragHandleClass: "dojoxDragHandle", + + constructor: function(){ + // summary: + // Constructor of AreaManager class. + // Initialize arrays, connects and subscribes. + + //console.log("dojox.mdnd.AreaManager ::: constructor"); + this._areaList = []; + this.resizeHandler = dojo.connect(dojo.global,"onresize", this, function(){ + this._dropMode.updateAreas(this._areaList); + }); + + this._oldIndexArea = this._currentIndexArea = this._oldDropIndex = this._currentDropIndex = this._sourceIndexArea = this._sourceDropIndex = -1; + }, + + init: function(){ + // summary: + // Initialize the manager by calling the registerByClass method + + //console.log("dojox.mdnd.AreaManager ::: init"); + this.registerByClass(); + }, + + registerByNode: function(/*DOMNode*/area, /*Boolean*/notInitAreas){ + // summary: + // To register Dnd Area : insert the DndArea using the specific sort of dropMode. + // area: + // a DOM node corresponding to the Dnd Area + // notInitAreas: + // if false or undefined, init the areas. + + //console.log("dojox.mdnd.AreaManager ::: registerByNode", area); + var index = this._getIndexArea(area); + if(area && index == -1){ + var acceptType = area.getAttribute("accept"); + var accept = (acceptType) ? acceptType.split(/\s*,\s*/) : ["text"]; + var obj = { + 'node': area, + 'items': [], + 'coords': {}, + 'margin': null, + 'accept': accept, + 'initItems': false + }; + dojo.forEach(this._getChildren(area), function(item){ + this._setMarginArea(obj, item); + obj.items.push(this._addMoveableItem(item)); + }, this); + this._areaList = this._dropMode.addArea(this._areaList, obj); + if(!notInitAreas){ + this._dropMode.updateAreas(this._areaList); + } + dojo.publish("/dojox/mdnd/manager/register",[area]); + } + }, + + registerByClass: function(){ + // summary: + // Register all Dnd Areas identified by the attribute areaClass : + // insert Dnd Areas using the specific sort of dropMode. + + //console.log("dojox.mdnd.AreaManager ::: registerByClass"); + dojo.query('.'+this.areaClass).forEach(function(area){ + this.registerByNode(area, true); + }, this); + this._dropMode.updateAreas(this._areaList); + }, + + unregister: function(/*DOMNode*/area){ + // summary: + // Unregister a D&D Area and its children into the AreaManager. + // area: + // A node corresponding to the D&D Area. + // returns: + // True if the area is found and unregistered. + + //console.log("dojox.mdnd.AreaManager ::: unregister"); + var index = this._getIndexArea(area); + if(index != -1){ + dojo.forEach(this._areaList[index].items, function(item){ + this._deleteMoveableItem(item); + }, this); + this._areaList.splice(index,1); + // refresh target area + this._dropMode.updateAreas(this._areaList); + return true; // Boolean + } + return false; // Boolean + }, + + _addMoveableItem: function(/*DOMNode*/node){ + // summary: + // Create a draggable item with a DOM node. + // node: + // A child of the D&D Area. + // returns: + // The draggable item. + // tags: + // protected + + //console.log("dojox.mdnd.AreaManager ::: _addMoveableItem"); + node.setAttribute("tabIndex", "0"); + var handle = this._searchDragHandle(node); + var moveable = new dojox.mdnd.Moveable({ 'handle': handle, 'skip': true }, node); + // add a css style : + dojo.addClass(handle || node, "dragHandle"); + var type = node.getAttribute("dndType"); + var item = { + 'item': moveable, + 'type': type ? type.split(/\s*,\s*/) : ["text"], + 'handlers': [dojo.connect(moveable, "onDragStart", this, "onDragStart")] + } + // connect to the uninitialize method of dijit._Widget to delete a moveable before a destruct + if(dijit && dijit.byNode){ + var widget = dijit.byNode(node); + if(widget){ + item.type = widget.dndType ? widget.dndType.split(/\s*,\s*/) : ["text"]; + item.handlers.push( + dojo.connect(widget, "uninitialize", this, function(){ + this.removeDragItem(node.parentNode, moveable.node); + }) + ); + } + } + return item; // Object + }, + + _deleteMoveableItem: function(/*Object*/ objItem){ + // summary: + // Delete the Moveable object associated with a node. + // item: + // A moveable Object. + // tags: + // protected + + //console.log("dojox.mdnd.AreaManager ::: _deleteMoveableItem", objItem); + // disconnect the handle + dojo.forEach(objItem.handlers, function(handler){ + dojo.disconnect(handler); + }); + // delete css style : + var node = objItem.item.node, + handle = this._searchDragHandle(node); + dojo.removeClass(handle || node, "dragHandle"); + // call destroy of Moveable class + objItem.item.destroy(); + }, + + _getIndexArea: function(/*DOMNode*/area){ + // summary: + // Get the index of an area. + // area: + // A moveable Object. + // returns: + // area index or -1 + // tags: + // protected + + //console.log("dojox.mdnd.AreaManager ::: _getIndexArea"); + if(area){ + for(var i = 0; i < this._areaList.length; i++){ + if(this._areaList[i].node === area){ + return i; // Integer + } + } + } + return -1; // Integer + }, + + _searchDragHandle: function(/*DOMNode*/node){ + // summary: + // Return the node which contains the first specific CSS class handle. + // node: + // A child of the D&D Area. + // returns: + // The drag handle node. + // tags: + // protected + + //console.log("dojox.mdnd.AreaManager ::: _searchDragHandle"); + if(node){ + var cssArray = this.dragHandleClass.split(' '), + length = cssArray.length, + queryCss = ""; + dojo.forEach(cssArray, function(css, i){ + queryCss += "." + css; + if(i != length - 1){ + queryCss += ", "; + } + }); + return dojo.query(queryCss, node)[0]; // DomNode + } + }, + + addDragItem: function(/*DOMNode*/area, /*DOMNode*/node, /*Integer*/index, /*Boolean*/notCheckParent){ + // summary: + // To add an item programmatically. + // area: + // a node corresponding to the D&D Area + // node: + // the node which has to be treated. + // index: + // the place in the area + // noCheckParent: + // if true, doesn't check if node has a parent. + // returns: + // True if the node has been inserted else false. + + //console.log("dojox.mdnd.AreaManager ::: addDragItem"); + var add = true; + if(!notCheckParent){ + add = area && node && (node.parentNode === null || (node.parentNode && node.parentNode.nodeType !== 1)); + } + if(add){ + var indexArea = this._getIndexArea(area); + if(indexArea !== -1){ + var item = this._addMoveableItem(node), + items = this._areaList[indexArea].items; + if(0 <= index && index < items.length){ + var firstListChild = items.slice(0, index), + lastListChild = items.slice(index, items.length); + firstListChild[firstListChild.length] = item; + this._areaList[indexArea].items = firstListChild.concat(lastListChild); + area.insertBefore(node, items[index].item.node); + } + else{ + this._areaList[indexArea].items.push(item); + area.appendChild(node); + } + this._setMarginArea(this._areaList[indexArea], node); + this._areaList[indexArea].initItems = false; + return true; // Boolean + } + } + return false; // Boolean + }, + + removeDragItem: function(/*DOMNode*/area, /*DOMNode*/node){ + // summary: + // Delete a moveable item programmatically. The node is removed from the area. + // area: + // A node corresponding to the DndArea. + // node: + // The node which has to be treated. + // returns: + // the removed node + + //console.log("dojox.mdnd.AreaManager ::: removeDragItem"); + var index = this._getIndexArea(area); + if(area && index !== -1){ + var items = this._areaList[index].items; + for(var j = 0; j < items.length; j++){ + if(items[j].item.node === node){ + this._deleteMoveableItem(items[j]); + // delete item of the array + items.splice(j, 1); + return area.removeChild(node); // Object + } + } + } + return null; + }, + + _getChildren: function(/*DOMNode*/area){ + // summary: + // Get the children of a D&D area. + // area: + // A DnD area. + // returns: + // The children of a DnD area + // tags: + // protected + + //console.log("dojox.mdnd.AreaManager ::: _getChildren"); + var children = []; + dojo.forEach(area.childNodes, function(child){ + // delete \n + if(child.nodeType == 1){ + if(dijit && dijit.byNode){ + var widget = dijit.byNode(child); + if(widget){ + if(!widget.dragRestriction){ + children.push(child); + } + } + else{ + children.push(child); + } + } + else{ + children.push(child); + } + } + }); + return children; //Array + }, + + _setMarginArea: function(/*Object*/area,/*DOMNode*/node){ + // summary: + // Set the value of margin in the data type of areaManager + // only when the margin has never been computed. + // area: + // The object of a D&D Area. + // node: + // The node which contains margins + // tags: + // protected + + //console.log("dojox.mdnd.AreaManager ::: _setMarginArea"); + if(area && area.margin === null && node){ + area.margin = dojo._getMarginExtents(node); + } + }, + + findCurrentIndexArea: function(/*Object*/coords, /*Object*/size){ + // summary: + // find the nearest target area according to coordinates. + // Coordinates are representing by an object : for example, {'x':10,'y':10} + // coords: + // an object encapsulating X and Y position + // size: + // an object encapsulating the area size + // returns: + // an index of area + + //console.log("dojox.mdnd.AreaManager ::: findCurrentIndexArea"); + this._oldIndexArea = this._currentIndexArea; + this._currentIndexArea = this._dropMode.getTargetArea(this._areaList, coords, this._currentIndexArea); + if(this._currentIndexArea != this._oldIndexArea){ + if(this._oldIndexArea != -1){ + this.onDragExit(coords, size); + } + if(this._currentIndexArea != -1){ + this.onDragEnter(coords, size); + } + } + return this._currentIndexArea; //Integer + }, + + _isAccepted: function(/*Array*/ type, /*Array*/ accept){ + // summary: + // True if user can drop widget on this node. + // type: + // Array containing item type + // accept: + // Array containing types + this._accept = false; + for(var i = 0; i < accept.length; ++i){ + for(var j = 0; j < type.length;++j){ + if(type[j] == accept[i]){ + this._accept = true; + break; + } + } + } + }, + + onDragStart: function(/*DOMNode*/node, /*Object*/coords, /*Object*/size){ + // summary: + // Initialize the drag (see dojox.mdnd.Moveable.initOffsetDrag()) + // node: + // The node which is about to be dragged + // coords: + // an object encapsulating X and Y position + // size: + // an object encapsulating width and height values + // tags: + // callback + + //console.log("dojox.mdnd.AreaManager ::: onDragStart"); + if(this.autoRefresh){ + this._dropMode.updateAreas(this._areaList); + } + + // Create the cover : + var _html = (dojo.isWebKit) ? dojo.body() : dojo.body().parentNode; + if(!this._cover){ + this._cover = dojo.create('div', { + 'class': "dndCover" + }); + this._cover2 = dojo.clone(this._cover); + dojo.addClass(this._cover2, "dndCover2"); + } + var h = _html.scrollHeight+"px"; + this._cover.style.height = this._cover2.style.height = h; + dojo.body().appendChild(this._cover); + dojo.body().appendChild(this._cover2); + + this._dragStartHandler = dojo.connect(node.ownerDocument, "ondragstart", dojo, "stopEvent"); + // to know the source + this._sourceIndexArea = this._lastValidIndexArea = this._currentIndexArea = this._getIndexArea(node.parentNode); + // delete the dragItem into the source area + var sourceArea = this._areaList[this._sourceIndexArea]; + var children = sourceArea.items; + for(var i = 0; i < children.length; i++){ + if(children[i].item.node == node){ + this._dragItem = children[i]; + this._dragItem.handlers.push(dojo.connect(this._dragItem.item, "onDrag", this, "onDrag")); + this._dragItem.handlers.push(dojo.connect(this._dragItem.item, "onDragEnd", this, "onDrop")); + children.splice(i,1); + this._currentDropIndex = this._sourceDropIndex = i; + break; + } + } + var nodeRef = null; + if(this._sourceDropIndex !== sourceArea.items.length){ + nodeRef = sourceArea.items[this._sourceDropIndex].item.node; + } + // IE7 OPTIMIZATION + if(dojo.isIE > 7){ + // connect these events on the cover + this._eventsIE7 = [ + dojo.connect(this._cover, "onmouseover", dojo, "stopEvent"), + dojo.connect(this._cover, "onmouseout", dojo, "stopEvent"), + dojo.connect(this._cover, "onmouseenter", dojo, "stopEvent"), + dojo.connect(this._cover, "onmouseleave", dojo, "stopEvent") + ]; + } + + var s = node.style; + s.left = coords.x+"px"; + s.top = coords.y+"px"; + // attach the node to the cover + if(s.position == "relative" || s.position == ""){ + s.position = "absolute"; // enforcing the absolute mode + } + this._cover.appendChild(node); + + this._dropIndicator.place(sourceArea.node, nodeRef, size); + // add a style to place the _dragNode in foreground + dojo.addClass(node, "dragNode"); + // A dragged node is always draggable in this source area. + this._accept = true; + dojo.publish("/dojox/mdnd/drag/start",[node, sourceArea, this._sourceDropIndex]); + }, + + onDragEnter: function(/*Object*/coords, /*Object*/size){ + // summary: + // Optionally called by the getTargetArea method of TargetFinder class. + // coords: + // coordinates of the dragged Node. + // size: + // size of the dragged Node. + // tags: + // callback + + //console.log("dojox.mdnd.AreaManager ::: onDragEnter", coords, size); + if(this._currentIndexArea === this._sourceIndexArea){ + this._accept = true; + } + else{ + this._isAccepted(this._dragItem.type, this._areaList[this._currentIndexArea].accept); + } + }, + + onDragExit: function(/*Object*/coords, /*Object*/size){ + // summary: + // Optionally called by the getTargetArea method of TargetFinder class. + // coords: + // coordinates of the dragged Node. + // size: + // size of the dragged Node. + // tags: + // callback + + //console.log("dojox.mdnd.AreaManager ::: onDragExit"); + this._accept = false; + }, + + onDrag: function(/*DOMNode*/node, /*Object*/coords, /*Object*/size, /*Object*/mousePosition){ + // summary: + // Occurs when the dojo.dnd.Moveable.onDrag is fired. + // Search the nearest target area and called the placeDropIndicator + // node: + // The node which is dragged + // coords: + // an object encapsulating X and Y position + // size: + // an object encapsulating width and height values + // mousePosition: + // coordinates of mouse + // tags: + // callback + + //console.log("dojox.mdnd.AreaManager ::: onDrag", node, ",", coords,size); + var coordinates = this._dropMode.getDragPoint(coords, size, mousePosition); + this.findCurrentIndexArea(coordinates, size); + if(this._currentIndexArea !== -1 && this._accept){ + this.placeDropIndicator(coordinates, size); + } + }, + + placeDropIndicator: function(/*Object*/coords, /*Object*/size){ + // summary: + // Search the right place to insert the dropIndicator and display the dropIndicator. + // coords: + // an object encapsulating X and Y position + // size: + // an object encapsulating width and height values + // returns: + // the current drop index + + //console.log("dojox.mdnd.AreaManager ::: placeDropIndicator"); + //keep old drop Index + this._oldDropIndex = this._currentDropIndex; + // calculate all children marker (see VerticalDropMode.initItems()) + var area = this._areaList[this._currentIndexArea]; + if(!area.initItems){ + this._dropMode.initItems(area); + } + //get the index where the drop has to be placed. + this._currentDropIndex = this._dropMode.getDropIndex(area, coords); + if(!(this._currentIndexArea === this._oldIndexArea && this._oldDropIndex === this._currentDropIndex)){ + this._placeDropIndicator(size); + } + return this._currentDropIndex; //Integer + }, + + _placeDropIndicator: function(/*Object*/size){ + // summary: + // place the dropIndicator + // size: + // an object encapsulating width and height values + // tags: + // protected + + var oldArea = this._areaList[this._lastValidIndexArea]; + var currentArea = this._areaList[this._currentIndexArea]; + //refresh the previous area after moving out the drop indicator + this._dropMode.refreshItems(oldArea, this._oldDropIndex, size, false); + // place dropIndicator + var node = null; + if(this._currentDropIndex != -1){ + node = currentArea.items[this._currentDropIndex].item.node; + } + this._dropIndicator.place(currentArea.node, node); + this._lastValidIndexArea = this._currentIndexArea; + //refresh the current area after placing the drop indicator + this._dropMode.refreshItems(currentArea, this._currentDropIndex, size, true); + }, + + onDropCancel: function(){ + // summary: + // Cancel the drop. + // The dragNode returns into the source. + // tags: + // callback + + //console.log("dojox.mdnd.AreaManager ::: onDropCancel"); + if(!this._accept){ + var index = this._getIndexArea(this._dropIndicator.node.parentNode); + if(index != -1){ + this._currentIndexArea = index; + } + else{ + // case if the dropIndicator is in the area which has been unregistered during the drag. + // chose by default the first area. + this._currentIndexArea = 0; + } + } + }, + + onDrop: function(/*DOMNode*/node){ + // summary: + // Drop the dragged item where the dropIndicator is displayed. + // node: + // The node which is about to be dropped + // tags: + // callback + + //console.log("dojox.mdnd.AreaManager ::: onDrop"); + //dropCancel + this.onDropCancel(); + var targetArea = this._areaList[this._currentIndexArea]; + dojo.removeClass(node, "dragNode"); + var style = node.style; + style.position = "relative"; + style.left = "0"; + style.top = "0"; + style.width = "auto"; + if(targetArea.node == this._dropIndicator.node.parentNode){ + targetArea.node.insertBefore(node, this._dropIndicator.node); + } + else{ + // case if the dropIndicator is in the area which has been unregistered during the drag. + targetArea.node.appendChild(node); + this._currentDropIndex = targetArea.items.length; + } + // add child into the new target area. + var indexChild = this._currentDropIndex; + if(indexChild == -1){ + indexChild = targetArea.items.length; + } + var children = targetArea.items; + var firstListArea = children.slice(0, indexChild); + var lastListArea = children.slice(indexChild, children.length); + firstListArea[firstListArea.length] = this._dragItem; + targetArea.items = firstListArea.concat(lastListArea); + + this._setMarginArea(targetArea, node); + dojo.forEach(this._areaList, function(obj){ + obj.initItems = false; + }); + // disconnect onDrop handler + dojo.disconnect(this._dragItem.handlers.pop()); + dojo.disconnect(this._dragItem.handlers.pop()); + this._resetAfterDrop(); + // remove the cover + if(this._cover){ + dojo.body().removeChild(this._cover); + dojo.body().removeChild(this._cover2); + } + dojo.publish("/dojox/mdnd/drop",[node, targetArea, indexChild]); + }, + + _resetAfterDrop: function(){ + // summary: + // reset manager properties after dropping an item + // tags: + // protected + + this._accept = false; + this._dragItem = null; + this._currentDropIndex = -1; + this._currentIndexArea = -1; + this._oldDropIndex = -1; + this._sourceIndexArea = -1; + this._sourceDropIndex = -1; + this._dropIndicator.remove(); + if(this._dragStartHandler){ + dojo.disconnect(this._dragStartHandler); + } + if(dojo.isIE > 7){ + dojo.forEach(this._eventsIE7, dojo.disconnect); + } + }, + + destroy: function(){ + // summary: + // Destroy the component. + + //console.log("dojox.mdnd.AreaManager ::: destroy"); + //see implementation of unregister() + while(this._areaList.length > 0){ + if(!this.unregister(this._areaList[0].node)){ + throw new Error("Error while destroying AreaManager"); + } + } + dojo.disconnect(this.resizeHandler); + this._dropIndicator.destroy(); + this._dropMode.destroy(); + if(dojox.mdnd.autoScroll){ + dojox.mdnd.autoScroll.destroy(); + } + if(this.refreshListener){ + dojo.unsubscribe(this.refreshListener); + } + // destroy the cover + if(this._cover){ + dojo._destroyElement(this._cover); + dojo._destroyElement(this._cover2); + delete this._cover; + delete this._cover2; + } + } + }); + + if(dijit && dijit._Widget){ + // Add a new property to widget + dojo.extend(dijit._Widget, { + // dndType: String + // Defines a type of widget. + dndType : "text" + }); + } + + dojox.mdnd._areaManager = null; + dojox.mdnd.areaManager = function(){ + // summary: + // Returns the current areaManager, creates one if it is not created yet. + if(!dojox.mdnd._areaManager){ + dojox.mdnd._areaManager = new dojox.mdnd.AreaManager(); + } + return dojox.mdnd._areaManager; // Object + }; + return am; +});
\ No newline at end of file diff --git a/js/dojo/dojox/mdnd/AutoScroll.js b/js/dojo/dojox/mdnd/AutoScroll.js new file mode 100644 index 0000000..ac5e3a7 --- /dev/null +++ b/js/dojo/dojox/mdnd/AutoScroll.js @@ -0,0 +1,197 @@ +//>>built +define("dojox/mdnd/AutoScroll", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/lang","dojo/_base/connect", + "dojo/_base/window"],function(dojo){ + var as = dojo.declare( + "dojox.mdnd.AutoScroll", + null, + { + // summary: + // Activate scrolling while dragging a widget. + + // interval: Integer + // default mouse move offset + interval: 3, + + // recursiveTimer: Integer + recursiveTimer: 10, + + // marginMouse: Integer + // Default mouse margin + marginMouse: 50, + + constructor: function(){ + //console.log("dojox.mdnd.AutoScroll ::: constructor "); + this.resizeHandler = dojo.connect(dojo.global,"onresize", this, function(){ + this.getViewport(); + }); + dojo.ready(dojo.hitch(this, "init")); + }, + + init: function(){ + //console.log("dojox.mdnd.AutoScroll ::: init "); + this._html = (dojo.isWebKit) ? dojo.body() : dojo.body().parentNode; + this.getViewport(); + }, + + getViewport:function(){ + // summary: + // Set the visible part of the window. Varies accordion to Navigator. + + //console.log("dojox.mdnd.AutoScroll ::: getViewport "); + var d = dojo.doc, dd = d.documentElement, w = window, b = dojo.body(); + if(dojo.isMozilla){ + this._v = { 'w': dd.clientWidth, 'h': w.innerHeight }; // Object + } + else if(!dojo.isOpera && w.innerWidth){ + this._v = { 'w': w.innerWidth, 'h': w.innerHeight }; // Object + } + else if(!dojo.isOpera && dd && dd.clientWidth){ + this._v = { 'w': dd.clientWidth, 'h': dd.clientHeight }; // Object + } + else if(b.clientWidth){ + this._v = { 'w': b.clientWidth, 'h': b.clientHeight }; // Object + } + }, + + setAutoScrollNode: function(/*Node*/node){ + // summary: + // set the node which is dragged + // node: + // node to scroll + + //console.log("dojox.mdnd.AutoScroll ::: setAutoScrollNode "); + this._node = node; + }, + + setAutoScrollMaxPage: function(){ + // summary: + // Set the hightest heigh and width authorized scroll. + + //console.log("dojox.mdnd.AutoScroll ::: setAutoScrollMaxPage "); + this._yMax = this._html.scrollHeight; + this._xMax = this._html.scrollWidth; + }, + + checkAutoScroll: function(/*Event*/e){ + // summary: + // Check if an autoScroll have to be launched. + + //console.log("dojox.mdnd.AutoScroll ::: checkAutoScroll"); + if(this._autoScrollActive){ + this.stopAutoScroll(); + } + this._y = e.pageY; + this._x = e.pageX; + if(e.clientX < this.marginMouse){ + this._autoScrollActive = true; + this._autoScrollLeft(e); + } + else if(e.clientX > this._v.w - this.marginMouse){ + this._autoScrollActive = true; + this._autoScrollRight(e); + } + if(e.clientY < this.marginMouse){ + this._autoScrollActive = true; + this._autoScrollUp(e); + + } + else if(e.clientY > this._v.h - this.marginMouse){ + this._autoScrollActive = true; + this._autoScrollDown(); + } + }, + + _autoScrollDown: function(){ + // summary: + // Manage the down autoscroll. + // tags: + // protected + + //console.log("dojox.mdnd.AutoScroll ::: _autoScrollDown "); + if(this._timer){ + clearTimeout(this._timer); + } + if(this._autoScrollActive && this._y + this.marginMouse < this._yMax){ + this._html.scrollTop += this.interval; + this._node.style.top = (parseInt(this._node.style.top) + this.interval) + "px"; + this._y += this.interval; + this._timer = setTimeout(dojo.hitch(this, "_autoScrollDown"), this.recursiveTimer); + } + }, + + _autoScrollUp: function(){ + // summary: + // Manage the up autoscroll. + // tags: + // protected + + //console.log("dojox.mdnd.AutoScroll ::: _autoScrollUp "); + if(this._timer){ + clearTimeout(this._timer); + } + if(this._autoScrollActive && this._y - this.marginMouse > 0){ + this._html.scrollTop -= this.interval; + this._node.style.top = (parseInt(this._node.style.top) - this.interval) + "px"; + this._y -= this.interval; + this._timer = setTimeout(dojo.hitch(this, "_autoScrollUp"),this.recursiveTimer); + } + }, + + _autoScrollRight: function(){ + // summary: + // Manage the right autoscroll. + // tags: + // protected + + //console.log("dojox.mdnd.AutoScroll ::: _autoScrollRight "); + if(this._timer){ + clearTimeout(this._timer); + } + if(this._autoScrollActive && this._x + this.marginMouse < this._xMax){ + this._html.scrollLeft += this.interval; + this._node.style.left = (parseInt(this._node.style.left) + this.interval) + "px"; + this._x += this.interval; + this._timer = setTimeout(dojo.hitch(this, "_autoScrollRight"), this.recursiveTimer); + } + }, + + _autoScrollLeft: function(/*Event*/e){ + // summary: + // Manage the left autoscroll. + // tags: + // protected + + //console.log("dojox.mdnd.AutoScroll ::: _autoScrollLeft "); + if(this._timer){ + clearTimeout(this._timer); + } + if(this._autoScrollActive && this._x - this.marginMouse > 0){ + this._html.scrollLeft -= this.interval; + this._node.style.left = (parseInt(this._node.style.left) - this.interval) + "px"; + this._x -= this.interval; + this._timer = setTimeout(dojo.hitch(this, "_autoScrollLeft"),this.recursiveTimer); + } + }, + + stopAutoScroll: function(){ + // summary: + // Stop the autoscroll. + + //console.log("dojox.mdnd.AutoScroll ::: stopAutoScroll "); + if(this._timer){ + clearTimeout(this._timer); + } + this._autoScrollActive = false; + }, + + destroy: function(){ + //console.log("dojox.mdnd.AutoScroll ::: destroy "); + dojo.disconnect(this.resizeHandler); + } + }); + + dojox.mdnd.autoScroll = null; + + dojox.mdnd.autoScroll = new dojox.mdnd.AutoScroll(); + return as; +}); diff --git a/js/dojo/dojox/mdnd/DropIndicator.js b/js/dojo/dojox/mdnd/DropIndicator.js new file mode 100644 index 0000000..ff2ca6b --- /dev/null +++ b/js/dojo/dojox/mdnd/DropIndicator.js @@ -0,0 +1,85 @@ +//>>built +define("dojox/mdnd/DropIndicator", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/html","./AreaManager"],function(dojo){ + var di = dojo.declare( + "dojox.mdnd.DropIndicator", + null, + { + // summary: + // DropIndicator managment for DnD. + + // node: DOMNode + // the drop indicator node + node : null, + + constructor: function(){ + //console.log("dojox.mdnd.DropIndicator ::: constructor"); + var dropIndicator = document.createElement("div"); + var subDropIndicator = document.createElement("div"); + dropIndicator.appendChild(subDropIndicator); + dojo.addClass(dropIndicator, "dropIndicator"); + this.node = dropIndicator; + }, + + place: function(/*Node*/area, /*Node*/nodeRef, /*Object*/size){ + // summary: + // Place the DropIndicator in the right place + // area: + // the dnd targer area node + // nodeRef: + // node where the dropIndicator have to be placed into the area + // dragNode: + // the node which is dragged + // returns: + // the node inserted or null if it crashes + + //console.log("dojox.mdnd.DropIndicator ::: place"); + if(size){ + this.node.style.height = size.h + "px"; + } + try{ + if(nodeRef){ + area.insertBefore(this.node, nodeRef); + } + else{ + // empty target area or last node => appendChild + area.appendChild(this.node); + } + return this.node; // DOMNode + }catch(e){ + return null; + } + }, + + remove: function(){ + // summary: + // remove the DropIndicator (not destroy) + + //console.log("dojox.mdnd.DropIndicator ::: remove"); + if(this.node){ + //FIX : IE6 problem + this.node.style.height = ""; + if(this.node.parentNode){ + this.node.parentNode.removeChild(this.node); + } + } + }, + + destroy: function(){ + // summary: + // destroy the dropIndicator + + //console.log("dojox.mdnd.DropIndicator ::: destroy"); + if(this.node){ + if(this.node.parentNode){ + this.node.parentNode.removeChild(this.node); + } + dojo._destroyElement(this.node); + delete this.node; + } + } + }); + + dojox.mdnd.areaManager()._dropIndicator = new dojox.mdnd.DropIndicator(); + + return di; +}); diff --git a/js/dojo/dojox/mdnd/LazyManager.js b/js/dojo/dojox/mdnd/LazyManager.js new file mode 100644 index 0000000..0fdd194 --- /dev/null +++ b/js/dojo/dojox/mdnd/LazyManager.js @@ -0,0 +1,73 @@ +//>>built +define("dojox/mdnd/LazyManager", [ + "dojo/_base/kernel", // dojo.addOnUnload + "dojo/_base/lang", // dojo.hitch + "dojo/_base/declare", + "dojo/_base/html", // dojo.create, dojo.attr, dojo.addClass + "dojo/dnd/Manager", + "./PureSource" +],function(dojo){ + return dojo.declare( + "dojox.mdnd.LazyManager", + null, + { + // summary: + // This class allows to launch a drag and drop dojo on the fly. + + constructor: function(){ + //console.log("dojox.mdnd.LazyManager ::: constructor"); + this._registry = {}; + // initialization of the _fakeSource to enabled DragAndDrop : + this._fakeSource = new dojox.mdnd.PureSource(dojo.create("div"), { + 'copyOnly': false + }); + this._fakeSource.startup(); + dojo.addOnUnload(dojo.hitch(this, "destroy")); + this.manager = dojo.dnd.manager(); + }, + + getItem: function(/*DOMNode*/draggedNode){ + //console.log("dojox.mdnd.LazyManager ::: getItem"); + var type = draggedNode.getAttribute("dndType"); + return { + 'data' : draggedNode.getAttribute("dndData") || draggedNode.innerHTML, + 'type' : type ? type.split(/\s*,\s*/) : ["text"] + } + }, + + startDrag: function(/*Event*/e, /*DOMNode?*/draggedNode){ + // summary: + // launch a dojo drag and drop on the fly. + + //console.log("dojox.mdnd.LazyManager ::: startDrag"); + draggedNode = draggedNode || e.target; + if(draggedNode){ + var m = this.manager, + object = this.getItem(draggedNode); + if(draggedNode.id == ""){ + dojo.attr(draggedNode, "id", dojo.dnd.getUniqueId()); + } + dojo.addClass(draggedNode, "dojoDndItem"); + this._fakeSource.setItem(draggedNode.id, object); + m.startDrag(this._fakeSource, [draggedNode], false); + m.onMouseMove(e); + } + }, + + cancelDrag: function(){ + // summary: + // cancel a drag and drop dojo on the fly. + + //console.log("dojox.mdnd.LazyManager ::: cancelDrag"); + var m = this.manager; + m.target = null; + m.onMouseUp(); + }, + + + destroy: function(){ + //console.log("dojox.mdnd.LazyManager ::: destroy"); + this._fakeSource.destroy(); + } + }); +}); diff --git a/js/dojo/dojox/mdnd/Moveable.js b/js/dojo/dojox/mdnd/Moveable.js new file mode 100644 index 0000000..43eebf2 --- /dev/null +++ b/js/dojo/dojox/mdnd/Moveable.js @@ -0,0 +1,263 @@ +//>>built +define("dojox/mdnd/Moveable", [ + "dojo/_base/kernel", + "dojo/_base/array", + "dojo/_base/connect", + "dojo/_base/declare", + "dojo/_base/event", + "dojo/_base/html", + "dojo/_base/sniff", + "dojo/_base/window" +],function(dojo){ + return dojo.declare( + "dojox.mdnd.Moveable", + null, + { + // summary: + // Allow end-users to track a DOM node into the web page + + // handle: DOMNode + // The node on which the user clicks to drag the main node. + handle: null, + + // skip: Boolean + // A flag to control a drag action if a form element has been focused. + // If true, the drag action is not executed. + skip: true, + + // dragDistance: Integer + // The user clicks on the handle, but the drag action will really begin + // if he tracks the main node to more than 3 pixels. + dragDistance: 3, + + constructor: function(/*Object*/params, /*DOMNode*/node){ + // summary: + // Configure parameters and listen to mousedown events from handle + // node. + // params: + // Hash of parameters + // node: + // The draggable node + + //console.log("dojox.mdnd.Moveable ::: constructor"); + this.node = dojo.byId(node); + + this.d = this.node.ownerDocument; + + if(!params){ params = {}; } + this.handle = params.handle ? dojo.byId(params.handle) : null; + if(!this.handle){ this.handle = this.node; } + this.skip = params.skip; + this.events = [ + dojo.connect(this.handle, "onmousedown", this, "onMouseDown") + ]; + if(dojox.mdnd.autoScroll){ + this.autoScroll = dojox.mdnd.autoScroll; + } + + }, + + isFormElement: function(/*DOMEvent*/ e){ + // summary: + // identify the type of target node associated with a DOM event. + // e: + // a DOM event + // returns: + // if true, the target is one of those specific nodes. + + //console.log("dojox.mdnd.Moveable ::: isFormElement"); + var t = e.target; + if(t.nodeType == 3 /*TEXT_NODE*/){ + t = t.parentNode; + } + return " a button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0; // Boolean + }, + + onMouseDown: function(/*DOMEvent*/e){ + // summary: + // Occurs when the user clicks on the handle node. + // Skip the drag action if a specific node is targeted. + // Listens to mouseup and mousemove events on to the HTML document. + // e: + // a DOM event + // tags: + // callback + + //console.log("dojox.mdnd.Moveable ::: onMouseDown"); + if(this._isDragging){ return;} + var isLeftButton = (e.which || e.button) == 1; + if(!isLeftButton){ + return; + } + if(this.skip && this.isFormElement(e)){ return; } + if(this.autoScroll){ + this.autoScroll.setAutoScrollNode(this.node); + this.autoScroll.setAutoScrollMaxPage(); + } + this.events.push(dojo.connect(this.d, "onmouseup", this, "onMouseUp")); + this.events.push(dojo.connect(this.d, "onmousemove", this, "onFirstMove")); + this._selectStart = dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent); + this._firstX = e.clientX; + this._firstY = e.clientY; + dojo.stopEvent(e); + }, + + onFirstMove: function(/*DOMEvent*/e){ + // summary: + // Occurs when the user moves the mouse after clicking on the + // handle. + // Determinate when the drag action will have to begin (see + // dragDistance). + // e: + // A DOM event + // tags: + // callback + + //console.log("dojox.mdnd.Moveable ::: onFirstMove"); + dojo.stopEvent(e); + var d = (this._firstX - e.clientX) * (this._firstX - e.clientX) + + (this._firstY - e.clientY) * (this._firstY - e.clientY); + if(d > this.dragDistance * this.dragDistance){ + this._isDragging = true; + dojo.disconnect(this.events.pop()); + dojo.style(this.node, "width", dojo.contentBox(this.node).w + "px"); + this.initOffsetDrag(e); + this.events.push(dojo.connect(this.d, "onmousemove", this, "onMove")); + } + }, + + initOffsetDrag: function(/*DOMEvent*/e){ + // summary: + // Initialize the gap between main node coordinates and the clicked point. + // Call the onDragStart method. + // e: + // A DOM event + + //console.log("dojox.mdnd.Moveable ::: initOffsetDrag"); + this.offsetDrag = { 'l': e.pageX, 't': e.pageY }; + var s = this.node.style; + var position = dojo.position(this.node, true); + /*if(s.position == "relative" || s.position == ""){ + s.position = "absolute"; // enforcing the absolute mode + }*/ + this.offsetDrag.l = position.x - this.offsetDrag.l; + this.offsetDrag.t = position.y - this.offsetDrag.t; + var coords = { + 'x': position.x, + 'y': position.y + }; + this.size = { + 'w': position.w, + 'h': position.h + }; + // method to catch + this.onDragStart(this.node, coords, this.size); + }, + + onMove: function(/*DOMEvent*/e){ + // summary: + // Occurs when the user moves the mouse. + // Calls the onDrag method. + // e: + // a DOM event + // tags: + // callback + + //console.log("dojox.mdnd.Moveable ::: onMove"); + dojo.stopEvent(e); + // hack to avoid too many calls to onMove in IE8 causing sometimes slowness + if(dojo.isIE == 8 && new Date() - this.date < 20){ + return; + } + if(this.autoScroll){ + this.autoScroll.checkAutoScroll(e); + } + var coords = { + 'x': this.offsetDrag.l + e.pageX, + 'y': this.offsetDrag.t + e.pageY + }; + var s = this.node.style; + s.left = coords.x + "px"; + s.top = coords.y + "px"; + + // method to catch + this.onDrag(this.node, coords, this.size, {'x':e.pageX, 'y':e.pageY}); + if(dojo.isIE == 8){ + this.date = new Date(); + } + }, + + onMouseUp: function(/*DOMEvent*/e){ + // summary: + // Occurs when the user releases the mouse + // Calls the onDragEnd method. + // e: + // a DOM event + + if (this._isDragging){ + dojo.stopEvent(e); + this._isDragging = false; + if(this.autoScroll){ + this.autoScroll.stopAutoScroll(); + } + delete this.onMove; + this.onDragEnd(this.node); + this.node.focus(); + } + dojo.disconnect(this.events.pop()); + dojo.disconnect(this.events.pop()); + }, + + onDragStart: function(/*DOMNode*/node, /*Object*/coords, /*Object*/size){ + // summary: + // Stub function. + // Notes : border box model + // node: + // a DOM node + // coords: + // absolute position of the main node + // size: + // an object encapsulating width an height values + // tags: + // callback + + }, + + onDragEnd: function(/*DOMNode*/node){ + // summary: + // Stub function + // Notes : Coordinates don't contain margins + // node: + // a DOM node + // tags: + // callback + + }, + + onDrag: function(/*DOMNode*/node, /*Object*/coords, /*Object*/size, /*Object*/mousePosition){ + // summary: + // Stub function. + // Notes : border box model for size value, margin box model for coordinates + // node: + // a DOM node + // coords: + // position of the main node (equals to css left/top properties) + // size: + // an object encapsulating width and height values + // mousePosition: + // coordiantes of mouse + // tags: + // callback + + }, + + destroy: function(){ + // summary: + // Delecte associated events + + // console.log("dojox.mdnd.Moveable ::: destroy"); + dojo.forEach(this.events, dojo.disconnect); + this.events = this.node = null; + } + }); +}); diff --git a/js/dojo/dojox/mdnd/PureSource.js b/js/dojo/dojox/mdnd/PureSource.js new file mode 100644 index 0000000..efb0cd2 --- /dev/null +++ b/js/dojo/dojox/mdnd/PureSource.js @@ -0,0 +1,207 @@ +//>>built +define("dojox/mdnd/PureSource", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/html","dojo/_base/connect", + "dojo/_base/array","dojo/dnd/Selector","dojo/dnd/Manager"],function(dojo){ + return dojo.declare( + "dojox.mdnd.PureSource", + dojo.dnd.Selector, + { + // summary: + // A Source Object, which can be used only as a DnD source. + // A Source can contained several dnd items. + // A dnd item is not a source. + + horizontal: false, + copyOnly: true, + skipForm: false, + withHandles: false, + isSource: true, + targetState: "Disabled", + generateText: true, + + constructor: function(/*DOMNode|String*/node, /*dojo.dnd.__SourceArgs?*/params){ + // summary: + // Initialize a new PureSource. + // node: + // Node or node's id to build the source on. + // params: + // Any property of this class may be configured via the params + // object which is mixed-in to the 'dojo.dnd.Source' instance. + + //console.log('dojox.mdnd.PureSource ::: constructor'); + dojo.mixin(this, dojo.mixin({}, params)); + var type = this.accept; + + // class-specific variables + this.isDragging = false; + this.mouseDown = false; + + // states + this.sourceState = ""; + dojo.addClass(this.node, "dojoDndSource"); + if(this.horizontal){ + dojo.addClass(this.node, "dojoDndHorizontal"); + } + // set up events + this.topics = [ + dojo.subscribe("/dnd/cancel", this, "onDndCancel"), + dojo.subscribe("/dnd/drop", this, "onDndCancel") + ]; + }, + + onDndCancel: function(){ + // summary: + // Topic event processor for /dnd/cancel, called to cancel the Dnd + // operation. + // tags: + // callback + + //console.log('dojox.mdnd.PureSource ::: onDndCancel'); + this.isDragging = false; + this.mouseDown = false; + delete this.mouseButton; + }, + + copyState: function(/*Boolean*/keyPressed){ + // summary: + // Returns true, if we need to copy items, false to move. + // It is separated to be overwritten dynamically, if needed. + // keyPressed: + // The "copy" was pressed. + // returns: + // True, if we need to copy items, false to move. + + //console.log('dojox.mdnd.PureSource ::: copyState'); + return this.copyOnly || keyPressed; // Boolean + }, + + destroy: function(){ + // summary: + // Prepares the object to be garbage-collected. + + //console.log('dojox.mdnd.PureSource ::: destroy'); + dojox.mdnd.PureSource.superclass.destroy.call(this); + dojo.forEach(this.topics, dojo.unsubscribe); + this.targetAnchor = null; + }, + + markupFactory: function(/*Object*/params, /*DomNode*/node){ + // summary: + // Markup methods. + // params: + // ??? + // node: + // ??? + // returns: + // New dojox.mdnd.PureSource instance. + + //console.log('dojox.mdnd.PureSource ::: markupFactory'); + params._skipStartup = true; + return new dojox.mdnd.PureSource(node, params); + }, + + onMouseMove: function(/*Event*/e){ + // summary: + // Event processor for onmousemove. + // e: + // Mouse event. + + //console.log('dojox.mdnd.PureSource ::: onMouseMove'); + if(this.isDragging){ + return; + } + dojox.mdnd.PureSource.superclass.onMouseMove.call(this, e); + var m = dojo.dnd.manager(); + if(this.mouseDown && !this.isDragging && this.isSource){ + var nodes = this.getSelectedNodes(); + if(nodes.length){ + m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e))); + this.isDragging = true; + } + } + + }, + + onMouseDown: function(/*Event*/e){ + // summary: + // Event processor for onmousedown. + // e: + // Mouse event. + // tags: + // callback + + //console.log('dojox.mdnd.PureSource ::: onMouseDown'); + if(this._legalMouseDown(e) && (!this.skipForm || !dojo.dnd.isFormElement(e))){ + this.mouseDown = true; + this.mouseButton = e.button; + dojox.mdnd.PureSource.superclass.onMouseDown.call(this, e); + } + }, + + onMouseUp: function(/*Event*/e){ + // summary: + // Event processor for onmouseup. + // e: + // Mouse event + // tags: + // callback + + //console.log('.dnd.PureSource ::: onMouseUp'); + if(this.mouseDown){ + this.mouseDown = false; + dojox.mdnd.PureSource.superclass.onMouseUp.call(this, e); + } + }, + + onOverEvent: function(){ + // summary: + // Called once, when mouse is over our container. + // tags: + // callback + + //console.log('dojox.mdnd.PureSource ::: onOverEvent'); + dojox.mdnd.PureSource.superclass.onOverEvent.call(this); + dojo.dnd.manager().overSource(this); + }, + + onOutEvent: function(){ + // summary: + // Called once, when mouse is out our container. + // tags: + // callback + + //console.log('dojox.mdnd.PureSource ::: onOutEvent'); + dojox.mdnd.PureSource.superclass.onOutEvent.call(this); + dojo.dnd.manager().outSource(this); + }, + + _markDndStatus: function(/*Boolean*/copy){ + // summary: + // Changes source's state based on "copy" status. + // copy: + // Copy status. + // tags: + // protected + + //console.log('dojox.mdnd.PureSource ::: _markDndStatus'); + this._changeState("Source", copy ? "Copied" : "Moved"); + }, + + _legalMouseDown: function(/*Event*/e){ + // summary: + // Checks if user clicked on "approved" items. + // e: + // Mouse event. + // returns: + // True if user clicked on "approved" items. + // tags: + // protected + + //console.log('dojox.mdnd.PureSource ::: _legalMouseDown'); + if(!this.withHandles){ return true; } + for(var node = e.target; node && !dojo.hasClass(node, "dojoDndItem"); node = node.parentNode){ + if(dojo.hasClass(node, "dojoDndHandle")){ return true; } + } + return false; // Boolean + } + }); +});
\ No newline at end of file diff --git a/js/dojo/dojox/mdnd/README b/js/dojo/dojox/mdnd/README new file mode 100644 index 0000000..69d99f8 --- /dev/null +++ b/js/dojo/dojox/mdnd/README @@ -0,0 +1,94 @@ +------------------------------------------------------------------------------- +dojox.mdnd Experimental coordinates based moveable drag and drop. +------------------------------------------------------------------------------- +Version 1.1 +Release date: 09/04/2009 +------------------------------------------------------------------------------- +Project state: + +[AreaManager] beta +[AutoScroll] beta +[DropIndicator] beta +[Movable] beta +[PureSource] beta +[adapter/DndFromDojo] experimental +[adapter/DndToDojo] experimental +[dropMode/DefaultDropMode] beta +[dropMode/OverDropMode] experimental + +------------------------------------------------------------------------------- +Credits + +Erwan Morvillez (emorvillez), +Jean-Jacques Patard (jjpatard), +Jeff Cunat (jfcunat) + + +------------------------------------------------------------------------------- +Project description + +Alternative Drag and Drop solution based on coordinates of drag element and +targets instead of mouseover. It allows dragging directly the nodes (like +dojo.dnd.Moveable) instead of an avatar (as in dojo.dnd). dojo.dnd and +dojox.mdnd are compatible by using adapters. + +PureSource is just a rewrite of dojo.dnd.Source to only allow drag start and no +drop without testing acceptance. + +------------------------------------------------------------------------------- +Dependencies + + require Dojo Core + +------------------------------------------------------------------------------- +Installation: + + checkout: + + http://svn.dojotoolkit.org/src/dojox/trunk/mdnd/ + + and require via: + dojo.require("dojox.mdnd.AreaManager"); + +------------------------------------------------------------------------------- +Basic Usage: + + dojo.require("dojox.mdnd.AreaManager"); + dojo.require("dojox.mdnd.DropIndicator"); + dojo.require("dojox.mdnd.dropMode.DefaultDropMode"); + + var init = function(){ + var m = dojox.mdnd.areaManager(); + m.areaClass = "dndArea"; + m.dragHandleClass = "dragHandle"; + m.registerByClass(); + }; + + dojo.addOnLoad(init); + + ... + + <div style="position:absolute; top:80px; left:50px;"> + <h2>Accepts Type1 items</h2> + <div class="dndArea container" accept="type1"> + <div class="dndItem" dndType="type1"> + <div class="dragHandle">Item Type 1</div> + <div> + <p>Proin aliquet accumsan nunc. Duis nec tortor.</p> + + </div> + </div> + <div class="dndItem simpleBlock" dndType="type2"> + <div class="dragHandle">Item Type2</div> + <div> + <p>Proin aliquet accumsan nunc. Duis nec tortor.</p> + </div> + </div> + + </div> + + <div style="position:absolute; top:80px; left:350px;"> + <h2>Accepts Type2 items</h2> + <div class="dndArea container" accept="type2"> + </div> + </div> diff --git a/js/dojo/dojox/mdnd/adapter/DndFromDojo.js b/js/dojo/dojox/mdnd/adapter/DndFromDojo.js new file mode 100644 index 0000000..8f0a3f1 --- /dev/null +++ b/js/dojo/dojox/mdnd/adapter/DndFromDojo.js @@ -0,0 +1,365 @@ +//>>built +define("dojox/mdnd/adapter/DndFromDojo", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/connect","dojo/_base/array", + "dojo/_base/html","dojo/_base/window","dojox/mdnd/AreaManager","dojo/dnd/Manager"],function(dojo){ + var dfd = dojo.declare( + "dojox.mdnd.adapter.DndFromDojo", + null, + { + // summary + // Allow communication between Dojo dnd items and DojoX D&D areas + + // dropIndicatorSize: Object + // size by default of dropIndicator (display only into a D&D Area) + dropIndicatorSize : {'w':0,'h':50}, + + // dropIndicatorSize: Object + // size by default of dropIndicator (display only into a D&D Area) + dropIndicatorSize: {'w':0,'h':50}, + + // _areaManager: Object + // Reference to the current DojoX Dnd Manager + _areaManager: null, + + // _dojoManager + // Reference to the current Dojo Manager + _dojoManager: null, + + // _currentArea: Object + // The current Area on mouse over + _currentArea: null, + + // _oldArea: Object + // The old area the mouse has passed over + _oldArea: null, + + // _moveHandler: Object + // The handler of mouse connection + _moveHandler: null, + + // _subscribeHandler: Array + // The list of dojo dnd topics + _subscribeHandler: null, + + constructor: function(){ + this._areaManager = dojox.mdnd.areaManager(); + this._dojoManager = dojo.dnd.manager(); + this._currentArea = null; + this._moveHandler = null; + this.subscribeDnd(); + }, + + subscribeDnd: function(){ + // summary: + // Subscribe to somes topics of dojo drag and drop. + + //console.log(("dojox.mdnd.adapter.DndFromDojo ::: subscribeDnd"); + this._subscribeHandler = [ + dojo.subscribe("/dnd/start",this,"onDragStart"), + dojo.subscribe("/dnd/drop/before", this, "onDrop"), + dojo.subscribe("/dnd/cancel",this,"onDropCancel"), + dojo.subscribe("/dnd/source/over",this,"onDndSource") + ] + }, + + unsubscribeDnd: function(){ + // summary: + // Unsubscribe to some topics of dojo drag and drop. + + //console.log(("dojox.mdnd.adapter.DndFromDojo ::: unsubscribeDnd"); + dojo.forEach(this._subscribeHandler, dojo.unsubscribe); + }, + + _getHoverArea: function(/*Object*/ coords){ + // summary: + // Get a D&D dojoX area as a DOM node positioned under a specific point. + // coords: + // Object containing the coordinates x and y (mouse position) + // tags: + // protected + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: _getHoverArea"); + var x = coords.x; + var y = coords.y; + this._oldArea = this._currentArea; + this._currentArea = null; + var areas = this._areaManager._areaList; + for(var i = 0; i < areas.length; i++){ + var area = areas[i]; + var startX = area.coords.x; + var endX = startX + area.node.offsetWidth; + var startY = area.coords.y; + var endY = startY + area.node.offsetHeight; + // check if the coordinates mouse is in a D&D Area + if(startX <= x && x <= endX && startY <= y && y <= endY){ + this._areaManager._oldIndexArea = this._areaManager._currentIndexArea; + this._areaManager._currentIndexArea = i; + this._currentArea = area.node; + break; + } + } + if(this._currentArea != this._oldArea){ + if(this._currentArea == null){ + // case when the dragNode was in a D&D area but it's out now. + this.onDragExit(); + } + else if(this._oldArea == null){ + // case when the dragNode was out a D&D area but it's in now. + this.onDragEnter(); + } + else{ + // case when the dragNode was in a D&D area and enter in an other D&D area directly. + this.onDragExit(); + this.onDragEnter(); + } + } + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: _getHoverArea",this._dojoManager.avatar.node,this._currentArea,this._oldArea); + }, + + onDragStart: function(/*Object*/source, /*Array*/nodes, /*Boolean*/copy){ + // summary: + // Occurs when the "/dnd/start" topic is published. + // source: + // the source which provides items + // nodes: + // the list of transferred items + // copy: + // copy items, if true, move items otherwise + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: onDragStart"); + // catch the dragNode to get the type when it's necessary. + this._dragNode = nodes[0]; + this._copy = copy; this._source = source; + // Connect the onMouseMove : + // It's usefull to activate the detection of a D&D area and the dropIndicator place only if + // the dragNode is out of a the source dojo. The classic behaviour of the dojo source is kept. + this._outSourceHandler = dojo.connect(this._dojoManager, "outSource", this, function(){ + //dojo.disconnect(this._outSourceHandler); + if(this._moveHandler == null){ + this._moveHandler = dojo.connect(dojo.doc, "mousemove", this, "onMouseMove"); + } + }); + }, + + onMouseMove: function(/*DOMEvent*/e){ + // summary: + // Occurs when the user moves the mouse. + // e: + // the DOM event + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: onMouseMove"); + // calculate the coordonates of the mouse. + var coords = { + 'x': e.pageX, + 'y': e.pageY + }; + this._getHoverArea(coords); + // if a D&D area has been found and if it's accepted to drop this type of dragged node + if(this._currentArea && this._areaManager._accept){ + // specific case : a dropIndicator can be hidden (see onDndSource method) + if(this._areaManager._dropIndicator.node.style.visibility == "hidden"){ + this._areaManager._dropIndicator.node.style.visibility = ""; + dojo.addClass(this._dojoManager.avatar.node, "dojoDndAvatarCanDrop"); + } + // place the dropIndicator in D&D Area with a default size. + this._areaManager.placeDropIndicator(coords, this.dropIndicatorSize); + } + }, + + onDragEnter: function(){ + // summary: + // Occurs when the user drages an DOJO dnd item inside a D&D dojoX area. + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: onDragEnter"); + // Check if the type of dragged node is accepted in the selected D&D dojoX Area. + var _dndType = this._dragNode.getAttribute("dndType"); + // need to have an array as type + var type = (_dndType) ? _dndType.split(/\s*,\s*/) : ["text"]; + this._areaManager._isAccepted(type, this._areaManager._areaList[this._areaManager._currentIndexArea].accept); + // if the D&D dojoX Area accepts the drop, change the color of Avatar. + if(this._dojoManager.avatar){ + if(this._areaManager._accept){ + dojo.addClass(this._dojoManager.avatar.node, "dojoDndAvatarCanDrop"); + } + else{ + dojo.removeClass(this._dojoManager.avatar.node, "dojoDndAvatarCanDrop"); + } + } + }, + + onDragExit: function(){ + // summary: + // Occurs when the user leaves a D&D dojoX area after dragging an DOJO dnd item over it. + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: onDragExit"); + // if the dragged node exits of a D&D dojoX Area : + this._areaManager._accept = false; + // change color of avatar + if(this._dojoManager.avatar){ + dojo.removeClass(this._dojoManager.avatar.node, "dojoDndAvatarCanDrop"); + } + // reset all variables and remove the dropIndicator. + if(this._currentArea == null){ + this._areaManager._dropMode.refreshItems(this._areaManager._areaList[this._areaManager._oldIndexArea], this._areaManager._oldDropIndex, this.dropIndicatorSize, false); + this._areaManager._resetAfterDrop(); + } + else{ + this._areaManager._dropIndicator.remove(); + } + }, + + isAccepted: function(/*Node*/node, /*Object*/accept){ + // summary: + // Check if a dragNode is accepted into a dojo target. + // node: + // The dragged node. + // accept: + // Object containing the type accepted for a target dojo. + // returns: + // true if the dragged node is accepted in the target dojo. + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: isAccepted"); + var type = (node.getAttribute("dndType")) ? node.getAttribute("dndType") : "text"; + if(type && type in accept) + return true; // Boolean + else + return false; // Boolean + }, + + onDndSource: function(/*Object*/ source){ + // summary: + // Called when the mouse enters or exits of a source dojo. + // source: + // the dojo source/target + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: onDndSource",source); + // Only the case : "source dojo into a D&D dojoX Area" is treated. + if(this._currentArea == null){ + return; + } + if(source){ + // Enter in a source/target dojo. + // test if the type of draggedNode is accepted : + var accept = false; + if(this._dojoManager.target == source){ + accept = true; + } + else{ + accept = this.isAccepted(this._dragNode, source.accept); + } + if(accept){ + // disconnect the onMouseMove to disabled the search of a drop zone in the D&D dojoX Area. + dojo.disconnect(this._moveHandler); + this._currentArea = this._moveHandler = null; + // hidden the visibility of dojoX dropIndicator to prevent an offset when the dropIndicator disappears. + // test if drop indicator is visible before applaying hidden style. + var dropIndicator = this._areaManager._dropIndicator.node; + if(dropIndicator && dropIndicator.parentNode !== null && dropIndicator.parentNode.nodeType == 1) + dropIndicator.style.visibility = "hidden"; + } + else{ + // if the type of dragged node is not accepted in the target dojo, the color of avatar + // have to be the same that the color of D&D dojoX Area acceptance. + this._resetAvatar(); + } + } + else{ + // Exit of a source/target dojo. + // reconnect the onMouseMove to enabled the search of a drop zone in the D&D dojox Area. + if(!this._moveHandler) + this._moveHandler = dojo.connect(dojo.doc, "mousemove", this, "onMouseMove"); + + this._resetAvatar(); + } + }, + + _resetAvatar: function(){ + // summary: + // Function executed in onDndSource function to set the avatar + // acceptance according to the dojox DnD AreaManager Acceptance. + // It is used when The mouse exit a source/target dojo or if the + // dragged node is not accepted in dojo source / target. + // tags: + // protected + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: _resetAvatar"); + if(this._dojoManager.avatar){ + if(this._areaManager._accept){ + dojo.addClass(this._dojoManager.avatar.node, "dojoDndAvatarCanDrop"); + } + else{ + dojo.removeClass(this._dojoManager.avatar.node, "dojoDndAvatarCanDrop"); + } + } + }, + + onDropCancel: function(){ + // summary: + // Occurs when the "/dnd/cancel" topic is published. + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: onDropCancel"); + if(this._currentArea == null){ + // the dragged node is not in the D&D dojox Area => Cancel + this._areaManager._resetAfterDrop(); + dojo.disconnect(this._moveHandler); + dojo.disconnect(this._outSourceHandler); + this._currentArea = this._moveHandler = this._outSourceHandler = null; + } + else{ + // the dragged node is in the D&D dojox Area + // (catch when dragged node exits of a source/target dojo and stays in the same D&D dojox Area) + // dojo cancel the drop but it's authorized in the D&D Area + if(this._areaManager._accept){ + this.onDrop(this._source, [this._dragNode], this._copy, this._currentArea); + } + else{ + this._currentArea = null; + dojo.disconnect(this._outSourceHandler); + dojo.disconnect(this._moveHandler); + this._moveHandler = this._outSourceHandler = null; + } + } + }, + + onDrop: function(/*Object*/source, /*Array*/nodes, /*Boolean*/copy){ + // summary: + // Occurs when the user leaves a D&D dojox area after dragging an DOJO dnd item over it. + // source: + // the source which provides items + // nodes: + // the list of transferred items + // copy: + // copy items, if true, move items otherwise + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndFromDojo ::: onDrop", this._currentArea); + dojo.disconnect(this._moveHandler); + dojo.disconnect(this._outSourceHandler); + this._moveHandler = this._outSourceHandler = null; + if(this._currentArea){ + var dropIndex = this._areaManager._currentDropIndex; + dojo.publish("/dnd/drop/after", [source, nodes, copy, this._currentArea, dropIndex]); + this._currentArea = null; + } + if(this._areaManager._dropIndicator.node.style.visibility == "hidden"){ + this._areaManager._dropIndicator.node.style.visibility = ""; + } + this._areaManager._resetAfterDrop(); + } + }); + + dojox.mdnd.adapter._dndFromDojo = null; + dojox.mdnd.adapter._dndFromDojo = new dojox.mdnd.adapter.DndFromDojo(); + return dfd; +}); diff --git a/js/dojo/dojox/mdnd/adapter/DndToDojo.js b/js/dojo/dojox/mdnd/adapter/DndToDojo.js new file mode 100644 index 0000000..baaf9b1 --- /dev/null +++ b/js/dojo/dojox/mdnd/adapter/DndToDojo.js @@ -0,0 +1,484 @@ +//>>built +define("dojox/mdnd/adapter/DndToDojo", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/html","dojo/_base/connect", + "dojo/_base/window","dojo/_base/array","dojox/mdnd/PureSource","dojox/mdnd/LazyManager"],function(dojo){ + var dtd = dojo.declare( + "dojox.mdnd.adapter.DndToDojo", + null, + { + // summary: + // Allow communication between an item of dojox D&D area to a target dojo. + + // _dojoList: Array + // Array containing object references the dojo Target list + _dojoList: null, + + // _currentDojoArea: DOMNode + // Representing the current dojo area + _currentDojoArea: null, + + // _dojoxManager: dojox.mdnd.AreaManager + // The reference to the dojox AreaManager + _dojoxManager: null, + + // _dragStartHandler: Object + // Handle to keep start subscribe + _dragStartHandler: null, + + // _dropHandler: Object + // Handle to keep drop subscribe + _dropHandler: null, + + // _moveHandler: Object + // Handle to keep move subscribe + _moveHandler: null, + + // _moveUpHandler: Object + // Handle to kee move up subscribe + _moveUpHandler: null, + + // _draggedNode: DOMNode + // The current dragged node + _draggedNode: null, + + constructor: function(){ + this._dojoList = []; + this._currentDojoArea = null; + this._dojoxManager = dojox.mdnd.areaManager(); + this._dragStartHandler = dojo.subscribe("/dojox/mdnd/drag/start", this, function(node, sourceArea, sourceDropIndex){ + this._draggedNode = node; + this._moveHandler = dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"); + }); + this._dropHandler = dojo.subscribe("/dojox/mdnd/drop", this, function(node, targetArea, indexChild){ + if(this._currentDojoArea){ + dojo.publish("/dojox/mdnd/adapter/dndToDojo/cancel", [this._currentDojoArea.node, this._currentDojoArea.type, this._draggedNode, this.accept]); + } + this._draggedNode = null; + this._currentDojoArea = null; + dojo.disconnect(this._moveHandler); + }); + }, + + _getIndexDojoArea: function(/*node*/area){ + // summary: + // Check if a dojo area is registered. + // area: DOMNode + // A node corresponding to the target dojo. + // returns: + // The index of area if it's registered else -1. + // tags: + // protected + + //console.log('dojox.mdnd.adapter.DndToDojo ::: _getIndexDojoArea'); + if(area){ + for(var i = 0, l = this._dojoList.length; i < l; i++){ + if(this._dojoList[i].node === area){ + return i; + } + } + } + return -1; + }, + + _initCoordinates: function(/*DOMNode*/area){ + // summary: + // Initialize the coordinates of the target dojo. + // area: + // A registered DOM node. + // returns: + // An object which contains coordinates : *{x:0,y:,x1:0,y1:0}* + // tags: + // protected + + //console.log('dojox.mdnd.adapter.DndToDojo ::: _initCoordinates'); + if(area){ + var position = dojo.position(area, true), + coords = {}; + coords.x = position.x + coords.y = position.y + coords.x1 = position.x + position.w; + coords.y1 = position.y + position.h; + return coords; // Object + } + return null; + }, + + register: function(/*DOMNode*/area, /*String*/ type,/*Boolean*/ dojoTarget){ + // summary: + // Register a target dojo. + // The target is represented by an object containing : + // - the dojo area node + // - the type reference to identify a group node + // - the coords of the area to enable refresh position + // area: + // The DOM node which has to be registered. + // type: + // A String to identify the node. + // dojoTarger: + // True if the dojo D&D have to be enable when mouse is hover the registered target dojo. + + //console.log("dojox.mdnd.adapter.DndToDojo ::: registerDojoArea", area, type, dojoTarget); + if(this._getIndexDojoArea(area) == -1){ + var coords = this._initCoordinates(area), + object = { + 'node': area, + 'type': type, + 'dojo': (dojoTarget)?dojoTarget:false, + 'coords': coords + }; + this._dojoList.push(object); + // initialization of the _fakeSource to allow Dnd switching + if(dojoTarget && !this._lazyManager){ + this._lazyManager = new dojox.mdnd.LazyManager(); + } + } + }, + + unregisterByNode: function(/*DOMNode*/area){ + // summary: + // Unregister a target dojo. + // area: + // The DOM node of target dojo. + + //console.log("dojox.mdnd.adapter.DndToDojo ::: unregisterByNode", area); + var index = this._getIndexDojoArea(area); + // if area is registered + if(index != -1){ + this._dojoList.splice(index, 1); + } + }, + + unregisterByType: function(/*String*/type){ + // summary: + // Unregister several targets dojo having the same type passing in parameter. + // type: + // A String to identify dojo targets. + + //console.log("dojox.mdnd.adapter.DndToDojo ::: unregisterByType", type); + if(type){ + var tempList = []; + dojo.forEach(this._dojoList, function(item, i){ + if(item.type != type){ + tempList.push(item); + } + }); + this._dojoList = tempList; + } + }, + + unregister: function(){ + // summary: + // Unregister all targets dojo. + + //console.log("dojox.mdnd.adapter.DndToDojo ::: unregister"); + this._dojoList = []; + }, + + refresh: function(){ + // summary: + // Refresh the coordinates of all registered dojo target. + + //console.log("dojox.mdnd.adapter.DndToDojo ::: refresh"); + var dojoList = this._dojoList; + this.unregister(); + dojo.forEach(dojoList, function(dojo){ + dojo.coords = this._initCoordinates(dojo.node); + }, this); + this._dojoList = dojoList; + }, + + refreshByType: function(/*String*/ type){ + // summary: + // Refresh the coordinates of registered dojo target with a specific type. + // type: + // A String to identify dojo targets. + + //console.log("dojox.mdnd.adapter.DndToDojo ::: refresh"); + var dojoList = this._dojoList; + this.unregister(); + dojo.forEach(dojoList, function(dojo){ + if(dojo.type == type){ + dojo.coords = this._initCoordinates(dojo.node); + } + }, this); + this._dojoList = dojoList; + }, + + _getHoverDojoArea: function(/*Object*/coords){ + // summary: + // Check if the coordinates of the mouse is in a dojo target. + // coords: + // Coordinates of the mouse. + // tags: + // protected + + //console.log("dojox.mdnd.adapter.DndToDojo ::: _getHoverDojoArea"); + this._oldDojoArea = this._currentDojoArea; + this._currentDojoArea = null; + var x = coords.x; + var y = coords.y; + var length = this._dojoList.length; + for(var i = 0; i < length; i++){ + var dojoArea = this._dojoList[i]; + var coordinates = dojoArea.coords; + if(coordinates.x <= x && x <= coordinates.x1 && coordinates.y <= y && y <= coordinates.y1){ + this._currentDojoArea = dojoArea; + break; + } + } + }, + + onMouseMove: function(/*DOMEvent*/e){ + // summary: + // Call when the mouse moving after an onStartDrag of AreaManger. + // Check if the coordinates of the mouse is in a dojo target. + // e: + // Event object. + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndToDojo ::: onMouseMove"); + var coords = { + 'x': e.pageX, + 'y': e.pageY + }; + this._getHoverDojoArea(coords); + if(this._currentDojoArea != this._oldDojoArea){ + if(this._currentDojoArea == null){ + this.onDragExit(e); + } + else if(this._oldDojoArea == null){ + this.onDragEnter(e); + } + else{ + this.onDragExit(e); + this.onDragEnter(e); + } + } + }, + + isAccepted: function(/*DOMNode*/draggedNode, /*Object*/ target){ + // summary: + // Return true if the dragged node is accepted. + // This method has to be overwritten according to registered target. + + //console.log("dojox.mdnd.adapter.DndToDojo ::: isAccepted"); + return true; + }, + + + onDragEnter: function(/*DOMEvent*/e){ + // summary: + // Call when the mouse enters in a registered dojo target. + // e: + // The current Javascript Event. + // tags: + // callback + + //console.log("dojox.mdnd.adapter.DndToDojo ::: onDragEnter"); + // specific for drag and drop switch + if(this._currentDojoArea.dojo){ + // disconnect + dojo.disconnect(this._dojoxManager._dragItem.handlers.pop()); + dojo.disconnect(this._dojoxManager._dragItem.handlers.pop()); + //disconnect onmousemove of moveable item + //console.info("before",this._dojoxManager._dragItem.item.events.pop()); + dojo.disconnect(this._dojoxManager._dragItem.item.events.pop()); + dojo.body().removeChild(this._dojoxManager._cover); + dojo.body().removeChild(this._dojoxManager._cover2); + var node = this._dojoxManager._dragItem.item.node; + // hide dragNode : + // disconnect the dojoDndAdapter if it's initialize + if(dojox.mdnd.adapter._dndFromDojo){ + dojox.mdnd.adapter._dndFromDojo.unsubscribeDnd(); + } + dojo.style(node, { + 'position': "relative", + 'top': '0', + 'left': '0' + }); + // launch the drag and drop Dojo. + this._lazyManager.startDrag(e, node); + var handle = dojo.connect(this._lazyManager.manager, "overSource", this, function(){ + dojo.disconnect(handle); + if(this._lazyManager.manager.canDropFlag){ + // remove dropIndicator + this._dojoxManager._dropIndicator.node.style.display = "none"; + } + }); + + this.cancelHandler = dojo.subscribe("/dnd/cancel", this, function(){ + var moveableItem = this._dojoxManager._dragItem.item; + // connect onmousemove of moveable item + // need to reconnect the onmousedown of movable class. + moveableItem.events = [ + dojo.connect(moveableItem.handle, "onmousedown", moveableItem, "onMouseDown") + ]; + // replace the cover and the dragNode in the cover. + dojo.body().appendChild(this._dojoxManager._cover); + dojo.body().appendChild(this._dojoxManager._cover2); + this._dojoxManager._cover.appendChild(moveableItem.node); + + var objectArea = this._dojoxManager._areaList[this._dojoxManager._sourceIndexArea]; + var dropIndex = this._dojoxManager._sourceDropIndex; + var nodeRef = null; + if(dropIndex != objectArea.items.length + && dropIndex != -1){ + nodeRef = objectArea.items[this._dojoxManager._sourceDropIndex].item.node; + } + if(this._dojoxManager._dropIndicator.node.style.display == "none"){ + this._dojoxManager._dropIndicator.node.style.display == ""; + } + this._dojoxManager._dragItem.handlers.push(dojo.connect(this._dojoxManager._dragItem.item, "onDrag", this._dojoxManager, "onDrag")); + this._dojoxManager._dragItem.handlers.push(dojo.connect(this._dojoxManager._dragItem.item, "onDragEnd", this._dojoxManager, "onDrop")); + this._draggedNode.style.display = ""; + this._dojoxManager.onDrop(this._draggedNode); + dojo.unsubscribe(this.cancelHandler); + dojo.unsubscribe(this.dropHandler); + if(dojox.mdnd.adapter._dndFromDojo){ + dojox.mdnd.adapter._dndFromDojo.subscribeDnd(); + } + }); + this.dropHandler = dojo.subscribe("/dnd/drop/before", this, function(params){ + dojo.unsubscribe(this.cancelHandler); + dojo.unsubscribe(this.dropHandler); + this.onDrop(); + }); + } + else{ + this.accept = this.isAccepted(this._dojoxManager._dragItem.item.node, this._currentDojoArea); + if(this.accept){ + // disconnect + dojo.disconnect(this._dojoxManager._dragItem.handlers.pop()); + dojo.disconnect(this._dojoxManager._dragItem.handlers.pop()); + // remove dropIndicator + this._dojoxManager._dropIndicator.node.style.display = "none"; + if(!this._moveUpHandler){ + this._moveUpHandler = dojo.connect(dojo.doc, "onmouseup", this, "onDrop"); + } + } + } + // publish a topic + dojo.publish("/dojox/mdnd/adapter/dndToDojo/over",[this._currentDojoArea.node, this._currentDojoArea.type, this._draggedNode, this.accept]); + }, + + onDragExit: function(/*DOMEvent*/e){ + // summary: + // Call when the mouse exit of a registered dojo target. + // e: + // current javscript event + + //console.log("dojox.mdnd.adapter.DndToDojo ::: onDragExit",e, this._dojoxManager._dragItem.item); + // set the old height of dropIndicator. + if(this._oldDojoArea.dojo){ + // unsubscribe the topic /dnd/cancel and /dnd/drop/before + dojo.unsubscribe(this.cancelHandler); + dojo.unsubscribe(this.dropHandler); + // launch Drag and Drop + var moveableItem = this._dojoxManager._dragItem.item; + // connect onmousemove of moveable item + this._dojoxManager._dragItem.item.events.push(dojo.connect( + moveableItem.node.ownerDocument, + "onmousemove", + moveableItem, + "onMove" + )); + // replace the cover and the dragNode in the cover. + dojo.body().appendChild(this._dojoxManager._cover); + dojo.body().appendChild(this._dojoxManager._cover2); + this._dojoxManager._cover.appendChild(moveableItem.node); + // fix style : + var style = moveableItem.node.style; + style.position = "absolute"; + style.left = (moveableItem.offsetDrag.l + e.pageX)+"px"; + style.top = (moveableItem.offsetDrag.t + e.pageX)+"px"; + style.display = ""; + // stop dojoDrag + this._lazyManager.cancelDrag(); + // reconnect the dndFromDojo + if(dojox.mdnd.adapter._dndFromDojo){ + dojox.mdnd.adapter._dndFromDojo.subscribeDnd(); + } + if(this._dojoxManager._dropIndicator.node.style.display == "none"){ + this._dojoxManager._dropIndicator.node.style.display = ""; + } + // reconnect the areaManager. + this._dojoxManager._dragItem.handlers.push(dojo.connect(this._dojoxManager._dragItem.item, "onDrag", this._dojoxManager, "onDrag")); + this._dojoxManager._dragItem.handlers.push(dojo.connect(this._dojoxManager._dragItem.item, "onDragEnd", this._dojoxManager, "onDrop")); + this._dojoxManager._dragItem.item.onMove(e); + } + else{ + if(this.accept){ + // disconnect the mouseUp event. + if(this._moveUpHandler){ + dojo.disconnect(this._moveUpHandler); + this._moveUpHandler = null; + } + // redisplay dropIndicator + if(this._dojoxManager._dropIndicator.node.style.display == "none"){ + this._dojoxManager._dropIndicator.node.style.display = ""; + } + // reconnect the areaManager. + this._dojoxManager._dragItem.handlers.push(dojo.connect(this._dojoxManager._dragItem.item, "onDrag", this._dojoxManager, "onDrag")); + this._dojoxManager._dragItem.handlers.push(dojo.connect(this._dojoxManager._dragItem.item, "onDragEnd", this._dojoxManager, "onDrop")); + this._dojoxManager._dragItem.item.onMove(e); + } + } + // publish a topic + dojo.publish("/dojox/mdnd/adapter/dndToDojo/out",[this._oldDojoArea.node, this._oldDojoArea.type, this._draggedNode, this.accept]); + }, + + onDrop: function(/*DOMEvent*/e){ + // summary: + // Called when an onmouseup event is loaded on a registered target dojo. + // e: + // Event object. + + // console.log("dojox.mdnd.adapter.DndToDojo ::: onDrop", this._currentDojoArea); + if(this._currentDojoArea.dojo){ + // reconnect the dojoDndAdapter + if(dojox.mdnd.adapter._dndFromDojo){ + dojox.mdnd.adapter._dndFromDojo.subscribeDnd(); + } + } + if(this._dojoxManager._dropIndicator.node.style.display == "none"){ + this._dojoxManager._dropIndicator.node.style.display = ""; + } + // remove the cover + if(this._dojoxManager._cover.parentNode && this._dojoxManager._cover.parentNode.nodeType == 1){ + dojo.body().removeChild(this._dojoxManager._cover); + dojo.body().removeChild(this._dojoxManager._cover2); + } + // remove draggedNode of target : + if(this._draggedNode.parentNode == this._dojoxManager._cover){ + this._dojoxManager._cover.removeChild(this._draggedNode); + } + dojo.disconnect(this._moveHandler); + dojo.disconnect(this._moveUpHandler); + this._moveHandler = this._moveUpHandler = null; + dojo.publish("/dojox/mdnd/adapter/dndToDojo/drop", [this._draggedNode, this._currentDojoArea.node, this._currentDojoArea.type]); + dojo.removeClass(this._draggedNode, "dragNode"); + var style = this._draggedNode.style; + style.position = "relative"; + style.left = "0"; + style.top = "0"; + style.width = "auto"; + dojo.forEach(this._dojoxManager._dragItem.handlers, dojo.disconnect); + this._dojoxManager._deleteMoveableItem(this._dojoxManager._dragItem); + this._draggedNode = null; + this._currentDojoArea = null; + // reset of area manager. + this._dojoxManager._resetAfterDrop(); + } + }); + + dojox.mdnd.adapter._dndToDojo = null; + dojox.mdnd.adapter.dndToDojo = function(){ + // summary: + // returns the current areaManager, creates one if it is not created yet + if(!dojox.mdnd.adapter._dndToDojo){ + dojox.mdnd.adapter._dndToDojo = new dojox.mdnd.adapter.DndToDojo(); + } + return dojox.mdnd.adapter._dndToDojo; // Object + }; + return dtd; +});
\ No newline at end of file diff --git a/js/dojo/dojox/mdnd/dropMode/DefaultDropMode.js b/js/dojo/dojox/mdnd/dropMode/DefaultDropMode.js new file mode 100644 index 0000000..05d08db --- /dev/null +++ b/js/dojo/dojox/mdnd/dropMode/DefaultDropMode.js @@ -0,0 +1,338 @@ +//>>built +define("dojox/mdnd/dropMode/DefaultDropMode", [ + "dojo/_base/kernel", + "dojo/_base/declare", + "dojo/_base/array", + "dojo/_base/html", + "dojox/mdnd/AreaManager" +],function(dojo){ + var ddm = dojo.declare("dojox.mdnd.dropMode.DefaultDropMode", null, { + // summary: + // Enabled a type of calcul for Dnd. + // Default class to find the nearest target. + + // _oldXPoint: Integer + // used to save a X position + _oldXPoint: null, + + // _oldYPoint: Integer + // used to save a Y position + _oldYPoint: null, + + // _oldBehaviour: String + // see <getDragPoint> + _oldBehaviour: "up", + + addArea: function(/*Array*/areas, /*Object*/object){ + // summary: + // Add a DnD Area into an array sorting by the x position. + // areas: + // array of areas + // object: + // data type of a DndArea + // returns: + // a sorted area + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: addArea"); + var length = areas.length; + var position = dojo.position(object.node, true); + object.coords = {'x':position.x, 'y':position.y}; + if (length == 0) { + areas.push(object); + }else{ + var x = object.coords.x; + for (var i = 0; i < length; i++) { + if (x < areas[i].coords.x) { + for (var j = length-1; j >= i; j--) + areas[j + 1] = areas[j]; + areas[i] = object; + break; + } + } + if (i == length) + areas.push(object); + } + return areas; // Array + }, + + updateAreas: function(/*Array*/areaList){ + // summary: + // Refresh intervals between areas to determinate the nearest area to drop an item. + // Algorithm : + // the marker should be the vertical line passing by the + // central point between two contiguous areas. + // Note: + // If the page has only one targetArea, it's not necessary to calculate coords. + // areaList: + // array of areas + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: initAreas"); + var length = areaList.length; + if (length > 1){ + var currentRight, nextLeft; + for (var i = 0; i < length; i++) { + var area = areaList[i]; + var nextArea; + area.coords.x1 = -1; + area.coords.x2 = -1; + if (i == 0) { + nextArea = areaList[i+1]; + this._updateArea(area); + this._updateArea(nextArea); + currentRight = area.coords.x + area.node.offsetWidth; + nextLeft = nextArea.coords.x; + area.coords.x2 = currentRight + (nextLeft-currentRight)/2; + } + else if (i == length-1) { + area.coords.x1 = areaList[i-1].coords.x2; + }else{ + nextArea = areaList[i+1]; + this._updateArea(nextArea); + currentRight = area.coords.x + area.node.offsetWidth; + nextLeft = nextArea.coords.x; + area.coords.x1 = areaList[i-1].coords.x2; + area.coords.x2 = currentRight + (nextLeft-currentRight)/2; + } + } + } + }, + + _updateArea : function(/*Object*/area){ + // summary: + // update the DnD area object (i.e. update coordinates of its DOM node) + // area: + // the DnD area + // tags: + // protected + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: _updateArea"); + var position = dojo.position(area.node, true); + area.coords.x = position.x; + area.coords.y = position.y; + }, + + initItems: function(/*Object*/area){ + // summary: + // initialize the horizontal line in order to determinate the drop zone. + // area: + // the DnD area + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: initItems"); + dojo.forEach(area.items, function(obj){ + //get the vertical middle of the item + var node = obj.item.node; + var position = dojo.position(node, true); + var y = position.y + position.h/2; + obj.y = y; + }); + area.initItems = true; + }, + + refreshItems: function(/*Object*/area, /*Integer*/indexItem, /*Object*/size, /*Boolean*/added){ + // summary: + // take into account the drop indicator DOM element in order to compute horizontal lines + // area: + // a DnD area object + // indexItem: + // index of a draggable item + // size: + // dropIndicator size + // added: + // boolean to know if a dropIndicator has been added or deleted + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: refreshItems"); + if (indexItem == -1) { + return; + }else if(area && size && size.h){ + var height = size.h; + if (area.margin){ + height += area.margin.t; + } + var length = area.items.length; + for (var i=indexItem; i<length; i++){ + var item = area.items[i]; + if (added) { + item.y += height; + }else{ + item.y -= height; + } + } + } + }, + + getDragPoint: function(/*Object*/coords, /*Object*/size, /*Object*/mousePosition){ + // summary: + // return coordinates of the draggable item + // description: + // return for: + // - X point : the middle + // - Y point : search if the user goes up or goes down with his mouse. + // - Up : top of the draggable item + // - Down : bottom of the draggable item + // coords: + // an object encapsulating X and Y position + // size: + // an object encapsulating width and height values + // mousePosition: + // coordinates of mouse + // returns: + // an object of coordinates + // example : {'x':10,'y':10} + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: getDragPoint"); + var y = coords.y; + if (this._oldYPoint){ + if (y > this._oldYPoint) { + this._oldBehaviour = "down"; + y += size.h; + } + else + if (y <= this._oldYPoint) { + this._oldBehaviour = "up"; + } + } + this._oldYPoint = y; + return { + 'x': coords.x + (size.w / 2), + 'y': y + }; // Object + }, + + getTargetArea: function(/*Array*/areaList, /*Object*/ coords, /*integer*/currentIndexArea ){ + // summary: + // get the nearest DnD area. + // Coordinates are basically provided by the <getDragPoint> method. + // areaList: + // a list of DnD areas objects + // coords: + // coordinates [x,y] of the dragItem + // currentIndexArea: + // an index representing the active DnD area + // returns: + // the index of the DnD area + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: getTargetArea"); + var index = 0; + var x = coords.x; + var end = areaList.length; + if (end > 1) { + var start = 0, direction = "right", compute = false; + if (currentIndexArea == -1 || arguments.length<3) { + // first time : Need to search the nearest area in all areas. + compute = true; + } + else { + // check if it's always the same area + if (this._checkInterval(areaList, currentIndexArea, x)){ + index = currentIndexArea; + }else{ + if (this._oldXPoint < x){ + start = currentIndexArea + 1; + }else{ + start = currentIndexArea - 1; + end = 0; + direction = "left"; + } + compute = true; + } + } + if (compute) { + if (direction === "right") { + for (var i = start; i < end; i++) { + if (this._checkInterval(areaList, i, x)) { + index = i; + break; + } + } + }else{ + for (var i = start; i >= end; i--) { + if (this._checkInterval(areaList, i, x)) { + index = i; + break; + } + } + } + } + } + this._oldXPoint = x; + return index; // Integer + }, + + _checkInterval: function(/*Array*/areaList, /*Integer*/index, /*Coord*/x){ + // summary: + // check if the dragNode is in the interval. + // The x coordinate is basically provided by the <getDragPoint> method. + // areaList: + // a list of DnD areas objects + // index: + // index of a DnD area (to get the interval) + // x: + // coordinate x, of the dragNode + // returns: + // true if the dragNode is in intervall + // tags: + // protected + + var coords = areaList[index].coords; + if (coords.x1 == -1) { + if (x <= coords.x2) { + return true; + } + } + else + if (coords.x2 == -1) { + if (x > coords.x1) { + return true; + } + } + else { + if (coords.x1 < x && x <= coords.x2) { + return true; + } + } + return false; // Boolean + }, + + getDropIndex: function(/*Object*/ targetArea, /*Object*/ coords){ + // summary: + // Return the index where the drop has to be placed. + // targetArea: + // a DnD area object + // coords: + // coordinates [x,y] of the draggable item + // returns: + // a number + // or -1 if the area has no children or the drop index represents the last position in to the area + + //console.log("dojox.mdnd.dropMode.DefaultDropMode ::: getDropIndex"); + var length = targetArea.items.length; + var coordinates = targetArea.coords; + var y = coords.y; + if (length > 0) { + // course all children in the target area. + for (var i = 0; i < length; i++) { + // compare y value with y value of children + if (y < targetArea.items[i].y) { + return i; // Integer + } + else { + if (i == length-1) { + return -1; + } + } + } + } + return -1; + }, + + destroy: function(){ + // can be overwritten. + } + }); + + //------------ + //Singleton + //------------ + dojox.mdnd.areaManager()._dropMode = new dojox.mdnd.dropMode.DefaultDropMode(); + return ddm; +}); diff --git a/js/dojo/dojox/mdnd/dropMode/OverDropMode.js b/js/dojo/dojox/mdnd/dropMode/OverDropMode.js new file mode 100644 index 0000000..36d13d7 --- /dev/null +++ b/js/dojo/dojox/mdnd/dropMode/OverDropMode.js @@ -0,0 +1,307 @@ +//>>built +define("dojox/mdnd/dropMode/OverDropMode", ["dojo/_base/kernel","dojo/_base/declare","dojo/_base/connect","dojo/_base/html", + "dojo/_base/array","dojox/mdnd/AreaManager"],function(dojo){ + var odm = dojo.declare( + "dojox.mdnd.dropMode.OverDropMode", + null, + { + // summary: + // Default class to find the nearest target only if the mouse is over an area. + + // _oldXPoint: Integer + // used to save a X position + _oldXPoint: null, + + // _oldYPoint: Integer + // used to save a Y position + _oldYPoint: null, + + // _oldBehaviour: Integer + // see getDragpoint() + _oldBehaviour: "up", + + constructor: function(){ + //console.log("dojox.mdnd.dropMode.OverDropMode ::: constructor"); + this._dragHandler = [ + dojo.connect(dojox.mdnd.areaManager(), "onDragEnter", function(coords, size){ + var m = dojox.mdnd.areaManager(); + if(m._oldIndexArea == -1){ + m._oldIndexArea = m._lastValidIndexArea; + } + }) + ]; + + }, + + addArea: function(/*Array*/areas, /*Object*/object){ + // summary: + // Add a D&D Area into an array sorting by the x position. + // areas: + // array of areas + // object: + // data type of a DndArea + // returns: + // a sorted area + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: addArea"); + var length = areas.length, + position = dojo.position(object.node, true); + object.coords = {'x':position.x, 'y':position.y}; + if(length == 0){ + areas.push(object); + } + else{ + var x = object.coords.x; + for(var i = 0; i < length; i++){ + if(x < areas[i].coords.x){ + for(var j = length-1; j >= i; j--) + areas[j + 1] = areas[j]; + areas[i] = object; + break; + } + } + if(i == length){ + areas.push(object); + } + } + return areas; // Array + }, + + updateAreas: function(/*Array*/areaList){ + // summary: + // refresh areas position and size to determinate the nearest area to drop an item + // description: + // the area position (and size) is equal to the postion of the domNode associated. + // areaList: + // array of areas + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: updateAreas"); + var length = areaList.length; + for(var i = 0; i < length; i++){ + this._updateArea(areaList[i]); + } + }, + + _updateArea : function(/*Object*/area){ + // summary: + // update the D&D area object (i.e. update coordinates of its DOM node) + // area: + // the D&D area. + // tags: + // protected + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: addArea"); + var position = dojo.position(area.node, true); + area.coords.x = position.x; + area.coords.x2 = position.x + position.w; + area.coords.y = position.y; + }, + + initItems: function(/*Object*/area){ + // summary: + // initialize the horizontal line in order to determinate the drop zone. + // area: + // the D&D area. + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: initItems"); + dojo.forEach(area.items, function(obj){ + //get the vertical middle of the item + var node = obj.item.node; + var position = dojo.position(node, true); + var y = position.y + position.h/2; + obj.y = y; + }); + area.initItems = true; + }, + + refreshItems: function(/*Object*/area, /*Integer*/indexItem, /*Object*/size, /*Boolean*/added){ + // summary: + // take into account the drop indicator DOM element in order to compute horizontal lines + // area: + // a D&D area object + // indexItem: + // index of a draggable item + // size: + // dropIndicator size + // added: + // boolean to know if a dropIndicator has been added or deleted + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: refreshItems", area, indexItem, size, added); + if(indexItem == -1){ + return; + } + else if(area && size && size.h){ + var height = size.h; + if(area.margin){ + height += area.margin.t; + } + var length = area.items.length; + for(var i = indexItem; i < length; i++){ + var item = area.items[i]; + if(added){ + item.y += height; + } + else{ + item.y -= height; + } + } + } + }, + + getDragPoint: function(/*Object*/coords, /*Object*/size, /*Object*/mousePosition){ + // summary: + // return coordinates of the draggable item. + // - For X point : the x position of mouse + // - For Y point : the y position of mouse + // returns: + // an object of coordinates + // examples:{'x':10,'y':10} + // coords: + // an object encapsulating X and Y position + // size: + // an object encapsulating width and height values + // mousePosition: + // coordinates of mouse + + //console.log("dojox.mdnd.OverDropMode ::: getDragPoint"); + return { // Object + 'x': mousePosition.x, + 'y': mousePosition.y + } + }, + + + getTargetArea: function(/*Array*/areaList, /*Object*/ coords, /*integer*/currentIndexArea ){ + // summary: + // get the nearest D&D area. + // areaList: + // a list of D&D areas objects + // coords: + // coordinates [x,y] of the dragItem (see getDragPoint()) + // currentIndexArea: + // an index representing the active D&D area + //returns: + // the index of the D&D area + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: getTargetArea"); + var index = 0; + var x = coords.x; + var y = coords.y; + var end = areaList.length; + var start = 0, direction = "right", compute = false; + if(currentIndexArea == -1 || arguments.length < 3){ + // first time : Need to search the nearest area in all areas. + compute = true; + } + else{ + // check if it's always the same area + if(this._checkInterval(areaList, currentIndexArea, x, y)){ + index = currentIndexArea; + } + else{ + if(this._oldXPoint < x){ + start = currentIndexArea + 1; + } + else{ + start = currentIndexArea - 1; + end = 0; + direction = "left"; + } + compute = true; + } + } + if(compute){ + if(direction === "right"){ + for(var i = start; i < end; i++){ + if(this._checkInterval(areaList, i, x, y)){ + index = i; + break; + } + } + if(i == end){ + index = -1; + } + } + else{ + for(var i = start; i >= end; i--){ + if(this._checkInterval(areaList, i, x, y)){ + index = i; + break; + } + } + if(i == end-1){ + index = -1; + } + } + } + this._oldXPoint = x; + return index; // Integer + }, + + _checkInterval: function(/*Array*/areaList, /*Integer*/index, /*Coord*/x, /*Coord*/y){ + // summary: + // check if the dragNode is in the interval. + // returns: + // true if the dragNode is in intervall + // areaList: + // a list of D&D areas objects + // index: + // index of a D&D area (to get the interval) + // x: + // coordinate x, of the dragNode (see getDragPoint()) + // tags: + // protected + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: _checkInterval"); + var area = areaList[index]; + var node = area.node; + var coords = area.coords; + var startX = coords.x; + var endX = coords.x2; + var startY = coords.y; + var endY = startY + node.offsetHeight; + if(startX <= x && x <= endX && startY <= y && y <= endY){ + return true; + } + return false; // Boolean + }, + + getDropIndex: function(/*Object*/ targetArea, /*Object*/ coords){ + // summary: + // Return the index where the drop has to be placed. + // targetArea: + // a D&D area object. + // coords: + // coordinates [x,y] of the draggable item. + // returns: + // a number or -1 if the area has no children or the drop index represents the last position in to the area + + //console.log("dojox.mdnd.dropMode.OverDropMode ::: getDropIndex"); + var length = targetArea.items.length; + var coordinates = targetArea.coords; + var y = coords.y; + if(length > 0){ + // course all children in the target area. + for(var i = 0; i < length; i++){ + // compare y value with y value of children + if(y < targetArea.items[i].y){ + return i; // integer + } + else{ + if(i == length-1){ + return -1; // integer + } + } + } + } + return -1; //integer + }, + + destroy: function(){ + dojo.forEach(this._dragHandler, dojo.disconnect); + } + }); + + dojox.mdnd.areaManager()._dropMode = new dojox.mdnd.dropMode.OverDropMode(); + return odm; +});
\ No newline at end of file diff --git a/js/dojo/dojox/mdnd/dropMode/VerticalDropMode.js b/js/dojo/dojox/mdnd/dropMode/VerticalDropMode.js new file mode 100644 index 0000000..c968dae --- /dev/null +++ b/js/dojo/dojox/mdnd/dropMode/VerticalDropMode.js @@ -0,0 +1,348 @@ +//>>built +define("dojox/mdnd/dropMode/VerticalDropMode", [ + "dojo/_base/kernel", + "dojo/_base/declare", + "dojo/_base/html", + "dojo/_base/array", + "dojox/mdnd/AreaManager" +],function(dojo){ + var vdm = dojo.declare( + "dojox.mdnd.dropMode.VerticalDropMode", + null, + { + // summary: + // Enabled a type of calcul for Dnd. + // Default class to find the nearest target. + + // _oldXPoint: Integer + // used to save a X position + _oldXPoint: null, + + // _oldYPoint: Integer + // used to save a Y position + _oldYPoint: null, + + // _oldBehaviour: String + // see <getDragPoint> + _oldBehaviour: "up", + + addArea: function(/*Array*/areas, /*Object*/object){ + // summary: + // Add a DnD Area into an array sorting by the x position. + // areas: + // array of areas + // object: + // data type of a DndArea + // returns: + // a sorted area + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: addArea"); + var length = areas.length; + var position = dojo.position(object.node, true); + object.coords = {'x':position.x, 'y':position.y}; + if(length == 0){ + areas.push(object); + } + else{ + var x = object.coords.x; + for(var i = 0; i < length; i++){ + if(x < areas[i].coords.x){ + for(var j = length-1; j >= i; j--) + areas[j + 1] = areas[j]; + areas[i] = object; + break; + } + } + if(i == length){ + areas.push(object); + } + } + return areas; // Array + }, + + updateAreas: function(/*Array*/areaList){ + // summary: + // Refresh intervals between areas to determinate the nearest area to drop an item. + // Algorithm : + // the marker should be the vertical line passing by the + // central point between two contiguous areas. + // Note: + // If the page has only one targetArea, it's not necessary to calculate coords. + // areaList: + // array of areas + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: initAreas"); + var length = areaList.length; + if(length > 1){ + var currentRight, nextLeft; + for(var i = 0; i < length; i++){ + var area = areaList[i]; + var nextArea; + area.coords.x1 = -1; + area.coords.x2 = -1; + if(i == 0){ + nextArea = areaList[i+1]; + this._updateArea(area); + this._updateArea(nextArea); + currentRight = area.coords.x + area.node.offsetWidth; + nextLeft = nextArea.coords.x; + area.coords.x2 = currentRight + (nextLeft-currentRight)/2; + } + else if(i == length-1){ + area.coords.x1 = areaList[i-1].coords.x2; + } + else{ + nextArea = areaList[i+1]; + this._updateArea(nextArea); + currentRight = area.coords.x + area.node.offsetWidth; + nextLeft = nextArea.coords.x; + area.coords.x1 = areaList[i-1].coords.x2; + area.coords.x2 = currentRight + (nextLeft-currentRight)/2; + } + } + } + }, + + _updateArea : function(/*Object*/area){ + // summary: + // update the DnD area object (i.e. update coordinates of its DOM node) + // area: + // the DnD area + // tags: + // protected + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: _updateArea"); + var position = dojo.position(area.node, true); + area.coords.x = position.x; + area.coords.y = position.y; + }, + + initItems: function(/*Object*/area){ + // summary: + // initialize the horizontal line in order to determinate the drop zone. + // area: + // the DnD area + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: initItems"); + dojo.forEach(area.items, function(obj){ + //get the vertical middle of the item + var node = obj.item.node; + var position = dojo.position(node, true); + var y = position.y + position.h/2; + obj.y = y; + }); + area.initItems = true; + }, + + refreshItems: function(/*Object*/area, /*Integer*/indexItem, /*Object*/size, /*Boolean*/added){ + // summary: + // take into account the drop indicator DOM element in order to compute horizontal lines + // area: + // a DnD area object + // indexItem: + // index of a draggable item + // size: + // dropIndicator size + // added: + // boolean to know if a dropIndicator has been added or deleted + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: refreshItems"); + if(indexItem == -1){ + return; + } + else if(area && size && size.h){ + var height = size.h; + if(area.margin){ + height += area.margin.t; + } + var length = area.items.length; + for(var i = indexItem; i < length; i++){ + var item = area.items[i]; + if(added){ + item.y += height; + } + else{ + item.y -= height; + } + } + } + }, + + getDragPoint: function(/*Object*/coords, /*Object*/size, /*Object*/mousePosition){ + // summary: + // return coordinates of the draggable item + // description: + // return for: + // - X point : the middle + // - Y point : search if the user goes up or goes down with his mouse. + // - Up : top of the draggable item + // - Down : bottom of the draggable item + // coords: + // an object encapsulating X and Y position + // size: + // an object encapsulating width and height values + // mousePosition: + // coordinates of mouse + // returns: + // an object of coordinates + // example : {'x':10,'y':10} + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: getDragPoint"); + var y = coords.y; + if(this._oldYPoint){ + if(y > this._oldYPoint){ + this._oldBehaviour = "down"; + y += size.h; + } + else + if(y <= this._oldYPoint){ + this._oldBehaviour = "up"; + } + } + this._oldYPoint = y; + return { + 'x': coords.x + (size.w / 2), + 'y': y + }; // Object + }, + + getTargetArea: function(/*Array*/areaList, /*Object*/ coords, /*integer*/currentIndexArea ){ + // summary: + // get the nearest DnD area. + // Coordinates are basically provided by the <getDragPoint> method. + // areaList: + // a list of DnD areas objects + // coords: + // coordinates [x,y] of the dragItem + // currentIndexArea: + // an index representing the active DnD area + // returns: + // the index of the DnD area + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: getTargetArea"); + var index = 0; + var x = coords.x; + var end = areaList.length; + if(end > 1){ + var start = 0, direction = "right", compute = false; + if(currentIndexArea == -1 || arguments.length < 3){ + // first time : Need to search the nearest area in all areas. + compute = true; + } + else{ + // check if it's always the same area + if(this._checkInterval(areaList, currentIndexArea, x)){ + index = currentIndexArea; + } + else{ + if(this._oldXPoint < x){ + start = currentIndexArea + 1; + } + else{ + start = currentIndexArea - 1; + end = 0; + direction = "left"; + } + compute = true; + } + } + if(compute){ + if(direction === "right"){ + for(var i = start; i < end; i++){ + if(this._checkInterval(areaList, i, x)){ + index = i; + break; + } + } + } + else{ + for(var i = start; i >= end; i--){ + if(this._checkInterval(areaList, i, x)){ + index = i; + break; + } + } + } + } + } + this._oldXPoint = x; + return index; // Integer + }, + + _checkInterval: function(/*Array*/areaList, /*Integer*/index, /*Coord*/x){ + // summary: + // check if the dragNode is in the interval. + // The x coordinate is basically provided by the <getDragPoint> method. + // areaList: + // a list of DnD areas objects + // index: + // index of a DnD area (to get the interval) + // x: + // coordinate x, of the dragNode + // returns: + // true if the dragNode is in intervall + // tags: + // protected + var coords = areaList[index].coords; + if(coords.x1 == -1){ + if(x <= coords.x2){ + return true; + } + } + else + if(coords.x2 == -1){ + if(x > coords.x1){ + return true; + } + } + else{ + if(coords.x1 < x && x <= coords.x2){ + return true; + } + } + return false; // Boolean + }, + + getDropIndex: function(/*Object*/ targetArea, /*Object*/ coords){ + // summary: + // Return the index where the drop has to be placed. + // targetArea: + // a DnD area object + // coords: + // coordinates [x,y] of the draggable item + // returns: + // a number + // or -1 if the area has no children or the drop index represents the last position in to the area + + //console.log("dojox.mdnd.dropMode.VerticalDropMode ::: getDropIndex"); + var length = targetArea.items.length; + var coordinates = targetArea.coords; + var y = coords.y; + if(length > 0){ + // course all children in the target area. + for(var i = 0; i < length; i++){ + // compare y value with y value of children + if(y < targetArea.items[i].y){ + return i; // Integer + } + else{ + if(i == length-1){ + return -1; + } + } + } + } + return -1; + }, + + destroy: function(){ + // can be overwritten. + } + }); + + //------------ + //Singleton + //------------ + dojox.mdnd.areaManager()._dropMode = new dojox.mdnd.dropMode.VerticalDropMode(); + return vdm; +}); diff --git a/js/dojo/dojox/mdnd/resources/dnd.css b/js/dojo/dojox/mdnd/resources/dnd.css new file mode 100644 index 0000000..f7f0469 --- /dev/null +++ b/js/dojo/dojox/mdnd/resources/dnd.css @@ -0,0 +1,93 @@ +/**********************************oaf.base.dnd************************************/ +.dragNode{ + z-index:10000; + cursor:move; +} +.dragHandle{ + cursor:move; +} +.dropIndicator{ + position:relative; + height:50px; + border:1px dashed #FFF; +} +.dropIndicator > div{ + position:absolute; + left:0;top:0;right:0;bottom:0; + background-color:#000; + opacity:0.17; + filter:alpha(opacity=17); + -khtml-opacity:0.17; + -moz-opacity:0.17; +} +.dj_ie6 .dropIndicator div{ + position:relative; + height:100%; + background-color:#000; + filter:alpha(opacity=17); +} +.dj_ie6 .dropIndicator{ + _margin:10px; +} +.dndCover{ + background-image:url(../../layout/resources/icons/pixel.gif); + position:absolute; + left:0; + top:0; + width:100%; + height:1000px; + z-index:9999; + cursor:move; +} + +.dndCover2{ + z-index: 10001; +} +.dragNode{ + z-index:10000; + cursor:move; +} +.dragHandle{ + cursor:move; +} +.dropIndicator{ + position:relative; + height:50px; + border:1px dashed #FFF; +} +.dropIndicator > div{ + position:absolute; + left:0;top:0;right:0;bottom:0; + background-color:#000; + opacity:0.17; + filter:alpha(opacity=17); + -khtml-opacity:0.17; + -moz-opacity:0.17; +} +.dj_ie6 .dropIndicator div{ + position:relative; + height:100%; + background-color:#000; + filter:alpha(opacity=17); +} +.dj_ie6 .dropIndicator{ + _margin:10px; +} +.dndCover{ + background-image:url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D); + position:absolute; + left:0; + top:0; + width:100%; + height:1000px; + z-index:9999; + cursor:move; +} + +.dj_ie6 .orange .dndCover, .dj_ie7 .orange .dndCover{ + background-image:url(../../images/oaf/pixel.gif); +} + +.orange .dndCover2{ + z-index: 10001; +}
\ No newline at end of file |
