Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dojo.dnd.Source"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.dojo._hasResource["dojo.dnd.Source"] = true;dojo.provide("dojo.dnd.Source");dojo.require("dojo.dnd.Selector");dojo.require("dojo.dnd.Manager");/*Container property:"Horizontal"- if this is the horizontal containerSource states:"" - normal state"Moved" - this source is being moved"Copied" - this source is being copiedTarget states:"" - normal state"Disabled" - the target cannot accept an avatarTarget anchor state:"" - item is not selected"Before" - insert point is before the anchor"After" - insert point is after the anchor*/dojo.declare("dojo.dnd.Source", dojo.dnd.Selector, {// summary: a Source object, which can be used as a DnD source, or a DnD target// object attributes (for markup)isSource: true,horizontal: false,copyOnly: false,skipForm: false,withHandles: false,accept: ["text"],constructor: function(node, params){// summary: a constructor of the Source// node: Node: node or node's id to build the source on// params: Object: a dict of parameters, recognized parameters are:// isSource: Boolean: can be used as a DnD source, if true; assumed to be "true" if omitted// accept: Array: list of accepted types (text strings) for a target; assumed to be ["text"] if omitted// horizontal: Boolean: a horizontal container, if true, vertical otherwise or when omitted// copyOnly: Boolean: always copy items, if true, use a state of Ctrl key otherwise// withHandles: Boolean: allows dragging only by handles// the rest of parameters are passed to the selectorif(!params){ params = {}; }this.isSource = typeof params.isSource == "undefined" ? true : params.isSource;var type = params.accept instanceof Array ? params.accept : ["text"];this.accept = null;if(type.length){this.accept = {};for(var i = 0; i < type.length; ++i){this.accept[type[i]] = 1;}}this.horizontal = params.horizontal;this.copyOnly = params.copyOnly;this.withHandles = params.withHandles;// class-specific variablesthis.isDragging = false;this.mouseDown = false;this.targetAnchor = null;this.targetBox = null;this.before = true;// statesthis.sourceState = "";if(this.isSource){dojo.addClass(this.node, "dojoDndSource");}this.targetState = "";if(this.accept){dojo.addClass(this.node, "dojoDndTarget");}if(this.horizontal){dojo.addClass(this.node, "dojoDndHorizontal");}// set up eventsthis.topics = [dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),dojo.subscribe("/dnd/start", this, "onDndStart"),dojo.subscribe("/dnd/drop", this, "onDndDrop"),dojo.subscribe("/dnd/cancel", this, "onDndCancel")];},// methodscheckAcceptance: function(source, nodes){// summary: checks, if the target can accept nodes from this source// source: Object: the source which provides items// nodes: Array: the list of transferred itemsif(this == source){ return true; }for(var i = 0; i < nodes.length; ++i){var type = source.getItem(nodes[i].id).type;// type instanceof Arrayvar flag = false;for(var j = 0; j < type.length; ++j){if(type[j] in this.accept){flag = true;break;}}if(!flag){return false; // Boolean}}return true; // Boolean},copyState: function(keyPressed){// summary: Returns true, if we need to copy items, false to move.// It is separated to be overwritten dynamically, if needed.// keyPressed: Boolean: the "copy" was pressedreturn this.copyOnly || keyPressed; // Boolean},destroy: function(){// summary: prepares the object to be garbage-collecteddojo.dnd.Source.superclass.destroy.call(this);dojo.forEach(this.topics, dojo.unsubscribe);this.targetAnchor = null;},// markup methodsmarkupFactory: function(params, node){params._skipStartup = true;return new dojo.dnd.Source(node, params);},// mouse event processorsonMouseMove: function(e){// summary: event processor for onmousemove// e: Event: mouse eventif(this.isDragging && this.targetState == "Disabled"){ return; }dojo.dnd.Source.superclass.onMouseMove.call(this, e);var m = dojo.dnd.manager();if(this.isDragging){// calculate before/aftervar before = false;if(this.current){if(!this.targetBox || this.targetAnchor != this.current){this.targetBox = {xy: dojo.coords(this.current, true),w: this.current.offsetWidth,h: this.current.offsetHeight};}if(this.horizontal){before = (e.pageX - this.targetBox.xy.x) < (this.targetBox.w / 2);}else{before = (e.pageY - this.targetBox.xy.y) < (this.targetBox.h / 2);}}if(this.current != this.targetAnchor || before != this.before){this._markTargetAnchor(before);m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));}}else{if(this.mouseDown && this.isSource){var nodes = this.getSelectedNodes();if(nodes.length){m.startDrag(this, nodes, this.copyState(dojo.dnd.getCopyKeyState(e)));}}}},onMouseDown: function(e){// summary: event processor for onmousedown// e: Event: mouse eventif(this._legalMouseDown(e) && (!this.skipForm || !dojo.dnd.isFormElement(e))){this.mouseDown = true;this.mouseButton = e.button;dojo.dnd.Source.superclass.onMouseDown.call(this, e);}},onMouseUp: function(e){// summary: event processor for onmouseup// e: Event: mouse eventif(this.mouseDown){this.mouseDown = false;dojo.dnd.Source.superclass.onMouseUp.call(this, e);}},// topic event processorsonDndSourceOver: function(source){// summary: topic event processor for /dnd/source/over, called when detected a current source// source: Object: the source which has the mouse over itif(this != source){this.mouseDown = false;if(this.targetAnchor){this._unmarkTargetAnchor();}}else if(this.isDragging){var m = dojo.dnd.manager();m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));}},onDndStart: function(source, nodes, copy){// summary: topic event processor for /dnd/start, called to initiate the DnD operation// source: Object: the source which provides items// nodes: Array: the list of transferred items// copy: Boolean: copy items, if true, move items otherwiseif(this.isSource){this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");}var accepted = this.accept && this.checkAcceptance(source, nodes);this._changeState("Target", accepted ? "" : "Disabled");if(accepted && this == source){dojo.dnd.manager().overSource(this);}this.isDragging = true;},onDndDrop: function(source, nodes, copy){// summary: topic event processor for /dnd/drop, called to finish the DnD operation// source: Object: the source which provides items// nodes: Array: the list of transferred items// copy: Boolean: copy items, if true, move items otherwisedo{ //break boxif(this.containerState != "Over"){ break; }var oldCreator = this._normalizedCreator;if(this != source){// transferring nodes from the source to the targetif(this.creator){// use defined creatorthis._normalizedCreator = function(node, hint){return oldCreator.call(this, source.getItem(node.id).data, hint);};}else{// we have no creator defined => move/clone nodesif(copy){// clone nodesthis._normalizedCreator = function(node, hint){var t = source.getItem(node.id);var n = node.cloneNode(true);n.id = dojo.dnd.getUniqueId();return {node: n, data: t.data, type: t.type};};}else{// move nodesthis._normalizedCreator = function(node, hint){var t = source.getItem(node.id);source.delItem(node.id);return {node: node, data: t.data, type: t.type};};}}}else{// transferring nodes within the single sourceif(this.current && this.current.id in this.selection){ break; }if(this.creator){// use defined creatorif(copy){// create new copies of data itemsthis._normalizedCreator = function(node, hint){return oldCreator.call(this, source.getItem(node.id).data, hint);};}else{// move nodesif(!this.current){ break; }this._normalizedCreator = function(node, hint){var t = source.getItem(node.id);return {node: node, data: t.data, type: t.type};};}}else{// we have no creator defined => move/clone nodesif(copy){// clone nodesthis._normalizedCreator = function(node, hint){var t = source.getItem(node.id);var n = node.cloneNode(true);n.id = dojo.dnd.getUniqueId();return {node: n, data: t.data, type: t.type};};}else{// move nodesif(!this.current){ break; }this._normalizedCreator = function(node, hint){var t = source.getItem(node.id);return {node: node, data: t.data, type: t.type};};}}}this._removeSelection();if(this != source){this._removeAnchor();}if(this != source && !copy && !this.creator){source.selectNone();}this.insertNodes(true, nodes, this.before, this.current);if(this != source && !copy && this.creator){source.deleteSelectedNodes();}this._normalizedCreator = oldCreator;}while(false);this.onDndCancel();},onDndCancel: function(){// summary: topic event processor for /dnd/cancel, called to cancel the DnD operationif(this.targetAnchor){this._unmarkTargetAnchor();this.targetAnchor = null;}this.before = true;this.isDragging = false;this.mouseDown = false;delete this.mouseButton;this._changeState("Source", "");this._changeState("Target", "");},// utilitiesonOverEvent: function(){// summary: this function is called once, when mouse is over our containerdojo.dnd.Source.superclass.onOverEvent.call(this);dojo.dnd.manager().overSource(this);},onOutEvent: function(){// summary: this function is called once, when mouse is out of our containerdojo.dnd.Source.superclass.onOutEvent.call(this);dojo.dnd.manager().outSource(this);},_markTargetAnchor: function(before){// summary: assigns a class to the current target anchor based on "before" status// before: Boolean: insert before, if true, after otherwiseif(this.current == this.targetAnchor && this.before == before){ return; }if(this.targetAnchor){this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");}this.targetAnchor = this.current;this.targetBox = null;this.before = before;if(this.targetAnchor){this._addItemClass(this.targetAnchor, this.before ? "Before" : "After");}},_unmarkTargetAnchor: function(){// summary: removes a class of the current target anchor based on "before" statusif(!this.targetAnchor){ return; }this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");this.targetAnchor = null;this.targetBox = null;this.before = true;},_markDndStatus: function(copy){// summary: changes source's state based on "copy" statusthis._changeState("Source", copy ? "Copied" : "Moved");},_legalMouseDown: function(e){// summary: checks if user clicked on "approved" items// e: Event: mouse eventif(!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}});dojo.declare("dojo.dnd.Target", dojo.dnd.Source, {// summary: a Target object, which can be used as a DnD targetconstructor: function(node, params){// summary: a constructor of the Target --- see the Source constructor for detailsthis.isSource = false;dojo.removeClass(this.node, "dojoDndSource");},// markup methodsmarkupFactory: function(params, node){params._skipStartup = true;return new dojo.dnd.Target(node, params);}});}