Skip to content
This repository
Browse code

Update to script.aculo.us 1.5.0_rc6

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3285 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit f7e39c4ec78e81c4336a1ef470f3ff0a2430fc7a 1 parent 6427db6
Thomas Fuchs madrobby authored
2  actionpack/CHANGELOG
... ... @@ -1,5 +1,7 @@
1 1 *SVN*
2 2
  3 +* Update to script.aculo.us 1.5.0_rc6
  4 +
3 5 * More robust relative url root discovery for SCGI compatibility. This solves the 'SCGI routes problem' -- you no longer need to prefix all your routes with the name of the SCGI mountpoint. #3070 [Dave Ringoen]
4 6
5 7 * Fix docs for text_area_tag. #3083. [Christopher Cotton]
309 actionpack/lib/action_view/helpers/javascripts/dragdrop.js
@@ -8,7 +8,7 @@ var Droppables = {
8 8 drops: [],
9 9
10 10 remove: function(element) {
11   - this.drops = this.drops.reject(function(d) { return d.element==element });
  11 + this.drops = this.drops.reject(function(d) { return d.element==$(element) });
12 12 },
13 13
14 14 add: function(element) {
@@ -43,7 +43,7 @@ var Droppables = {
43 43 return drop._containers.detect(function(c) { return parentNode == c });
44 44 },
45 45
46   - isAffected: function(pX, pY, element, drop) {
  46 + isAffected: function(point, element, drop) {
47 47 return (
48 48 (drop.element!=element) &&
49 49 ((!drop._containers) ||
@@ -51,7 +51,7 @@ var Droppables = {
51 51 ((!drop.accept) ||
52 52 (Element.classNames(element).detect(
53 53 function(v) { return drop.accept.include(v) } ) )) &&
54   - Position.within(drop.element, pX, pY) );
  54 + Position.within(drop.element, point[0], point[1]) );
55 55 },
56 56
57 57 deactivate: function(drop) {
@@ -61,38 +61,32 @@ var Droppables = {
61 61 },
62 62
63 63 activate: function(drop) {
64   - if(this.last_active) this.deactivate(this.last_active);
65 64 if(drop.hoverclass)
66 65 Element.addClassName(drop.element, drop.hoverclass);
67 66 this.last_active = drop;
68 67 },
69 68
70   - show: function(event, element) {
  69 + show: function(point, element) {
71 70 if(!this.drops.length) return;
72   - var pX = Event.pointerX(event);
73   - var pY = Event.pointerY(event);
74   - Position.prepare();
75   -
76   - var i = this.drops.length-1; do {
77   - var drop = this.drops[i];
78   - if(this.isAffected(pX, pY, element, drop)) {
  71 +
  72 + if(this.last_active) this.deactivate(this.last_active);
  73 + this.drops.each( function(drop) {
  74 + if(Droppables.isAffected(point, element, drop)) {
79 75 if(drop.onHover)
80 76 drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
81 77 if(drop.greedy) {
82   - this.activate(drop);
83   - return;
  78 + Droppables.activate(drop);
  79 + throw $break;
84 80 }
85 81 }
86   - } while (i--);
87   -
88   - if(this.last_active) this.deactivate(this.last_active);
  82 + });
89 83 },
90 84
91 85 fire: function(event, element) {
92 86 if(!this.last_active) return;
93 87 Position.prepare();
94 88
95   - if (this.isAffected(Event.pointerX(event), Event.pointerY(event), element, this.last_active))
  89 + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
96 90 if (this.last_active.onDrop)
97 91 this.last_active.onDrop(element, this.last_active.element, event);
98 92 },
@@ -104,21 +98,78 @@ var Droppables = {
104 98 }
105 99
106 100 var Draggables = {
  101 + drags: [],
107 102 observers: [],
  103 +
  104 + register: function(draggable) {
  105 + if(this.drags.length == 0) {
  106 + this.eventMouseUp = this.endDrag.bindAsEventListener(this);
  107 + this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
  108 + this.eventKeypress = this.keyPress.bindAsEventListener(this);
  109 +
  110 + Event.observe(document, "mouseup", this.eventMouseUp);
  111 + Event.observe(document, "mousemove", this.eventMouseMove);
  112 + Event.observe(document, "keypress", this.eventKeypress);
  113 + }
  114 + this.drags.push(draggable);
  115 + },
  116 +
  117 + unregister: function(draggable) {
  118 + this.drags = this.drags.reject(function(d) { return d==draggable });
  119 + if(this.drags.length == 0) {
  120 + Event.stopObserving(document, "mouseup", this.eventMouseUp);
  121 + Event.stopObserving(document, "mousemove", this.eventMouseMove);
  122 + Event.stopObserving(document, "keypress", this.eventKeypress);
  123 + }
  124 + },
  125 +
  126 + activate: function(draggable) {
  127 + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
  128 + this.activeDraggable = draggable;
  129 + },
  130 +
  131 + deactivate: function(draggbale) {
  132 + this.activeDraggable = null;
  133 + },
  134 +
  135 + updateDrag: function(event) {
  136 + if(!this.activeDraggable) return;
  137 + var pointer = [Event.pointerX(event), Event.pointerY(event)];
  138 + // Mozilla-based browsers fire successive mousemove events with
  139 + // the same coordinates, prevent needless redrawing (moz bug?)
  140 + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
  141 + this._lastPointer = pointer;
  142 + this.activeDraggable.updateDrag(event, pointer);
  143 + },
  144 +
  145 + endDrag: function(event) {
  146 + if(!this.activeDraggable) return;
  147 + this._lastPointer = null;
  148 + this.activeDraggable.endDrag(event);
  149 + },
  150 +
  151 + keyPress: function(event) {
  152 + if(this.activeDraggable)
  153 + this.activeDraggable.keyPress(event);
  154 + },
  155 +
108 156 addObserver: function(observer) {
109 157 this.observers.push(observer);
110 158 this._cacheObserverCallbacks();
111 159 },
  160 +
112 161 removeObserver: function(element) { // element instead of observer fixes mem leaks
113 162 this.observers = this.observers.reject( function(o) { return o.element==element });
114 163 this._cacheObserverCallbacks();
115 164 },
  165 +
116 166 notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
117 167 if(this[eventName+'Count'] > 0)
118 168 this.observers.each( function(o) {
119 169 if(o[eventName]) o[eventName](eventName, draggable, event);
120 170 });
121 171 },
  172 +
122 173 _cacheObserverCallbacks: function() {
123 174 ['onStart','onEnd','onDrag'].each( function(eventName) {
124 175 Draggables[eventName+'Count'] = Draggables.observers.select(
@@ -140,68 +191,48 @@ Draggable.prototype = {
140 191 },
141 192 reverteffect: function(element, top_offset, left_offset) {
142 193 var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
143   - new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});
  194 + element._revert = new Effect.MoveBy(element, -top_offset, -left_offset, {duration:dur});
144 195 },
145 196 endeffect: function(element) {
146   - new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
  197 + new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
147 198 },
148 199 zindex: 1000,
149   - revert: false
  200 + revert: false,
  201 + snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
150 202 }, arguments[1] || {});
151 203
152   - this.element = $(element);
  204 + this.element = $(element);
  205 +
153 206 if(options.handle && (typeof options.handle == 'string'))
154   - this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
155   -
  207 + this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
156 208 if(!this.handle) this.handle = $(options.handle);
157 209 if(!this.handle) this.handle = this.element;
158 210
159 211 Element.makePositioned(this.element); // fix IE
160 212
161   - this.offsetX = 0;
162   - this.offsetY = 0;
163   - this.originalLeft = this.currentLeft();
164   - this.originalTop = this.currentTop();
165   - this.originalX = this.element.offsetLeft;
166   - this.originalY = this.element.offsetTop;
167   -
168   - this.options = options;
169   -
170   - this.active = false;
171   - this.dragging = false;
  213 + this.delta = this.currentDelta();
  214 + this.options = options;
  215 + this.dragging = false;
172 216
173   - this.eventMouseDown = this.startDrag.bindAsEventListener(this);
174   - this.eventMouseUp = this.endDrag.bindAsEventListener(this);
175   - this.eventMouseMove = this.update.bindAsEventListener(this);
176   - this.eventKeypress = this.keyPress.bindAsEventListener(this);
  217 + this.eventMouseDown = this.initDrag.bindAsEventListener(this);
  218 + Event.observe(this.handle, "mousedown", this.eventMouseDown);
177 219
178   - this.registerEvents();
  220 + Draggables.register(this);
179 221 },
  222 +
180 223 destroy: function() {
181 224 Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
182   - this.unregisterEvents();
183   - },
184   - registerEvents: function() {
185   - Event.observe(document, "mouseup", this.eventMouseUp);
186   - Event.observe(document, "mousemove", this.eventMouseMove);
187   - Event.observe(document, "keypress", this.eventKeypress);
188   - Event.observe(this.handle, "mousedown", this.eventMouseDown);
189   - },
190   - unregisterEvents: function() {
191   - //if(!this.active) return;
192   - //Event.stopObserving(document, "mouseup", this.eventMouseUp);
193   - //Event.stopObserving(document, "mousemove", this.eventMouseMove);
194   - //Event.stopObserving(document, "keypress", this.eventKeypress);
  225 + Draggables.unregister(this);
195 226 },
196   - currentLeft: function() {
197   - return parseInt(this.element.style.left || '0');
  227 +
  228 + currentDelta: function() {
  229 + return([
  230 + parseInt(this.element.style.left || '0'),
  231 + parseInt(this.element.style.top || '0')]);
198 232 },
199   - currentTop: function() {
200   - return parseInt(this.element.style.top || '0')
201   - },
202   - startDrag: function(event) {
203   - if(Event.isLeftClick(event)) {
204   -
  233 +
  234 + initDrag: function(event) {
  235 + if(Event.isLeftClick(event)) {
205 236 // abort on form elements, fixes a Firefox issue
206 237 var src = Event.element(event);
207 238 if(src.tagName && (
@@ -209,20 +240,53 @@ Draggable.prototype = {
209 240 src.tagName=='SELECT' ||
210 241 src.tagName=='BUTTON' ||
211 242 src.tagName=='TEXTAREA')) return;
  243 +
  244 + if(this.element._revert) {
  245 + this.element._revert.cancel();
  246 + this.element._revert = null;
  247 + }
212 248
213   - // this.registerEvents();
214   - this.active = true;
215 249 var pointer = [Event.pointerX(event), Event.pointerY(event)];
216   - var offsets = Position.cumulativeOffset(this.element);
217   - this.offsetX = (pointer[0] - offsets[0]);
218   - this.offsetY = (pointer[1] - offsets[1]);
  250 + var pos = Position.cumulativeOffset(this.element);
  251 + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
  252 +
  253 + Draggables.activate(this);
219 254 Event.stop(event);
220 255 }
221 256 },
  257 +
  258 + startDrag: function(event) {
  259 + this.dragging = true;
  260 +
  261 + if(this.options.zindex) {
  262 + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
  263 + this.element.style.zIndex = this.options.zindex;
  264 + }
  265 +
  266 + if(this.options.ghosting) {
  267 + this._clone = this.element.cloneNode(true);
  268 + Position.absolutize(this.element);
  269 + this.element.parentNode.insertBefore(this._clone, this.element);
  270 + }
  271 +
  272 + Draggables.notify('onStart', this, event);
  273 + if(this.options.starteffect) this.options.starteffect(this.element);
  274 + },
  275 +
  276 + updateDrag: function(event, pointer) {
  277 + if(!this.dragging) this.startDrag(event);
  278 + Position.prepare();
  279 + Droppables.show(pointer, this.element);
  280 + Draggables.notify('onDrag', this, event);
  281 + this.draw(pointer);
  282 + if(this.options.change) this.options.change(this);
  283 +
  284 + // fix AppleWebKit rendering
  285 + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
  286 + Event.stop(event);
  287 + },
  288 +
222 289 finishDrag: function(event, success) {
223   - // this.unregisterEvents();
224   -
225   - this.active = false;
226 290 this.dragging = false;
227 291
228 292 if(this.options.ghosting) {
@@ -236,14 +300,13 @@ Draggable.prototype = {
236 300
237 301 var revert = this.options.revert;
238 302 if(revert && typeof revert == 'function') revert = revert(this.element);
239   -
  303 +
  304 + var d = this.currentDelta();
240 305 if(revert && this.options.reverteffect) {
241 306 this.options.reverteffect(this.element,
242   - this.currentTop()-this.originalTop,
243   - this.currentLeft()-this.originalLeft);
  307 + d[1]-this.delta[1], d[0]-this.delta[0]);
244 308 } else {
245   - this.originalLeft = this.currentLeft();
246   - this.originalTop = this.currentTop();
  309 + this.delta = d;
247 310 }
248 311
249 312 if(this.options.zindex)
@@ -252,71 +315,48 @@ Draggable.prototype = {
252 315 if(this.options.endeffect)
253 316 this.options.endeffect(this.element);
254 317
255   -
  318 + Draggables.deactivate(this);
256 319 Droppables.reset();
257 320 },
  321 +
258 322 keyPress: function(event) {
259   - if(this.active) {
260   - if(event.keyCode==Event.KEY_ESC) {
261   - this.finishDrag(event, false);
262   - Event.stop(event);
263   - }
264   - }
  323 + if(!event.keyCode==Event.KEY_ESC) return;
  324 + this.finishDrag(event, false);
  325 + Event.stop(event);
265 326 },
  327 +
266 328 endDrag: function(event) {
267   - if(this.active && this.dragging) {
268   - this.finishDrag(event, true);
269   - Event.stop(event);
270   - }
271   - this.active = false;
272   - this.dragging = false;
273   - },
274   - draw: function(event) {
275   - var pointer = [Event.pointerX(event), Event.pointerY(event)];
276   - var offsets = Position.cumulativeOffset(this.element);
277   - offsets[0] -= this.currentLeft();
278   - offsets[1] -= this.currentTop();
  329 + if(!this.dragging) return;
  330 + this.finishDrag(event, true);
  331 + Event.stop(event);
  332 + },
  333 +
  334 + draw: function(point) {
  335 + var pos = Position.cumulativeOffset(this.element);
  336 + var d = this.currentDelta();
  337 + pos[0] -= d[0]; pos[1] -= d[1];
  338 +
  339 + var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this));
  340 +
  341 + if(this.options.snap) {
  342 + if(typeof this.options.snap == 'function') {
  343 + p = this.options.snap(p[0],p[1]);
  344 + } else {
  345 + if(this.options.snap instanceof Array) {
  346 + p = p.map( function(v, i) {
  347 + return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
  348 + } else {
  349 + p = p.map( function(v) {
  350 + return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
  351 + }
  352 + }}
  353 +
279 354 var style = this.element.style;
280 355 if((!this.options.constraint) || (this.options.constraint=='horizontal'))
281   - style.left = (pointer[0] - offsets[0] - this.offsetX) + "px";
  356 + style.left = p[0] + "px";
282 357 if((!this.options.constraint) || (this.options.constraint=='vertical'))
283   - style.top = (pointer[1] - offsets[1] - this.offsetY) + "px";
  358 + style.top = p[1] + "px";
284 359 if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
285   - },
286   - update: function(event) {
287   - if(this.active) {
288   - if(!this.dragging) {
289   - var style = this.element.style;
290   - this.dragging = true;
291   -
292   - if(Element.getStyle(this.element,'position')=='')
293   - style.position = "relative";
294   -
295   - if(this.options.zindex) {
296   - this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
297   - style.zIndex = this.options.zindex;
298   - }
299   -
300   - if(this.options.ghosting) {
301   - this._clone = this.element.cloneNode(true);
302   - Position.absolutize(this.element);
303   - this.element.parentNode.insertBefore(this._clone, this.element);
304   - }
305   -
306   - Draggables.notify('onStart', this, event);
307   - if(this.options.starteffect) this.options.starteffect(this.element);
308   - }
309   -
310   - Droppables.show(event, this.element);
311   - Draggables.notify('onDrag', this, event);
312   - this.draw(event);
313   - if(this.options.change) this.options.change(this);
314   -
315   - // fix AppleWebKit rendering
316   - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
317   -
318   - Event.stop(event);
319   - }
320 360 }
321 361 }
322 362
@@ -329,9 +369,11 @@ SortableObserver.prototype = {
329 369 this.observer = observer;
330 370 this.lastValue = Sortable.serialize(this.element);
331 371 },
  372 +
332 373 onStart: function() {
333 374 this.lastValue = Sortable.serialize(this.element);
334 375 },
  376 +
335 377 onEnd: function() {
336 378 Sortable.unmark();
337 379 if(this.lastValue != Sortable.serialize(this.element))
@@ -341,10 +383,12 @@ SortableObserver.prototype = {
341 383
342 384 var Sortable = {
343 385 sortables: new Array(),
  386 +
344 387 options: function(element){
345 388 element = $(element);
346 389 return this.sortables.detect(function(s) { return s.element == element });
347 390 },
  391 +
348 392 destroy: function(element){
349 393 element = $(element);
350 394 this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
@@ -354,6 +398,7 @@ var Sortable = {
354 398 });
355 399 this.sortables = this.sortables.reject(function(s) { return s.element == element });
356 400 },
  401 +
357 402 create: function(element) {
358 403 element = $(element);
359 404 var options = Object.extend({
@@ -447,7 +492,7 @@ var Sortable = {
447 492 if(!element.hasChildNodes()) return null;
448 493 var elements = [];
449 494 $A(element.childNodes).each( function(e) {
450   - if(e.tagName && e.tagName==options.tag.toUpperCase() &&
  495 + if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
451 496 (!options.only || (Element.hasClassName(e, options.only))))
452 497 elements.push(e);
453 498 if(options.tree) {
@@ -531,7 +576,7 @@ var Sortable = {
531 576 name: element.id,
532 577 format: sortableOptions.format || /^[^_]*_(.*)$/
533 578 }, arguments[1] || {});
534   - return $(this.findElements(element, options) || []).collect( function(item) {
  579 + return $(this.findElements(element, options) || []).map( function(item) {
535 580 return (encodeURIComponent(options.name) + "[]=" +
536 581 encodeURIComponent(item.id.match(options.format) ? item.id.match(options.format)[1] : ''));
537 582 }).join("&");
566 actionpack/lib/action_view/helpers/javascripts/effects.js
@@ -11,8 +11,8 @@
11 11 // converts rgb() and #xxx to #xxxxxx format,
12 12 // returns self (or first argument) if not convertable
13 13 String.prototype.parseColor = function() {
14   - color = "#";
15   - if(this.slice(0,4) == "rgb(") {
  14 + var color = '#';
  15 + if(this.slice(0,4) == 'rgb(') {
16 16 var cols = this.slice(4,this.length-1).split(',');
17 17 var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
18 18 } else {
@@ -26,8 +26,8 @@ String.prototype.parseColor = function() {
26 26
27 27 Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
28 28 var children = $(element).childNodes;
29   - var text = "";
30   - var classtest = new RegExp("^([^ ]+ )*" + ignoreclass+ "( [^ ]+)*$","i");
  29 + var text = '';
  30 + var classtest = new RegExp('^([^ ]+ )*' + ignoreclass+ '( [^ ]+)*$','i');
31 31
32 32 for (var i = 0; i < children.length; i++) {
33 33 if(children[i].nodeType==3) {
@@ -41,69 +41,70 @@ Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
41 41 return text;
42 42 }
43 43
  44 +Element.setStyle = function(element, style) {
  45 + element = $(element);
  46 + for(k in style) element.style[k.camelize()] = style[k];
  47 +}
  48 +
44 49 Element.setContentZoom = function(element, percent) {
45   - element = $(element);
46   - element.style.fontSize = (percent/100) + "em";
  50 + Element.setStyle(element, {fontSize: (percent/100) + 'em'});
47 51 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
48 52 }
49 53
50 54 Element.getOpacity = function(element){
51   - var opacity;
52   - if (opacity = Element.getStyle(element, "opacity"))
  55 + var opacity;
  56 + if (opacity = Element.getStyle(element, 'opacity'))
53 57 return parseFloat(opacity);
54   - if (opacity = (Element.getStyle(element, "filter") || '').match(/alpha\(opacity=(.*)\)/))
  58 + if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
55 59 if(opacity[1]) return parseFloat(opacity[1]) / 100;
56 60 return 1.0;
57 61 }
58 62
59 63 Element.setOpacity = function(element, value){
60 64 element= $(element);
61   - var els = element.style;
62   - if (value == 1){
63   - els.opacity = '0.999999';
  65 + if (value == 1){
  66 + Element.setStyle(element, { opacity:
  67 + (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
  68 + 0.999999 : null });
64 69 if(/MSIE/.test(navigator.userAgent))
65   - els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'');
  70 + Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
66 71 } else {
67 72 if(value < 0.00001) value = 0;
68   - els.opacity = value;
  73 + Element.setStyle(element, {opacity: value});
69 74 if(/MSIE/.test(navigator.userAgent))
70   - els.filter = Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
71   - "alpha(opacity="+value*100+")";
  75 + Element.setStyle(element,
  76 + { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
  77 + 'alpha(opacity='+value*100+')' });
72 78 }
73 79 }
74 80
75 81 Element.getInlineOpacity = function(element){
76   - element= $(element);
77   - var op;
78   - op = element.style.opacity;
79   - if (typeof op != "undefined" && op != "") return op;
80   - return "";
81   -}
82   -
83   -Element.setInlineOpacity = function(element, value){
84   - element= $(element);
85   - var els = element.style;
86   - els.opacity = value;
  82 + return $(element).style.opacity || '';
87 83 }
88   -
  84 +
89 85 Element.childrenWithClassName = function(element, className) {
90 86 return $A($(element).getElementsByTagName('*')).select(
91 87 function(c) { return Element.hasClassName(c, className) });
92   -}
93   -
  88 +}
  89 +
  90 +Array.prototype.call = function() {
  91 + var args = arguments;
  92 + this.each(function(f){ f.apply(this, args) });
  93 +}
  94 +
94 95 /*--------------------------------------------------------------------------*/
95 96
96 97 var Effect = {
97 98 tagifyText: function(element) {
98   - var tagifyStyle = "position:relative";
99   - if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ";zoom:1";
  99 + var tagifyStyle = 'position:relative';
  100 + if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
100 101 element = $(element);
101 102 $A(element.childNodes).each( function(child) {
102 103 if(child.nodeType==3) {
103 104 child.nodeValue.toArray().each( function(character) {
104 105 element.insertBefore(
105 106 Builder.node('span',{style: tagifyStyle},
106   - character == " " ? String.fromCharCode(160) : character),
  107 + character == ' ' ? String.fromCharCode(160) : character),
107 108 child);
108 109 });
109 110 Element.remove(child);
@@ -123,11 +124,10 @@ var Effect = {
123 124 speed: 0.1,
124 125 delay: 0.0
125 126 }, arguments[2] || {});
126   - var speed = options.speed;
127   - var delay = options.delay;
  127 + var masterDelay = options.delay;
128 128
129 129 $A(elements).each( function(element, index) {
130   - new effect(element, Object.extend(options, { delay: delay + index * speed }));
  130 + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
131 131 });
132 132 }
133 133 };
@@ -258,13 +258,15 @@ Effect.Base.prototype = {
258 258 if(this.setup) this.setup();
259 259 this.event('afterSetup');
260 260 }
261   - if(this.options.transition) pos = this.options.transition(pos);
262   - pos *= (this.options.to-this.options.from);
263   - pos += this.options.from;
264   - this.position = pos;
265   - this.event('beforeUpdate');
266   - if(this.update) this.update(pos);
267   - this.event('afterUpdate');
  261 + if(this.state == 'running') {
  262 + if(this.options.transition) pos = this.options.transition(pos);
  263 + pos *= (this.options.to-this.options.from);
  264 + pos += this.options.from;
  265 + this.position = pos;
  266 + this.event('beforeUpdate');
  267 + if(this.update) this.update(pos);
  268 + this.event('afterUpdate');
  269 + }
268 270 },
269 271 cancel: function() {
270 272 if(!this.options.sync) Effect.Queue.remove(this);
@@ -273,6 +275,9 @@ Effect.Base.prototype = {
273 275 event: function(eventName) {
274 276 if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
275 277 if(this.options[eventName]) this.options[eventName](this);
  278 + },
  279 + inspect: function() {
  280 + return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
276 281 }
277 282 }
278 283
@@ -302,7 +307,7 @@ Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
302 307 this.element = $(element);
303 308 // make this work on IE on elements without 'layout'
304 309 if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
305   - this.element.style.zoom = 1;
  310 + Element.setStyle(this.element, {zoom: 1});
306 311 var options = Object.extend({
307 312 from: Element.getOpacity(this.element) || 0.0,
308 313 to: 1.0
@@ -326,20 +331,16 @@ Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
326 331 // Bug in Opera: Opera returns the "real" position of a static element or
327 332 // relative element that does not have top/left explicitly set.
328 333 // ==> Always set top and left for position relative elements in your stylesheets
329   - // (to 0 if you do not need them)
330   -
  334 + // (to 0 if you do not need them)
331 335 Element.makePositioned(this.element);
332 336 this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0');
333 337 this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
334 338 },
335 339 update: function(position) {
336   - var topd = this.toTop * position + this.originalTop;
337   - var leftd = this.toLeft * position + this.originalLeft;
338   - this.setPosition(topd, leftd);
339   - },
340   - setPosition: function(topd, leftd) {
341   - this.element.style.top = topd + "px";
342   - this.element.style.left = leftd + "px";
  340 + Element.setStyle(this.element, {
  341 + top: this.toTop * position + this.originalTop + 'px',
  342 + left: this.toLeft * position + this.originalLeft + 'px'
  343 + });
343 344 }
344 345 });
345 346
@@ -359,33 +360,31 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
359 360 this.start(options);
360 361 },
361 362 setup: function() {
362   - var effect = this;
363   -
364 363 this.restoreAfterFinish = this.options.restoreAfterFinish || false;
365 364 this.elementPositioning = Element.getStyle(this.element,'position');
366 365
367   - effect.originalStyle = {};
  366 + this.originalStyle = {};
368 367 ['top','left','width','height','fontSize'].each( function(k) {
369   - effect.originalStyle[k] = effect.element.style[k];
370   - });
  368 + this.originalStyle[k] = this.element.style[k];
  369 + }.bind(this));
371 370
372 371 this.originalTop = this.element.offsetTop;
373 372 this.originalLeft = this.element.offsetLeft;
374 373
375   - var fontSize = Element.getStyle(this.element,'font-size') || "100%";
  374 + var fontSize = Element.getStyle(this.element,'font-size') || '100%';
376 375 ['em','px','%'].each( function(fontSizeType) {
377 376 if(fontSize.indexOf(fontSizeType)>0) {
378   - effect.fontSize = parseFloat(fontSize);
379   - effect.fontSizeType = fontSizeType;
  377 + this.fontSize = parseFloat(fontSize);
  378 + this.fontSizeType = fontSizeType;
380 379 }
381   - });
  380 + }.bind(this));
382 381
383 382 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
384 383
385 384 this.dims = null;
386 385 if(this.options.scaleMode=='box')
387   - this.dims = [this.element.clientHeight, this.element.clientWidth];
388   - if(this.options.scaleMode=='content')
  386 + this.dims = [this.element.offsetHeight, this.element.offsetWidth];
  387 + if(/^content/.test(this.options.scaleMode))
389 388 this.dims = [this.element.scrollHeight, this.element.scrollWidth];
390 389 if(!this.dims)
391 390 this.dims = [this.options.scaleMode.originalHeight,
@@ -394,32 +393,28 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
394 393 update: function(position) {
395 394 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
396 395 if(this.options.scaleContent && this.fontSize)
397   - this.element.style.fontSize = this.fontSize*currentScale + this.fontSizeType;
  396 + Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
398 397 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
399 398 },
400 399 finish: function(position) {
401   - if (this.restoreAfterFinish) {
402   - var effect = this;
403   - ['top','left','width','height','fontSize'].each( function(k) {
404   - effect.element.style[k] = effect.originalStyle[k];
405   - });
406   - }
  400 + if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
407 401 },
408 402 setDimensions: function(height, width) {
409   - var els = this.element.style;
410   - if(this.options.scaleX) els.width = width + 'px';
411   - if(this.options.scaleY) els.height = height + 'px';
  403 + var d = {};
  404 + if(this.options.scaleX) d.width = width + 'px';
  405 + if(this.options.scaleY) d.height = height + 'px';
412 406 if(this.options.scaleFromCenter) {
413 407 var topd = (height - this.dims[0])/2;
414 408 var leftd = (width - this.dims[1])/2;
415 409 if(this.elementPositioning == 'absolute') {
416   - if(this.options.scaleY) els.top = this.originalTop-topd + "px";
417   - if(this.options.scaleX) els.left = this.originalLeft-leftd + "px";
  410 + if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
  411 + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
418 412 } else {
419   - if(this.options.scaleY) els.top = -topd + "px";
420   - if(this.options.scaleX) els.left = -leftd + "px";
  413 + if(this.options.scaleY) d.top = -topd + 'px';
  414 + if(this.options.scaleX) d.left = -leftd + 'px';
421 415 }
422 416 }
  417 + Element.setStyle(this.element, d);
423 418 }
424 419 });
425 420
@@ -427,41 +422,32 @@ Effect.Highlight = Class.create();
427 422 Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
428 423 initialize: function(element) {
429 424 this.element = $(element);
430   - var options = Object.extend({
431   - startcolor: "#ffff99"
432   - }, arguments[1] || {});
  425 + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
433 426 this.start(options);
434 427 },
435 428 setup: function() {
436 429 // Prevent executing on elements not in the layout flow
437   - if(this.element.style.display=='none') { this.cancel(); return; }
  430 + if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
438 431 // Disable background image during the effect
439   - this.oldBgImage = this.element.style.backgroundImage;
440   - this.element.style.backgroundImage = "none";
  432 + this.oldStyle = {
  433 + backgroundImage: Element.getStyle(this.element, 'background-image') };
  434 + Element.setStyle(this.element, {backgroundImage: 'none'});
441 435 if(!this.options.endcolor)
442 436 this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
443   - if (typeof this.options.restorecolor == "undefined")
444   - this.options.restorecolor = this.element.style.backgroundColor;
  437 + if(!this.options.restorecolor)
  438 + this.options.restorecolor = Element.getStyle(this.element, 'background-color');
445 439 // init color calculations
446   - this.colors_base = [
447   - parseInt(this.options.startcolor.slice(1,3),16),
448   - parseInt(this.options.startcolor.slice(3,5),16),
449   - parseInt(this.options.startcolor.slice(5),16) ];
450   - this.colors_delta = [
451   - parseInt(this.options.endcolor.slice(1,3),16)-this.colors_base[0],
452   - parseInt(this.options.endcolor.slice(3,5),16)-this.colors_base[1],
453   - parseInt(this.options.endcolor.slice(5),16)-this.colors_base[2]];
  440 + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
  441 + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
454 442 },
455 443 update: function(position) {
456   - var effect = this; var colors = $R(0,2).map( function(i){
457   - return Math.round(effect.colors_base[i]+(effect.colors_delta[i]*position))
458   - });
459   - this.element.style.backgroundColor = "#" +
460   - colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart();
  444 + Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
  445 + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
461 446 },
462 447 finish: function() {
463   - this.element.style.backgroundColor = this.options.restorecolor;
464   - this.element.style.backgroundImage = this.oldBgImage;
  448 + Element.setStyle(this.element, Object.extend(this.oldStyle, {
  449 + backgroundColor: this.options.restorecolor
  450 + }));
465 451 }
466 452 });
467 453
@@ -474,6 +460,7 @@ Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
474 460 setup: function() {
475 461 Position.prepare();
476 462 var offsets = Position.cumulativeOffset(this.element);
  463 + if(this.options.offset) offsets[1] += this.options.offset;
477 464 var max = window.innerHeight ?
478 465 window.height - window.innerHeight :
479 466 document.body.scrollHeight -
@@ -496,42 +483,38 @@ Effect.Fade = function(element) {
496 483 var options = Object.extend({
497 484 from: Element.getOpacity(element) || 1.0,
498 485 to: 0.0,
499   - afterFinishInternal: function(effect)
500   - { if (effect.options.to == 0) {
501   - Element.hide(effect.element);
502   - Element.setInlineOpacity(effect.element, oldOpacity);
503   - }
504   - }
  486 + afterFinishInternal: function(effect) { with(Element) {
  487 + if(effect.options.to!=0) return;
  488 + hide(effect.element);
  489 + setStyle(effect.element, {opacity: oldOpacity}); }}
505 490 }, arguments[1] || {});
506 491 return new Effect.Opacity(element,options);
507 492 }
508 493
509 494 Effect.Appear = function(element) {
510 495 var options = Object.extend({
511   - from: (Element.getStyle(element, "display") == "none" ? 0.0 : Element.getOpacity(element) || 0.0),
  496 + from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
512 497 to: 1.0,
513   - beforeSetup: function(effect)
514   - { Element.setOpacity(effect.element, effect.options.from);
515   - Element.show(effect.element); }
  498 + beforeSetup: function(effect) { with(Element) {
  499 + setOpacity(effect.element, effect.options.from);
  500 + show(effect.element); }}
516 501 }, arguments[1] || {});
517 502 return new Effect.Opacity(element,options);
518 503 }
519 504
520 505 Effect.Puff = function(element) {
521 506 element = $(element);
522   - var oldOpacity = Element.getInlineOpacity(element);
523   - var oldPosition = element.style.position;
  507 + var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
524 508 return new Effect.Parallel(
525 509 [ new Effect.Scale(element, 200,
526 510 { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
527 511 new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
528 512 Object.extend({ duration: 1.0,
529   - beforeSetupInternal: function(effect)
530   - { effect.effects[0].element.style.position = 'absolute'; },
531   - afterFinishInternal: function(effect)
532   - { Element.hide(effect.effects[0].element);
533   - effect.effects[0].element.style.position = oldPosition;
534   - Element.setInlineOpacity(effect.effects[0].element, oldOpacity); }
  513 + beforeSetupInternal: function(effect) { with(Element) {
  514 + setStyle(effect.effects[0].element, {position: 'absolute'}); }},
  515 + afterFinishInternal: function(effect) { with(Element) {
  516 + hide(effect.effects[0].element);
  517 + setStyle(effect.effects[0].element, oldStyle); }}
535 518 }, arguments[1] || {})
536 519 );
537 520 }
@@ -543,18 +526,15 @@ Effect.BlindUp = function(element) {
543 526 Object.extend({ scaleContent: false,
544 527 scaleX: false,
545 528 restoreAfterFinish: true,
546   - afterFinishInternal: function(effect)
547   - {
548   - Element.hide(effect.element);
549   - Element.undoClipping(effect.element);
550   - }
  529 + afterFinishInternal: function(effect) { with(Element) {
  530 + [hide, undoClipping].call(effect.element); }}
551 531 }, arguments[1] || {})
552 532 );
553 533 }
554 534
555 535 Effect.BlindDown = function(element) {
556 536 element = $(element);
557   - var oldHeight = element.style.height;
  537 + var oldHeight = Element.getStyle(element, 'height');
558 538 var elementDimensions = Element.getDimensions(element);
559 539 return new Effect.Scale(element, 100,
560 540 Object.extend({ scaleContent: false,
@@ -562,15 +542,15 @@ Effect.BlindDown = function(element) {
562 542 scaleFrom: 0,
563 543 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
564 544 restoreAfterFinish: true,
565   - afterSetup: function(effect) {
566   - Element.makeClipping(effect.element);
567   - effect.element.style.height = "0px";
568   - Element.show(effect.element);
569   - },
570   - afterFinishInternal: function(effect) {
571   - Element.undoClipping(effect.element);
572   - effect.element.style.height = oldHeight;
573   - }
  545 + afterSetup: function(effect) { with(Element) {
  546 + makeClipping(effect.element);
  547 + setStyle(effect.element, {height: '0px'});
  548 + show(effect.element);
  549 + }},
  550 + afterFinishInternal: function(effect) { with(Element) {
  551 + undoClipping(effect.element);
  552 + setStyle(effect.element, {height: oldHeight});
  553 + }}
574 554 }, arguments[1] || {})
575 555 );
576 556 }
@@ -586,16 +566,13 @@ Effect.SwitchOff = function(element) {
586 566 new Effect.Scale(effect.element, 1, {
587 567 duration: 0.3, scaleFromCenter: true,
588 568 scaleX: false, scaleContent: false, restoreAfterFinish: true,
589   - beforeSetup: function(effect) {
590   - Element.makePositioned(effect.element);
591   - Element.makeClipping(effect.element);
592   - },
593   - afterFinishInternal: function(effect) {
594   - Element.hide(effect.element);
595   - Element.undoClipping(effect.element);
596   - Element.undoPositioned(effect.element);
597   - Element.setInlineOpacity(effect.element, oldOpacity);
598   - }
  569 + beforeSetup: function(effect) { with(Element) {
  570 + [makePositioned,makeClipping].call(effect.element);
  571 + }},
  572 + afterFinishInternal: function(effect) { with(Element) {
  573 + [hide,undoClipping,undoPositioned].call(effect.element);
  574 + setStyle(effect.element, {opacity: oldOpacity});
  575 + }}
599 576 })
600 577 }
601 578 });
@@ -603,29 +580,28 @@ Effect.SwitchOff = function(element) {
603 580
604 581 Effect.DropOut = function(element) {
605 582 element = $(element);
606   - var oldTop = element.style.top;
607   - var oldLeft = element.style.left;
608   - var oldOpacity = Element.getInlineOpacity(element);
  583 + var oldStyle = {
  584 + top: Element.getStyle(element, 'top'),
  585 + left: Element.getStyle(element, 'left'),
  586 + opacity: Element.getInlineOpacity(element) };
609 587 return new Effect.Parallel(
610 588 [ new Effect.MoveBy(element, 100, 0, { sync: true }),
611 589 new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
612 590 Object.extend(
613 591 { duration: 0.5,
614   - beforeSetup: function(effect) {
615   - Element.makePositioned(effect.effects[0].element); },
616   - afterFinishInternal: function(effect) {
617   - Element.hide(effect.effects[0].element);
618   - Element.undoPositioned(effect.effects[0].element);
619   - effect.effects[0].element.style.left = oldLeft;
620   - effect.effects[0].element.style.top = oldTop;
621   - Element.setInlineOpacity(effect.effects[0].element, oldOpacity); }
  592 + beforeSetup: function(effect) { with(Element) {
  593 + makePositioned(effect.effects[0].element); }},
  594 + afterFinishInternal: function(effect) { with(Element) {
  595 + [hide, undoPositioned].call(effect.effects[0].element);
  596 + setStyle(effect.effects[0].element, oldStyle); }}
622 597 }, arguments[1] || {}));
623 598 }
624 599
625 600 Effect.Shake = function(element) {
626 601 element = $(element);
627   - var oldTop = element.style.top;
628   - var oldLeft = element.style.left;
  602 + var oldStyle = {
  603 + top: Element.getStyle(element, 'top'),
  604 + left: Element.getStyle(element, 'left') };
629 605 return new Effect.MoveBy(element, 0, 20,
630 606 { duration: 0.05, afterFinishInternal: function(effect) {
631 607 new Effect.MoveBy(effect.element, 0, -40,
@@ -637,39 +613,39 @@ Effect.Shake = function(element) {
637 613 new Effect.MoveBy(effect.element, 0, 40,
638 614 { duration: 0.1, afterFinishInternal: function(effect) {
639 615 new Effect.MoveBy(effect.element, 0, -20,
640   - { duration: 0.05, afterFinishInternal: function(effect) {
641   - Element.undoPositioned(effect.element);
642   - effect.element.style.left = oldLeft;
643   - effect.element.style.top = oldTop;
644   - }}) }}) }}) }}) }}) }});
  616 + { duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
  617 + undoPositioned(effect.element);
  618 + setStyle(effect.element, oldStyle);
  619 + }}}) }}) }}) }}) }}) }});
645 620 }
646 621
647 622 Effect.SlideDown = function(element) {
648 623 element = $(element);
649 624 Element.cleanWhitespace(element);
650 625 // SlideDown need to have the content of the element wrapped in a container element with fixed height!
651   - var oldInnerBottom = element.firstChild.style.bottom;
  626 + var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
652 627 var elementDimensions = Element.getDimensions(element);
653   - return new Effect.Scale(element, 100,
654   - Object.extend({ scaleContent: false,
  628 + return new Effect.Scale(element, 100, Object.extend({
  629 + scaleContent: false,
655 630 scaleX: false,
656 631 scaleFrom: 0,
657   - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  632 + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
658 633 restoreAfterFinish: true,
659   - afterSetup: function(effect) {
660   - Element.makePositioned(effect.element.firstChild);
661   - if (window.opera) effect.element.firstChild.style.top = "";
662   - Element.makeClipping(effect.element);
663   - element.style.height = '0';
664   - Element.show(element);
665   - },
666   - afterUpdateInternal: function(effect) {
667   - effect.element.firstChild.style.bottom =
668   - (effect.dims[0] - effect.element.clientHeight) + 'px'; },
669   - afterFinishInternal: function(effect) {
670   - Element.undoClipping(effect.element);
671   - Element.undoPositioned(effect.element.firstChild);