Use document-wide Event handlers.
authorMichael M Slusarz <slusarz@curecanti.org>
Sun, 18 Jan 2009 23:41:20 +0000 (16:41 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Sun, 18 Jan 2009 23:41:20 +0000 (16:41 -0700)
DIMP now uses approx. 10 total ecent handlers as opposed to before,
where 1000's of event handlers needed to be created/deleted if a user
would scroll through a list of messages.

imp/js/dragdrop.js
imp/js/src/dragdrop.js

index eb7ee18..796b348 100644 (file)
@@ -1 +1 @@
-var DragDrop={Drags:{drags:$H(),register:function(a){if(!this.drags.size()){if(!this.div){this.div=new Element("DIV",{className:a.options.classname}).hide()}$(document.body).insert(this.div)}this.drags.set(a.element.identify(),a)},unregister:function(a){if(this.drag==a.element){this.drag.deactivate()}this.drags.unset(a.element.identify());if(!this.drags.size()&&this.div){this.div.remove()}},get_drag:function(a){return this.drags.get(Object.isElement(a)?$(a).identify():a)},activate:function(a){if(this.drag){this.deactivate()}this.drag=a;this.mousemoveE=a._mouseMove.bindAsEventListener(a);this.mouseupE=a._mouseUp.bindAsEventListener(a);document.observe("mousemove",this.mousemoveE);document.observe("mouseup",this.mouseupE)},deactivate:function(){if(this.drag){this.drag=null;document.stopObserving("mousemove",this.mousemoveE);document.stopObserving("mouseup",this.mouseupE)}}},Drops:{drops:$H(),register:function(a){this.drops.set(a.element.identify(),a)},unregister:function(a){if(this.drop==a.element){this.drop=null}this.drops.unset(a.element.identify())},get_drop:function(a){return this.drops.get(Object.isElement(a)?$(a).identify():a)}},validDrop:function(a){var b=DragDrop.Drops.drop;return(b&&a&&a!=b.element&&(!b.options.accept.size()||b.options.accept.include(a.tagName)))}},Drag=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({caption:"",classname:"drag",constraint:null,ghosting:false,scroll:null,snap:null,threshold:0,onDrag:null,onEnd:null,onStart:null},arguments[1]||{});this.mousedownE=this._mouseDown.bindAsEventListener(this);this.element.observe("mousedown",this.mousedownE);if(this.options.scroll){this.options.scroll=$(this.options.scroll)}DragDrop.Drags.register(this);if(Prototype.Browser.IE){this.element.observe("selectstart",Event.stop)}else{if(Prototype.Browser.Gecko){this.element.setStyle({MozUserSelect:"none"})}}},destroy:function(){this.element.stopObserving("mousedown",this.mousedownE);DragDrop.Drags.unregister(this)},_mouseDown:function(a){$(document.body).setStyle({cursor:"default"});DragDrop.Drags.activate(this);this.move=0;this.wasDragged=false;this.lastcaption=null;if(Object.isFunction(this.options.onStart)){this.options.onStart(this,a)}if(!Prototype.Browser.IE&&!Prototype.Browser.Gecko){a.stop()}},_mouseMove:function(f){var b,c,a,d;if(++this.move<=this.options.threshold){return}this.lastCoord=d=[f.pointerX(),f.pointerY()];if(this.options.ghosting){if(!this.ghost){b=this.element.offsetLeft;c=this.element.offsetTop;this.ghost=$(this.element.cloneNode(true)).writeAttribute("id",null).setOpacity(0.7).clonePosition(this.element,{setLeft:false,setTop:false}).setStyle({left:b+"px",position:"absolute",top:c+"px",zIndex:parseInt(this.element.getStyle("zIndex"))+1});this.element.insert({before:this.ghost});a=this.ghost.viewportOffset();this.ghostOffset=[a[0]-b,a[1]-c]}d[0]-=this.ghostOffset[0];d[1]-=this.ghostOffset[1];switch(this.options.constraint){case"horizontal":d[1]=this.ghost.offsetTop;break;case"vertical":d[0]=this.ghost.offsetLeft;break}if(this.options.snap){d=this.options.snap(d[0],d[1],this.element)}if(this.options.offset){d[0]+=this.options.offset.x;d[1]+=this.options.offset.y}this._setContents(this.ghost,d[0],d[1])}this._onMoveDrag(d,f);if(Object.isFunction(this.options.onDrag)){this.options.onDrag(this,f)}this.wasDragged=true;if(this.options.scroll){this._onMoveScroll()}},_mouseUp:function(a){var b=DragDrop.Drops.drop;this._stopScrolling();if(this.ghost){this.ghost.remove();this.ghost=null}DragDrop.Drags.div.hide();if(DragDrop.validDrop(this.element)&&Object.isFunction(b.options.onDrop)){b.options.onDrop(b.element,this.element,a)}DragDrop.Drags.deactivate();if(Object.isFunction(this.options.onEnd)){this.options.onEnd(this,a)}},_onMoveDrag:function(k,g){var i,j,f,c,h=DragDrop.Drops.drop,a=DragDrop.Drags.div,b=true;if(h&&DragDrop.validDrop(this.element)){c=h.options.caption;if(c){j=Object.isFunction(c)?c(h.element,this.element,g):c;if(j&&h.options.hoverclass){f=h.options.hoverclass}}else{b=false}}if(b){if(!j){i=this.options.caption;j=Object.isFunction(i)?i(this.element):i}if(j!=this.lastcaption){this.lastcaption=j;a.update(j).writeAttribute({className:f||this.options.classname});if(j.empty()){a.hide()}}}if(!this.lastcaption.empty()){this._setContents(a,k[0]+15,k[1]+(this.ghost?(this.ghost.getHeight()+5):5))}},_onMoveScroll:function(){this._stopScrolling();var e,d,b,a=this.options.scroll,c=a.getDimensions();if(a.scrollHeight==c.height){return}e=document.viewport.getScrollOffsets();d=a.viewportOffset(),b=[0,0];d[0]+=a.scrollLeft+e.left;d[2]=d[0]+c.width;if(this.lastCoord[0]>d[2]||this.lastCoord[0]<d[0]){return}d[1]+=a.scrollTop+e.top;d[3]=d[1]+c.height;if(this.lastCoord[1]<d[1]){b[1]=this.lastCoord[1]-d[1]}if(this.lastCoord[1]>d[3]){b[1]=this.lastCoord[1]-d[3]}if(b[0]||b[1]){this.lastScrolled=new Date();this.scrollInterval=setInterval(this._scroll.bind(this,b[0]*15,b[1]*15),10)}},_stopScrolling:function(){if(this.scrollInterval){clearInterval(this.scrollInterval);this.scrollInterval=null}},_scroll:function(a,e){var c=new Date(),d=c-this.lastScrolled,b=this.options.scroll;this.lastScrolled=c;b.scrollTop+=e*d/1000},_setContents:function(c,a,e){var d=document.viewport.getDimensions(),b=c.getDimensions();if((a+b.width>d.width)||(e+b.height>d.height)){c.hide()}else{c.setStyle({left:a+"px",top:e+"px"}).show()}}}),Drop=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({accept:[],caption:"",hoverclass:"",onDrop:null,onOut:null,onOver:null},arguments[1]||{});this.mouseoverE=this._mouseOver.bindAsEventListener(this);this.mouseoutE=this._mouseOut.bindAsEventListener(this);this.element.observe("mouseover",this.mouseoverE);this.element.observe("mouseout",this.mouseoutE);DragDrop.Drops.register(this)},destroy:function(){this.element.stopObserving("mouseover",this.mouseoverE);this.element.stopObserving("mouseout",this.mouseoutE);DragDrop.Drops.unregister(this)},_mouseOver:function(a){if(DragDrop.Drags.drag){DragDrop.Drops.drop=this;if(Object.isFunction(this.options.onOver)){this.options.onOver(this.element,DragDrop.Drags.drag)}}},_mouseOut:function(a){if(Object.isFunction(this.options.onOut)){this.options.onOut(this.element,DragDrop.Drags.drag)}DragDrop.Drops.drop=null}});
\ No newline at end of file
+var DragDrop={Drags:{drags:$H(),register:function(a){if(!this.div){this.div=new Element("DIV",{className:a.options.classname}).hide();$(document.body).insert(this.div);document.observe("mousedown",this._mouseHandler.bindAsEventListener(this))}this.drags.set(a.element.identify(),a);a.element.addClassName("DragElt")},unregister:function(a){if(this.drag==a.element){this.drag.deactivate()}this.drags.unset(a.element.identify());a.element.removeClassName("DragElt")},get_drag:function(a){return this.drags.get(Object.isElement(a)?$(a).identify():a)},activate:function(a){if(this.drag){this.deactivate()}this.drag=a;this.mousemoveE=a._mouseMove.bindAsEventListener(a);this.mouseupE=a._mouseUp.bindAsEventListener(a);document.observe("mousemove",this.mousemoveE);document.observe("mouseup",this.mouseupE)},deactivate:function(){if(this.drag){this.drag=null;document.stopObserving("mousemove",this.mousemoveE);document.stopObserving("mouseup",this.mouseupE)}},_mouseHandler:function(b){var a=b.element();if(this.drags.size()){if(!a.hasClassName("DragElt")){a=a.up(".DragElt")}if(a){this.get_drag(a).mouseDown(b)}}}},Drops:{drops:$H(),init:false,register:function(a){if(!this.init){document.observe("mouseover",this._mouseHandler.bindAsEventListener(this,"over"));document.observe("mouseout",this._mouseHandler.bindAsEventListener(this,"out"));this.init=true}this.drops.set(a.element.identify(),a);a.element.addClassName("DropElt")},unregister:function(a){if(this.drop==a.element){this.drop=null}this.drops.unset(a.element.identify());a.element.addClassName("DropElt")},get_drop:function(a){return this.drops.get(Object.isElement(a)?$(a).identify():a)},_mouseHandler:function(c,b){var a=c.element();if(this.drops.size()){if(!a.hasClassName("DropElt")){a=a.up(".DropElt")}if(a){switch(b){case"over":this.get_drop(a).mouseOver(c);break;case"out":this.get_drop(a).mouseOut(c);break}}}}},validDrop:function(a){var b=DragDrop.Drops.drop;return(b&&a&&a!=b.element&&(!b.options.accept.size()||b.options.accept.include(a.tagName)))}},Drag=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({caption:"",classname:"drag",constraint:null,ghosting:false,scroll:null,snap:null,threshold:0,onDrag:null,onEnd:null,onStart:null},arguments[1]||{});if(this.options.scroll){this.options.scroll=$(this.options.scroll)}DragDrop.Drags.register(this);if(Prototype.Browser.IE){this.element.observe("selectstart",Event.stop)}else{if(Prototype.Browser.Gecko){this.element.setStyle({MozUserSelect:"none"})}}},destroy:function(){DragDrop.Drags.unregister(this)},mouseDown:function(a){$(document.body).setStyle({cursor:"default"});DragDrop.Drags.activate(this);this.move=0;this.wasDragged=false;this.lastcaption=null;if(Object.isFunction(this.options.onStart)){this.options.onStart(this,a)}if(!Prototype.Browser.IE&&!Prototype.Browser.Gecko){a.stop()}},_mouseMove:function(f){var b,c,a,d;if(++this.move<=this.options.threshold){return}this.lastCoord=d=[f.pointerX(),f.pointerY()];if(this.options.ghosting){if(!this.ghost){b=this.element.offsetLeft;c=this.element.offsetTop;this.ghost=$(this.element.cloneNode(true)).writeAttribute("id",null).setOpacity(0.7).clonePosition(this.element,{setLeft:false,setTop:false}).setStyle({left:b+"px",position:"absolute",top:c+"px",zIndex:parseInt(this.element.getStyle("zIndex"))+1});this.element.insert({before:this.ghost});a=this.ghost.viewportOffset();this.ghostOffset=[a[0]-b,a[1]-c]}d[0]-=this.ghostOffset[0];d[1]-=this.ghostOffset[1];switch(this.options.constraint){case"horizontal":d[1]=this.ghost.offsetTop;break;case"vertical":d[0]=this.ghost.offsetLeft;break}if(this.options.snap){d=this.options.snap(d[0],d[1],this.element)}if(this.options.offset){d[0]+=this.options.offset.x;d[1]+=this.options.offset.y}this._setContents(this.ghost,d[0],d[1])}this._onMoveDrag(d,f);if(Object.isFunction(this.options.onDrag)){this.options.onDrag(this,f)}this.wasDragged=true;if(this.options.scroll){this._onMoveScroll()}},_mouseUp:function(a){var b=DragDrop.Drops.drop;this._stopScrolling();if(this.ghost){this.ghost.remove();this.ghost=null}DragDrop.Drags.div.hide();if(DragDrop.validDrop(this.element)&&Object.isFunction(b.options.onDrop)){b.options.onDrop(b.element,this.element,a)}DragDrop.Drags.deactivate();if(Object.isFunction(this.options.onEnd)){this.options.onEnd(this,a)}},_onMoveDrag:function(k,g){var i,j,f,c,h=DragDrop.Drops.drop,a=DragDrop.Drags.div,b=true;if(h&&DragDrop.validDrop(this.element)){c=h.options.caption;if(c){j=Object.isFunction(c)?c(h.element,this.element,g):c;if(j&&h.options.hoverclass){f=h.options.hoverclass}}else{b=false}}if(b){if(!j){i=this.options.caption;j=Object.isFunction(i)?i(this.element):i}if(j!=this.lastcaption){this.lastcaption=j;a.update(j).writeAttribute({className:f||this.options.classname});if(j.empty()){a.hide()}}}if(!this.lastcaption.empty()){this._setContents(a,k[0]+15,k[1]+(this.ghost?(this.ghost.getHeight()+5):5))}},_onMoveScroll:function(){this._stopScrolling();var e,d,b,a=this.options.scroll,c=a.getDimensions();if(a.scrollHeight==c.height){return}e=document.viewport.getScrollOffsets();d=a.viewportOffset(),b=[0,0];d[0]+=a.scrollLeft+e.left;d[2]=d[0]+c.width;if(this.lastCoord[0]>d[2]||this.lastCoord[0]<d[0]){return}d[1]+=a.scrollTop+e.top;d[3]=d[1]+c.height;if(this.lastCoord[1]<d[1]){b[1]=this.lastCoord[1]-d[1]}if(this.lastCoord[1]>d[3]){b[1]=this.lastCoord[1]-d[3]}if(b[0]||b[1]){this.lastScrolled=new Date();this.scrollInterval=setInterval(this._scroll.bind(this,b[0]*15,b[1]*15),10)}},_stopScrolling:function(){if(this.scrollInterval){clearInterval(this.scrollInterval);this.scrollInterval=null}},_scroll:function(a,e){var c=new Date(),d=c-this.lastScrolled,b=this.options.scroll;this.lastScrolled=c;b.scrollTop+=e*d/1000},_setContents:function(c,a,e){var d=document.viewport.getDimensions(),b=c.getDimensions();if((a+b.width>d.width)||(e+b.height>d.height)){c.hide()}else{c.setStyle({left:a+"px",top:e+"px"}).show()}}}),Drop=Class.create({initialize:function(a){this.element=$(a);this.options=Object.extend({accept:[],caption:"",hoverclass:"",onDrop:null,onOut:null,onOver:null},arguments[1]||{});DragDrop.Drops.register(this)},destroy:function(){DragDrop.Drops.unregister(this)},mouseOver:function(a){if(DragDrop.Drags.drag){DragDrop.Drops.drop=this;if(Object.isFunction(this.options.onOver)){this.options.onOver(this.element,DragDrop.Drags.drag)}}},mouseOut:function(a){if(DragDrop.Drags.drag){if(Object.isFunction(this.options.onOut)){this.options.onOut(this.element,DragDrop.Drags.drag)}DragDrop.Drops.drop=null}}});
\ No newline at end of file
index 2d683e5..fc5bbd8 100644 (file)
@@ -63,7 +63,8 @@
  *
  * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
  *
