|
1 // script.aculo.us dragdrop.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007 |
|
2 |
|
3 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) |
|
4 // (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) |
|
5 // |
|
6 // script.aculo.us is freely distributable under the terms of an MIT-style license. |
|
7 // For details, see the script.aculo.us web site: http://script.aculo.us/ |
|
8 // |
|
9 // Modified by Tero Marttila to strip unused code |
|
10 |
|
11 var Draggables = { |
|
12 drags: [], |
|
13 observers: [], |
|
14 |
|
15 register: function(draggable) { |
|
16 if(this.drags.length == 0) { |
|
17 this.eventMouseUp = this.endDrag.bindAsEventListener(this); |
|
18 this.eventMouseMove = this.updateDrag.bindAsEventListener(this); |
|
19 this.eventKeypress = this.keyPress.bindAsEventListener(this); |
|
20 |
|
21 Event.observe(document, "mouseup", this.eventMouseUp); |
|
22 Event.observe(document, "mousemove", this.eventMouseMove); |
|
23 Event.observe(document, "keypress", this.eventKeypress); |
|
24 } |
|
25 this.drags.push(draggable); |
|
26 }, |
|
27 |
|
28 unregister: function(draggable) { |
|
29 this.drags = this.drags.reject(function(d) { return d==draggable }); |
|
30 if(this.drags.length == 0) { |
|
31 Event.stopObserving(document, "mouseup", this.eventMouseUp); |
|
32 Event.stopObserving(document, "mousemove", this.eventMouseMove); |
|
33 Event.stopObserving(document, "keypress", this.eventKeypress); |
|
34 } |
|
35 }, |
|
36 |
|
37 activate: function(draggable) { |
|
38 if(draggable.options.delay) { |
|
39 this._timeout = setTimeout(function() { |
|
40 Draggables._timeout = null; |
|
41 window.focus(); |
|
42 Draggables.activeDraggable = draggable; |
|
43 }.bind(this), draggable.options.delay); |
|
44 } else { |
|
45 window.focus(); // allows keypress events if window isn't currently focused, fails for Safari |
|
46 this.activeDraggable = draggable; |
|
47 } |
|
48 }, |
|
49 |
|
50 deactivate: function() { |
|
51 this.activeDraggable = null; |
|
52 }, |
|
53 |
|
54 updateDrag: function(event) { |
|
55 if(!this.activeDraggable) return; |
|
56 var pointer = [Event.pointerX(event), Event.pointerY(event)]; |
|
57 // Mozilla-based browsers fire successive mousemove events with |
|
58 // the same coordinates, prevent needless redrawing (moz bug?) |
|
59 if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; |
|
60 this._lastPointer = pointer; |
|
61 |
|
62 this.activeDraggable.updateDrag(event, pointer); |
|
63 }, |
|
64 |
|
65 endDrag: function(event) { |
|
66 if(this._timeout) { |
|
67 clearTimeout(this._timeout); |
|
68 this._timeout = null; |
|
69 } |
|
70 if(!this.activeDraggable) return; |
|
71 this._lastPointer = null; |
|
72 this.activeDraggable.endDrag(event); |
|
73 this.activeDraggable = null; |
|
74 }, |
|
75 |
|
76 keyPress: function(event) { |
|
77 if(this.activeDraggable) |
|
78 this.activeDraggable.keyPress(event); |
|
79 }, |
|
80 |
|
81 addObserver: function(observer) { |
|
82 this.observers.push(observer); |
|
83 this._cacheObserverCallbacks(); |
|
84 }, |
|
85 |
|
86 removeObserver: function(element) { // element instead of observer fixes mem leaks |
|
87 this.observers = this.observers.reject( function(o) { return o.element==element }); |
|
88 this._cacheObserverCallbacks(); |
|
89 }, |
|
90 |
|
91 notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' |
|
92 if(this[eventName+'Count'] > 0) |
|
93 this.observers.each( function(o) { |
|
94 if(o[eventName]) o[eventName](eventName, draggable, event); |
|
95 }); |
|
96 if(draggable.options[eventName]) draggable.options[eventName](draggable, event); |
|
97 }, |
|
98 |
|
99 _cacheObserverCallbacks: function() { |
|
100 ['onStart','onEnd','onDrag'].each( function(eventName) { |
|
101 Draggables[eventName+'Count'] = Draggables.observers.select( |
|
102 function(o) { return o[eventName]; } |
|
103 ).length; |
|
104 }); |
|
105 } |
|
106 } |
|
107 |
|
108 /*--------------------------------------------------------------------------*/ |
|
109 |
|
110 var Draggable = Class.create({ |
|
111 initialize: function(element) { |
|
112 var defaults = { |
|
113 handle: false, |
|
114 zindex: 1000, |
|
115 quiet: false, |
|
116 delay: 0 |
|
117 }; |
|
118 |
|
119 var options = Object.extend(defaults, arguments[1] || { }); |
|
120 |
|
121 this.element = $(element); |
|
122 |
|
123 if(options.handle && Object.isString(options.handle)) |
|
124 this.handle = this.element.down('.'+options.handle, 0); |
|
125 |
|
126 if(!this.handle) this.handle = $(options.handle); |
|
127 if(!this.handle) this.handle = this.element; |
|
128 |
|
129 Element.makePositioned(this.element); // fix IE |
|
130 |
|
131 this.options = options; |
|
132 this.dragging = false; |
|
133 |
|
134 this.eventMouseDown = this.initDrag.bindAsEventListener(this); |
|
135 Event.observe(this.handle, "mousedown", this.eventMouseDown); |
|
136 |
|
137 Draggables.register(this); |
|
138 }, |
|
139 |
|
140 destroy: function() { |
|
141 Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); |
|
142 Draggables.unregister(this); |
|
143 }, |
|
144 |
|
145 currentDelta: function() { |
|
146 return([ |
|
147 parseInt(Element.getStyle(this.element,'left') || '0'), |
|
148 parseInt(Element.getStyle(this.element,'top') || '0')]); |
|
149 }, |
|
150 |
|
151 initDrag: function(event) { |
|
152 if(!Object.isUndefined(Draggable._dragging[this.element]) && |
|
153 Draggable._dragging[this.element]) return; |
|
154 if(Event.isLeftClick(event)) { |
|
155 // abort on form elements, fixes a Firefox issue |
|
156 var src = Event.element(event); |
|
157 if((tag_name = src.tagName.toUpperCase()) && ( |
|
158 tag_name=='INPUT' || |
|
159 tag_name=='SELECT' || |
|
160 tag_name=='OPTION' || |
|
161 tag_name=='BUTTON' || |
|
162 tag_name=='TEXTAREA')) return; |
|
163 |
|
164 var pointer = [Event.pointerX(event), Event.pointerY(event)]; |
|
165 var pos = Position.cumulativeOffset(this.element); |
|
166 this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); |
|
167 |
|
168 Draggables.activate(this); |
|
169 Event.stop(event); |
|
170 } |
|
171 }, |
|
172 |
|
173 startDrag: function(event) { |
|
174 this.dragging = true; |
|
175 if(!this.delta) |
|
176 this.delta = this.currentDelta(); |
|
177 |
|
178 if(this.options.zindex) { |
|
179 this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); |
|
180 this.element.style.zIndex = this.options.zindex; |
|
181 } |
|
182 |
|
183 Draggables.notify('onStart', this, event); |
|
184 }, |
|
185 |
|
186 updateDrag: function(event, pointer) { |
|
187 if(!this.dragging) this.startDrag(event); |
|
188 |
|
189 Draggables.notify('onDrag', this, event); |
|
190 |
|
191 this.draw(pointer); |
|
192 if(this.options.change) this.options.change(this); |
|
193 |
|
194 // fix AppleWebKit rendering |
|
195 if(Prototype.Browser.WebKit) window.scrollBy(0,0); |
|
196 |
|
197 Event.stop(event); |
|
198 }, |
|
199 |
|
200 finishDrag: function(event, success) { |
|
201 this.dragging = false; |
|
202 |
|
203 Draggables.notify('onEnd', this, event); |
|
204 |
|
205 var d = this.currentDelta(); |
|
206 this.delta = d; |
|
207 |
|
208 if(this.options.zindex) |
|
209 this.element.style.zIndex = this.originalZ; |
|
210 |
|
211 Draggables.deactivate(this); |
|
212 }, |
|
213 |
|
214 keyPress: function(event) { |
|
215 if(event.keyCode!=Event.KEY_ESC) return; |
|
216 this.finishDrag(event, false); |
|
217 Event.stop(event); |
|
218 }, |
|
219 |
|
220 endDrag: function(event) { |
|
221 if(!this.dragging) return; |
|
222 this.finishDrag(event, true); |
|
223 Event.stop(event); |
|
224 }, |
|
225 |
|
226 draw: function(point) { |
|
227 var pos = Position.cumulativeOffset(this.element); |
|
228 |
|
229 var d = this.currentDelta(); |
|
230 pos[0] -= d[0]; pos[1] -= d[1]; |
|
231 |
|
232 var p = [0,1].map(function(i){ |
|
233 return (point[i]-pos[i]-this.offset[i]) |
|
234 }.bind(this)); |
|
235 |
|
236 var style = this.element.style; |
|
237 if((!this.options.constraint) || (this.options.constraint=='horizontal')) |
|
238 style.left = p[0] + "px"; |
|
239 if((!this.options.constraint) || (this.options.constraint=='vertical')) |
|
240 style.top = p[1] + "px"; |
|
241 |
|
242 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering |
|
243 }, |
|
244 |
|
245 }); |
|
246 |
|
247 Draggable._dragging = { }; |
|
248 |