- Author:
- David Nickerson <nickerso@users.sourceforge.net>
- Date:
- 2009-07-16 02:00:03+12:00
- Desc:
- the starting point for the HH tutorial example
- Permanent Source URI:
- https://models.fieldml.org/workspace/a1/rawfile/f6a8f90307388eb4b040ee3566b84d88b59247f7/dojo-presentation/js/dojo/dojox/layout/dnd/PlottedDnd.js
dojo.provide("dojox.layout.dnd.PlottedDnd");
dojo.require("dojo.dnd.Source");
dojo.require("dojo.dnd.Manager");
dojo.require("dojox.layout.dnd.Avatar");
dojo.declare("dojox.layout.dnd.PlottedDnd", [dojo.dnd.Source], {
// summary:
// dnd source handling plotted zone to show the dropping area
GC_OFFSET_X: dojo.dnd.manager().OFFSET_X,
GC_OFFSET_Y: dojo.dnd.manager().OFFSET_Y,
constructor: function(/*Node*/node, /*Object*/params){
this.childBoxes = null;
this.dropIndicator = new dojox.layout.dnd.DropIndicator("dndDropIndicator", "div");
this.withHandles = params.withHandles;
this.handleClasses = params.handleClasses;
this.opacity = params.opacity;
this.allowAutoScroll = params.allowAutoScroll;//MODIF MYS
this.dom = params.dom;
this.singular = true;
this.skipForm = true;
this._over = false;
this.defaultHandleClass = "GcDndHandle";
this.isDropped = false;
this._timer = null;
//Initialize the params to calculate offset
this.isOffset = (params.isOffset)?true:false;
this.offsetDrag = (params.offsetDrag) ? params.offsetDrag : {x:0,y:0};
this.hideSource = params.hideSource ? params.hideSource : true;
this._drop = this.dropIndicator.create();
},
_calculateCoords : function(/*Boolean*/height){
// summary: Calculate each position of children
dojo.forEach(this.node.childNodes, dojo.hitch(this, function(child){
child.coords = {
xy: dojo.coords(child, true),
w: child.offsetWidth / 2,
h: child.offsetHeight / 2
};
if(height){
child.coords.mh = dojo.marginBox(child).h;
}
}));
},
_legalMouseDown: function(/*Event*/e){
// summary: Checks if user clicked on "approved" items.
if(!this.withHandles){ return true; }
for(var node = (e.target); node && node != this.node; node = node.parentNode)
if(dojo.hasClass(node, this.defaultHandleClass))
return true;
return false; // Boolean
},
setDndItemSelectable: function(/*Node*/node, /*Boolean*/isSelectable) {
// summary: set an item as selectable
for(var _node = node; _node && node != this.node; _node = _node.parentNode) {
if (dojo.hasClass(_node,"dojoDndItem")) {
dojo.setSelectable(_node, isSelectable);
return;
}
}
},
getDraggedWidget: function(/*Node*/node) {
// summary: Return one or more widget selected during the drag.
var _node = node;
while (_node && _node.nodeName.toLowerCase()!="body" && !dojo.hasClass(_node,"dojoDndItem")) {
_node = _node.parentNode;
}
return (_node)? dijit.byNode(_node) : null;
},
isAccepted: function(/*Node*/ node) {
// summary: test if this node can be accepted
var _dndType = (node) ? node.getAttribute("dndtype") : null;
if(_dndType && _dndType in this.accept)
return true;
else
return false;
},
onDndStart:function(/*Object*/source, /*Array*/nodes, /*Object*/copy){
// summary: Called to initiate the DnD operation.
if (source == this)
this.firstIndicator = true;
else
this.firstIndicator = false;
this._calculateCoords(true);
//this.isDropped = true;
if (nodes[0].coords) {
this._drop.style.height = nodes[0].coords.mh + "px";
}else{
var m= dojo.dnd.manager();
this._drop.style.height = m.avatar.node.clientHeight+"px";
}
this.dndNodes = nodes;
dojox.layout.dnd.PlottedDnd.superclass.onDndStart.call(this,source, nodes, copy);
if(source==this)
if(this.hideSource)
for(var i=0; i<nodes.length; i++)
dojo.style(nodes[i], "display", "none");
},
onDndCancel:function(){
// summary: Called to cancel the DnD operation.
var m = dojo.dnd.manager();
if(m.source == this && this.hideSource){
var nodes = this.getSelectedNodes();
for(var i=0; i<nodes.length; i++)
if(nodes[i])
dojo.style(nodes[i], "display", "");
}
dojox.layout.dnd.PlottedDnd.superclass.onDndCancel.call(this);
this.deleteDashedZone();
},
onDndDrop: function(source,nodes,copy,target) {
// summary: Called to finish the DnD operation
try {
if (!this.isAccepted(nodes[0]))
this.onDndCancel();
else {
if (source == this && this._over && this.dropObject)
this.current = this.dropObject.c;
dojox.layout.dnd.PlottedDnd.superclass.onDndDrop.call(this, source, nodes, copy, target);
this._calculateCoords(true);
}
}
catch (error) {
console.info(error);
}
},
onMouseDown: function(/*Event*/e) {
// summary: Event processor for onmousedown.
if (this.current == null)
this.selection = {};
else{
if (this.current == this.anchor)
this.anchor = null;
}
if (this.current !== null) {
this.current.coords = {
xy: dojo.coords(this.current, true),
w: this.current.offsetWidth / 2,
h: this.current.offsetHeight / 2,
mh: dojo.marginBox(this.current).h
};
this._drop.style.height = this.current.coords.mh + "px";
if (this.isOffset) {
if (this.offsetDrag.x == 0 && this.offsetDrag.y == 0) {
var NoOffsetDrag = true;
var coords = dojo.coords(this._getChildByEvent(e));
this.offsetDrag.x = coords.x - e.pageX;
this.offsetDrag.y = coords.y - e.clientY;
}
if (this.offsetDrag.y < 16 && this.current != null)
this.offsetDrag.y = this.GC_OFFSET_Y;
var m = dojo.dnd.manager();
m.OFFSET_X = this.offsetDrag.x;
m.OFFSET_Y = this.offsetDrag.y;
if (NoOffsetDrag) {
this.offsetDrag.x = 0;
this.offsetDrag.y = 0;
}
}
}
if (dojo.dnd.isFormElement(e)) {
this.setDndItemSelectable(e.target,true);
}
else {
this.containerSource = true;
var _draggedWidget = this.getDraggedWidget(e.target);
if (_draggedWidget && _draggedWidget.dragRestriction)
dragRestriction = true;
else
dojox.layout.dnd.PlottedDnd.superclass.onMouseDown.call(this,e);
}
},
onMouseUp: function(/*Event*/e) {
// summary: Event processor for onmouseup.
dojox.layout.dnd.PlottedDnd.superclass.onMouseUp.call(this,e);
this.containerSource = false;
if (!dojo.isIE && this.mouseDown)
this.setDndItemSelectable(e.target,true);
var m = dojo.dnd.manager();
m.OFFSET_X = this.GC_OFFSET_X;
m.OFFSET_Y = this.GC_OFFSET_Y;
},
onMouseMove: function(e) {
// summary: Event processor for onmousemove
var m = dojo.dnd.manager();
if (this.isDragging) {
var before = false;
if (this.current != null || (this.current == null && !this.dropObject)) {
if (this.isAccepted(m.nodes[0]) || this.containerSource)
before = this.setIndicatorPosition(e);
}
if (this.current != this.targetAnchor || before != this.before) {
this._markTargetAnchor(before);
m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
}
if (this.allowAutoScroll)
this._checkAutoScroll(e);
}
else {
if (this.mouseDown && this.isSource) {
var nodes = this.getSelectedNodes();
if (nodes.length) {
m.startDrag(this, nodes, this.copyState(dojo.dnd.getCopyKeyState(e)));
}
}
if (this.allowAutoScroll)
this._stopAutoScroll();
}
},
_markTargetAnchor: function(/*Boolean*/before){
// summary: Assigns a class to the current target anchor based on "before" status
if(this.current == this.targetAnchor && this.before == before){ return; }
this.targetAnchor = this.current;
this.targetBox = null;
this.before = before;
},
_unmarkTargetAnchor: function(){
// summary: Removes a class of the current target anchor based on "before" status.
if(!this.targetAnchor){ return; }
this.targetAnchor = null;
this.targetBox = null;
this.before = true;
},
setIndicatorPosition: function(/*Event*/e) {
// summary: set the position of the drop indicator
var before = false;
if(this.current){
if (!this.current.coords || this.allowAutoScroll) {
this.current.coords = {
xy: dojo.coords(this.current, true),
w: this.current.offsetWidth / 2,
h: this.current.offsetHeight / 2
};
}
if (this.horizontal) {
before = (e.pageX - this.current.coords.xy.x) < this.current.coords.w;
}
else {
before = (e.pageY - this.current.coords.xy.y) < this.current.coords.h;
}
this.insertDashedZone(before);
}
else {
if (!this.dropObject /*|| dojo.isIE*/) this.insertDashedZone(false);
}
return before;
},
onOverEvent:function(){
this._over = true;
dojox.layout.dnd.PlottedDnd.superclass.onOverEvent.call(this);
if (this.isDragging) {
var m = dojo.dnd.manager();
if (!this.current && !this.dropObject && this.getSelectedNodes()[0] && this.isAccepted(m.nodes[0]))
this.insertDashedZone(false);
}
},
onOutEvent: function() {
this._over = false;
this.containerSource = false;
dojox.layout.dnd.PlottedDnd.superclass.onOutEvent.call(this);
if (this.dropObject) this.deleteDashedZone();
},
deleteDashedZone: function() {
// summary: hide the dashed zone
this._drop.style.display = "none";
var next = this._drop.nextSibling;
while (next != null) {
next.coords.xy.y -= parseInt(this._drop.style.height);
next = next.nextSibling;
}
delete this.dropObject;
},
insertDashedZone: function(/*Boolean*/before) {
// summary: Insert the dashed zone at the right place
if (this.dropObject) {
if (before == this.dropObject.b && ((this.current && this.dropObject.c == this.current.id) || (!this.current && !this.dropObject.c)))
return;
else
this.deleteDashedZone();
}
this.dropObject = {n: this._drop, c: (this.current)? this.current.id : null, b: before};
if (this.current) {
dojo.place(this._drop, this.current, (before) ? "before" : "after");
if (!this.firstIndicator) {
var next = this._drop.nextSibling;
while (next != null) {
next.coords.xy.y += parseInt(this._drop.style.height);
next = next.nextSibling;
}
}else{
this.firstIndicator = false;
}
}
else
this.node.appendChild(this._drop);
this._drop.style.display = "";
},
insertNodes: function(/*Boolean*/addSelected, /*Array*/data, /*Boolean*/before, /*Node*/anchor){
// summary: Inserts new data items (see Dojo Container's insertNodes method for details).
if (this.dropObject){
dojo.style(this.dropObject.n,"display","none");
dojox.layout.dnd.PlottedDnd.superclass.insertNodes.call(this,true,data,true,this.dropObject.n);
this.deleteDashedZone();
}
else {
return dojox.layout.dnd.PlottedDnd.superclass.insertNodes.call(this,addSelected,data,before,anchor);
}
var _widget = dijit.byId(data[0].getAttribute("widgetId"));
if (_widget) {
dojox.layout.dnd._setGcDndHandle(_widget, this.withHandles, this.handleClasses);
if(this.hideSource)
dojo.style(_widget.domNode, "display", "");
}
},
_checkAutoScroll: function(e){
if (this._timer)
clearTimeout(this._timer);
this._stopAutoScroll();
var node = this.dom;
var y = this._sumAncestorProperties(node,"offsetTop");
//Down
if( (e.pageY - node.offsetTop +30 ) > node.clientHeight ){
autoScrollActive = true;
this._autoScrollDown(node);
} else if ( (node.scrollTop > 0) && (e.pageY - y) < 30){
//Up
autoScrollActive = true;
this._autoScrollUp(node);
}
},
_autoScrollUp: function(node){
if( autoScrollActive && node.scrollTop > 0) {
node.scrollTop -= 30;
this._timer = setTimeout(dojo.hitch(this, function(){this._autoScrollUp(node);}),"100");
}
},
_autoScrollDown: function(node){
if( autoScrollActive && (node.scrollTop < (node.scrollHeight-node.clientHeight))){
node.scrollTop += 30;
this._timer = setTimeout(dojo.hitch(this, function(){this._autoScrollDown(node);}),"100");
}
},
_stopAutoScroll: function(){
this.autoScrollActive = false;
},
_sumAncestorProperties: function(node, prop){
// summary
// Returns the sum of the passed property on all ancestors of node.
node = dojo.byId(node);
if(!node){ return 0; }
var retVal = 0;
while(node){
var val = node[prop];
if(val){
retVal += val - 0;
if(node==dojo.body()){ break; }// opera and khtml #body & #html has the same values, we only need one value
}
node = node.parentNode;
}
return retVal; // integer
}
});
dojox.layout.dnd._setGcDndHandle = function(service,withHandles,handleClasses, first) {
if(!first){
dojo.query(".GcDndHandle", service.domNode).removeClass("GcDndHandle");
}
if(!withHandles){
dojo.addClass(service.domNode, "GcDndHandle");
}else{
var _hasHandle = false;
for(var i = handleClasses.length - 1; i >= 0; i--){
var _node = dojo.query("." + handleClasses[i], service.domNode)[0];
if(_node){
_hasHandle = true;
if(handleClasses[i] != "GcDndHandle"){
var _gripNode = dojo.query(".GcDndHandle", service.domNode);
if(_gripNode.length == 0){
dojo.removeClass(service.domNode, "GcDndHandle");
}else{
_gripNode.removeClass("GcDndHandle");
}
dojo.addClass(_node, "GcDndHandle");
}
}
}
if(!_hasHandle){
dojo.addClass(service.domNode, "GcDndHandle");
}
}
};
dojo.declare("dojox.layout.dnd.DropIndicator", null, {
// summary: An empty widget to show at the user the drop zone of the widget.
constructor: function(/*String*/cn, /*String*/tag) {
this.tag = tag || "div";
this.style = cn || null;
},
isInserted : function(){
return (this.node.parentNode && this.node.parentNode.nodeType==1);
},
create : function(/*Node*//*nodeRef*/){
if(this.node && this.isInserted()) return this.node;
var h= "90px";
var el = document.createElement(this.tag);
if(this.style){
el.className = this.style;
el.style.height = h;
}else{
with(el.style) {
position = "relative";
border = "1px dashed #F60";
margin = "2px";
height = h;
}
}
this.node = el;
return el;
},
destroy : function(){
if(!this.node || !this.isInserted()) return;
this.node.parentNode.removeChild(this.node);
this.node = null;
}
});
dojo.extend(dojo.dnd.Manager, {
canDrop: function(flag){
var canDropFlag = this.target && flag;
if(this.canDropFlag != canDropFlag){
this.canDropFlag = canDropFlag;
if (this.avatar) this.avatar.update();
}
},
makeAvatar: function(){
//summary: Makes the avatar, it is separate to be overwritten dynamically, if needed.
if (this.source.declaredClass == "dojox.layout.dnd.PlottedDnd")
return new dojox.layout.dnd.Avatar(this,this.source.opacity);
else
return new dojo.dnd.Avatar(this);
}
});
if (dojo.isIE){
dojox.layout.dnd.handdleIE = [
dojo.subscribe("/dnd/start", null, function(){
IEonselectstart = document.body.onselectstart;
document.body.onselectstart = function (e) {return false;};
}),
dojo.subscribe("/dnd/cancel", null, function(){
document.body.onselectstart = IEonselectstart;
}),
dojo.subscribe("/dnd/drop", null, function(){
document.body.onselectstart = IEonselectstart;
})
];
dojo.addOnWindowUnload(function(){
dojo.forEach(dojox.layout.dnd.handdleIE, dojo.unsubscribe);
});
}