- * @author Michael Slusarz <slusarz@curecanti.org>
+ * @author  Michael Slusarz <slusarz@curecanti.org>
+ * @package IMP
  */
 
 var DragDrop = {
@@ -72,14 +73,14 @@ var DragDrop = {
 
         register: function(obj)
         {
-            if (!this.drags.size()) {
-                if (!this.div) {
-                    this.div = new Element('DIV', { className: obj.options.classname }).hide();
-                }
+            if (!this.div) {
+                this.div = new Element('DIV', { className: obj.options.classname }).hide();
                 $(document.body).insert(this.div);
+                document.observe('mousedown', this._mouseHandler.bindAsEventListener(this));
             }
 
             this.drags.set(obj.element.identify(), obj);
+            obj.element.addClassName('DragElt');
         },
 
         unregister: function(obj)
@@ -89,10 +90,7 @@ var DragDrop = {
             }
 
             this.drags.unset(obj.element.identify());
-
-            if (!this.drags.size() && this.div) {
-                this.div.remove();
-            }
+            obj.element.removeClassName('DragElt');
         },
 
         get_drag: function(el)
@@ -119,15 +117,36 @@ var DragDrop = {
                 document.stopObserving('mousemove', this.mousemoveE);
                 document.stopObserving('mouseup', this.mouseupE);
             }
+        },
+
+        _mouseHandler: function(e)
+        {
+            var elt = e.element();
+
+            if (this.drags.size()) {
+                if (!elt.hasClassName('DragElt')) {
+                    elt = elt.up('.DragElt');
+                }
+                if (elt) {
+                    this.get_drag(elt).mouseDown(e);
+                }
+            }
         }
     },
 
     Drops: {
         drops: $H(),
+        init: false,
 
         register: function(obj)
         {
+            if (!this.init) {
+                document.observe('mouseover', this._mouseHandler.bindAsEventListener(this, 'over'));
+                document.observe('mouseout', this._mouseHandler.bindAsEventListener(this, 'out'));
+                this.init = true;
+            }
             this.drops.set(obj.element.identify(), obj);
+            obj.element.addClassName('DropElt');
         },
 
         unregister: function(obj)
@@ -137,11 +156,35 @@ var DragDrop = {
             }
 
             this.drops.unset(obj.element.identify());
+            obj.element.addClassName('DropElt');
         },
 
         get_drop: function(el)
         {
             return this.drops.get(Object.isElement(el) ? $(el).identify() : el);
+        },
+
+        _mouseHandler: function(e, type)
+        {
+            var elt = e.element();
+
+            if (this.drops.size()) {
+                if (!elt.hasClassName('DropElt')) {
+                    elt = elt.up('.DropElt');
+                }
+
+                if (elt) {
+                    switch (type) {
+                    case 'over':
+                        this.get_drop(elt).mouseOver(e);
+                        break;
+
+                    case 'out':
+                        this.get_drop(elt).mouseOut(e);
+                        break;
+                    }
+                }
+            }
         }
     },
 
@@ -172,8 +215,6 @@ Drag = Class.create({
             onEnd: null,
             onStart: null
         }, arguments[1] || {});
-        this.mousedownE = this._mouseDown.bindAsEventListener(this);
-        this.element.observe('mousedown', this.mousedownE);
         if (this.options.scroll) {
             this.options.scroll = $(this.options.scroll);
         }
@@ -193,11 +234,10 @@ Drag = Class.create({
 
     destroy: function()
     {
-        this.element.stopObserving('mousedown', this.mousedownE);
         DragDrop.Drags.unregister(this);
     },
 
-    _mouseDown: function(e)
+    mouseDown: function(e)
     {
         $(document.body).setStyle({ cursor: 'default' });
         DragDrop.Drags.activate(this);
@@ -433,21 +473,15 @@ Drop = Class.create({
             onOut: null,
             onOver: null
         }, arguments[1] || {});
-        this.mouseoverE = this._mouseOver.bindAsEventListener(this);
-        this.mouseoutE = this._mouseOut.bindAsEventListener(this);
-        this.element.observe('mouseover', this.mouseoverE);
-        this.element.observe('mouseout', this.mouseoutE);
         DragDrop.Drops.register(this);
     },
 
     destroy: function()
     {
-        this.element.stopObserving('mouseover', this.mouseoverE);
-        this.element.stopObserving('mouseout', this.mouseoutE);
         DragDrop.Drops.unregister(this);
     },
 
-    _mouseOver: function(e)
+    mouseOver: function(e)
     {
         if (DragDrop.Drags.drag) {
             DragDrop.Drops.drop = this;
@@ -457,11 +491,13 @@ Drop = Class.create({
         }
     },
 
-    _mouseOut: function(e)
+    mouseOut: function(e)
     {
-        if (Object.isFunction(this.options.onOut)) {
-            this.options.onOut(this.element, DragDrop.Drags.drag);
+        if (DragDrop.Drags.drag) {
+            if (Object.isFunction(this.options.onOut)) {
+                this.options.onOut(this.element, DragDrop.Drags.drag);
+            }
+            DragDrop.Drops.drop = null;
         }
-        DragDrop.Drops.drop = null;
     }
 });