backlog 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. data/History.txt +15 -0
  2. data/app/controllers/application.rb +17 -0
  3. data/app/controllers/customers_controller.rb +51 -0
  4. data/app/controllers/estimates_controller.rb +3 -4
  5. data/app/controllers/tasks_controller.rb +20 -32
  6. data/app/helpers/application_helper.rb +11 -2
  7. data/app/helpers/customers_helper.rb +2 -0
  8. data/app/helpers/tasks_helper.rb +69 -0
  9. data/app/views/customers/_form.rhtml +7 -0
  10. data/app/views/customers/edit.rhtml +9 -0
  11. data/app/views/customers/list.rhtml +27 -0
  12. data/app/views/customers/new.rhtml +8 -0
  13. data/app/views/customers/show.rhtml +8 -0
  14. data/app/views/periods/_show_active.rhtml +13 -10
  15. data/app/views/redirect.rjs +1 -0
  16. data/app/views/redirect.rjs~ +0 -0
  17. data/app/views/tasks/_fields_header.rhtml +1 -1
  18. data/app/views/tasks/_form.rhtml +6 -1
  19. data/app/views/tasks/_task.rhtml +3 -3
  20. data/app/views/tasks/finish.rjs +4 -0
  21. data/app/views/tasks/move_to_period.rjs +4 -0
  22. data/app/views/tasks/reopen.rjs +4 -24
  23. data/config/boot.rb +1 -10
  24. data/public/javascripts/builder.js +136 -0
  25. data/public/javascripts/controls.js +486 -354
  26. data/public/javascripts/dragdrop.js +82 -52
  27. data/public/javascripts/effects.js +398 -364
  28. data/public/javascripts/prototype.js +2764 -1095
  29. data/public/javascripts/scriptaculous.js +58 -0
  30. data/public/javascripts/slider.js +275 -0
  31. data/public/javascripts/sound.js +55 -0
  32. data/public/javascripts/unittest.js +568 -0
  33. data/test/functional/backlogs_controller_test.rb +1 -1
  34. data/test/functional/customers_controller_test.rb +93 -0
  35. data/test/functional/tasks_controller_test.rb +4 -8
  36. data/test/functional/work_accounts_controller_test.rb +1 -1
  37. data/test/performance/test_threaded.rb +40 -31
  38. data/test/test_helper.rb +4 -2
  39. metadata +20 -3
  40. data/app/views/tasks/finish_ajax.rjs +0 -25
@@ -1,12 +1,12 @@
1
- // script.aculo.us dragdrop.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
1
+ // script.aculo.us dragdrop.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
2
2
 
3
- // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
- // (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
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
5
  //
6
6
  // script.aculo.us is freely distributable under the terms of an MIT-style license.
7
7
  // For details, see the script.aculo.us web site: http://script.aculo.us/
8
8
 
9
- if(typeof Effect == 'undefined')
9
+ if(Object.isUndefined(Effect))
10
10
  throw("dragdrop.js requires including script.aculo.us' effects.js library");
11
11
 
12
12
  var Droppables = {
@@ -22,14 +22,13 @@ var Droppables = {
22
22
  greedy: true,
23
23
  hoverclass: null,
24
24
  tree: false
25
- }, arguments[1] || {});
25
+ }, arguments[1] || { });
26
26
 
27
27
  // cache containers
28
28
  if(options.containment) {
29
29
  options._containers = [];
30
30
  var containment = options.containment;
31
- if((typeof containment == 'object') &&
32
- (containment.constructor == Array)) {
31
+ if(Object.isArray(containment)) {
33
32
  containment.each( function(c) { options._containers.push($(c)) });
34
33
  } else {
35
34
  options._containers.push($(containment));
@@ -89,21 +88,23 @@ var Droppables = {
89
88
 
90
89
  show: function(point, element) {
91
90
  if(!this.drops.length) return;
92
- var affected = [];
91
+ var drop, affected = [];
93
92
 
94
- if(this.last_active) this.deactivate(this.last_active);
95
93
  this.drops.each( function(drop) {
96
94
  if(Droppables.isAffected(point, element, drop))
97
95
  affected.push(drop);
98
96
  });
99
97
 
100
- if(affected.length>0) {
98
+ if(affected.length>0)
101
99
  drop = Droppables.findDeepestChild(affected);
100
+
101
+ if(this.last_active && this.last_active != drop) this.deactivate(this.last_active);
102
+ if (drop) {
102
103
  Position.within(drop.element, point[0], point[1]);
103
104
  if(drop.onHover)
104
105
  drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
105
106
 
106
- Droppables.activate(drop);
107
+ if (drop != this.last_active) Droppables.activate(drop);
107
108
  }
108
109
  },
109
110
 
@@ -112,8 +113,10 @@ var Droppables = {
112
113
  Position.prepare();
113
114
 
114
115
  if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
115
- if (this.last_active.onDrop)
116
- this.last_active.onDrop(element, this.last_active.element, event);
116
+ if (this.last_active.onDrop) {
117
+ this.last_active.onDrop(element, this.last_active.element, event);
118
+ return true;
119
+ }
117
120
  },
118
121
 
119
122
  reset: function() {
@@ -221,10 +224,7 @@ var Draggables = {
221
224
 
222
225
  /*--------------------------------------------------------------------------*/
223
226
 
224
- var Draggable = Class.create();
225
- Draggable._dragging = {};
226
-
227
- Draggable.prototype = {
227
+ var Draggable = Class.create({
228
228
  initialize: function(element) {
229
229
  var defaults = {
230
230
  handle: false,
@@ -235,7 +235,7 @@ Draggable.prototype = {
235
235
  });
236
236
  },
237
237
  endeffect: function(element) {
238
- var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
238
+ var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0;
239
239
  new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
240
240
  queue: {scope:'_draggable', position:'end'},
241
241
  afterFinish: function(){
@@ -245,6 +245,7 @@ Draggable.prototype = {
245
245
  },
246
246
  zindex: 1000,
247
247
  revert: false,
248
+ quiet: false,
248
249
  scroll: false,
249
250
  scrollSensitivity: 20,
250
251
  scrollSpeed: 15,
@@ -252,7 +253,7 @@ Draggable.prototype = {
252
253
  delay: 0
253
254
  };
254
255
 
255
- if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
256
+ if(!arguments[1] || Object.isUndefined(arguments[1].endeffect))
256
257
  Object.extend(defaults, {
257
258
  starteffect: function(element) {
258
259
  element._opacity = Element.getOpacity(element);
@@ -261,11 +262,11 @@ Draggable.prototype = {
261
262
  }
262
263
  });
263
264
 
264
- var options = Object.extend(defaults, arguments[1] || {});
265
+ var options = Object.extend(defaults, arguments[1] || { });
265
266
 
266
267
  this.element = $(element);
267
268
 
268
- if(options.handle && (typeof options.handle == 'string'))
269
+ if(options.handle && Object.isString(options.handle))
269
270
  this.handle = this.element.down('.'+options.handle, 0);
270
271
 
271
272
  if(!this.handle) this.handle = $(options.handle);
@@ -278,7 +279,6 @@ Draggable.prototype = {
278
279
 
279
280
  Element.makePositioned(this.element); // fix IE
280
281
 
281
- this.delta = this.currentDelta();
282
282
  this.options = options;
283
283
  this.dragging = false;
284
284
 
@@ -300,7 +300,7 @@ Draggable.prototype = {
300
300
  },
301
301
 
302
302
  initDrag: function(event) {
303
- if(typeof Draggable._dragging[this.element] != 'undefined' &&
303
+ if(!Object.isUndefined(Draggable._dragging[this.element]) &&
304
304
  Draggable._dragging[this.element]) return;
305
305
  if(Event.isLeftClick(event)) {
306
306
  // abort on form elements, fixes a Firefox issue
@@ -323,6 +323,8 @@ Draggable.prototype = {
323
323
 
324
324
  startDrag: function(event) {
325
325
  this.dragging = true;
326
+ if(!this.delta)
327
+ this.delta = this.currentDelta();
326
328
 
327
329
  if(this.options.zindex) {
328
330
  this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
@@ -331,7 +333,9 @@ Draggable.prototype = {
331
333
 
332
334
  if(this.options.ghosting) {
333
335
  this._clone = this.element.cloneNode(true);
334
- Position.absolutize(this.element);
336
+ this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute');
337
+ if (!this.element._originallyAbsolute)
338
+ Position.absolutize(this.element);
335
339
  this.element.parentNode.insertBefore(this._clone, this.element);
336
340
  }
337
341
 
@@ -353,8 +357,12 @@ Draggable.prototype = {
353
357
 
354
358
  updateDrag: function(event, pointer) {
355
359
  if(!this.dragging) this.startDrag(event);
356
- Position.prepare();
357
- Droppables.show(pointer, this.element);
360
+
361
+ if(!this.options.quiet){
362
+ Position.prepare();
363
+ Droppables.show(pointer, this.element);
364
+ }
365
+
358
366
  Draggables.notify('onDrag', this, event);
359
367
 
360
368
  this.draw(pointer);
@@ -382,30 +390,44 @@ Draggable.prototype = {
382
390
  }
383
391
 
384
392
  // fix AppleWebKit rendering
385
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
393
+ if(Prototype.Browser.WebKit) window.scrollBy(0,0);
386
394
 
387
395
  Event.stop(event);
388
396
  },
389
397
 
390
398
  finishDrag: function(event, success) {
391
399
  this.dragging = false;
400
+
401
+ if(this.options.quiet){
402
+ Position.prepare();
403
+ var pointer = [Event.pointerX(event), Event.pointerY(event)];
404
+ Droppables.show(pointer, this.element);
405
+ }
392
406
 
393
407
  if(this.options.ghosting) {
394
- Position.relativize(this.element);
408
+ if (!this.element._originallyAbsolute)
409
+ Position.relativize(this.element);
410
+ delete this.element._originallyAbsolute;
395
411
  Element.remove(this._clone);
396
412
  this._clone = null;
397
413
  }
398
414
 
399
- if(success) Droppables.fire(event, this.element);
415
+ var dropped = false;
416
+ if(success) {
417
+ dropped = Droppables.fire(event, this.element);
418
+ if (!dropped) dropped = false;
419
+ }
420
+ if(dropped && this.options.onDropped) this.options.onDropped(this.element);
400
421
  Draggables.notify('onEnd', this, event);
401
422
 
402
423
  var revert = this.options.revert;
403
- if(revert && typeof revert == 'function') revert = revert(this.element);
424
+ if(revert && Object.isFunction(revert)) revert = revert(this.element);
404
425
 
405
426
  var d = this.currentDelta();
406
427
  if(revert && this.options.reverteffect) {
407
- this.options.reverteffect(this.element,
408
- d[1]-this.delta[1], d[0]-this.delta[0]);
428
+ if (dropped == 0 || revert != 'failure')
429
+ this.options.reverteffect(this.element,
430
+ d[1]-this.delta[1], d[0]-this.delta[0]);
409
431
  } else {
410
432
  this.delta = d;
411
433
  }
@@ -453,15 +475,15 @@ Draggable.prototype = {
453
475
  }.bind(this));
454
476
 
455
477
  if(this.options.snap) {
456
- if(typeof this.options.snap == 'function') {
478
+ if(Object.isFunction(this.options.snap)) {
457
479
  p = this.options.snap(p[0],p[1],this);
458
480
  } else {
459
- if(this.options.snap instanceof Array) {
481
+ if(Object.isArray(this.options.snap)) {
460
482
  p = p.map( function(v, i) {
461
- return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
483
+ return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this))
462
484
  } else {
463
485
  p = p.map( function(v) {
464
- return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
486
+ return (v/this.options.snap).round()*this.options.snap }.bind(this))
465
487
  }
466
488
  }}
467
489
 
@@ -545,12 +567,13 @@ Draggable.prototype = {
545
567
  }
546
568
  return { top: T, left: L, width: W, height: H };
547
569
  }
548
- }
570
+ });
571
+
572
+ Draggable._dragging = { };
549
573
 
550
574
  /*--------------------------------------------------------------------------*/
551
575
 
552
- var SortableObserver = Class.create();
553
- SortableObserver.prototype = {
576
+ var SortableObserver = Class.create({
554
577
  initialize: function(element, observer) {
555
578
  this.element = $(element);
556
579
  this.observer = observer;
@@ -566,12 +589,12 @@ SortableObserver.prototype = {
566
589
  if(this.lastValue != Sortable.serialize(this.element))
567
590
  this.observer(this.element)
568
591
  }
569
- }
592
+ });
570
593
 
571
594
  var Sortable = {
572
595
  SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
573
596
 
574
- sortables: {},
597
+ sortables: { },
575
598
 
576
599
  _findRootElement: function(element) {
577
600
  while (element.tagName.toUpperCase() != "BODY") {
@@ -614,13 +637,20 @@ var Sortable = {
614
637
  delay: 0,
615
638
  hoverclass: null,
616
639
  ghosting: false,
640
+ quiet: false,
617
641
  scroll: false,
618
642
  scrollSensitivity: 20,
619
643
  scrollSpeed: 15,
620
644
  format: this.SERIALIZE_RULE,
645
+
646
+ // these take arrays of elements or ids and can be
647
+ // used for better initialization performance
648
+ elements: false,
649
+ handles: false,
650
+
621
651
  onChange: Prototype.emptyFunction,
622
652
  onUpdate: Prototype.emptyFunction
623
- }, arguments[1] || {});
653
+ }, arguments[1] || { });
624
654
 
625
655
  // clear any old sortable with same element
626
656
  this.destroy(element);
@@ -628,6 +658,7 @@ var Sortable = {
628
658
  // build options for the draggables
629
659
  var options_for_draggable = {
630
660
  revert: true,
661
+ quiet: options.quiet,
631
662
  scroll: options.scroll,
632
663
  scrollSpeed: options.scrollSpeed,
633
664
  scrollSensitivity: options.scrollSensitivity,
@@ -681,10 +712,9 @@ var Sortable = {
681
712
  options.droppables.push(element);
682
713
  }
683
714
 
684
- (this.findElements(element, options) || []).each( function(e) {
685
- // handles are per-draggable
686
- var handle = options.handle ?
687
- $(e).down('.'+options.handle,0) : e;
715
+ (options.elements || this.findElements(element, options) || []).each( function(e,i) {
716
+ var handle = options.handles ? $(options.handles[i]) :
717
+ (options.handle ? $(e).select('.' + options.handle)[0] : e);
688
718
  options.draggables.push(
689
719
  new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
690
720
  Droppables.add(e, options_for_droppable);
@@ -844,7 +874,7 @@ var Sortable = {
844
874
  only: sortableOptions.only,
845
875
  name: element.id,
846
876
  format: sortableOptions.format
847
- }, arguments[1] || {});
877
+ }, arguments[1] || { });
848
878
 
849
879
  var root = {
850
880
  id: null,
@@ -868,7 +898,7 @@ var Sortable = {
868
898
 
869
899
  sequence: function(element) {
870
900
  element = $(element);
871
- var options = Object.extend(this.options(element), arguments[1] || {});
901
+ var options = Object.extend(this.options(element), arguments[1] || { });
872
902
 
873
903
  return $(this.findElements(element, options) || []).map( function(item) {
874
904
  return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
@@ -877,9 +907,9 @@ var Sortable = {
877
907
 
878
908
  setSequence: function(element, new_sequence) {
879
909
  element = $(element);
880
- var options = Object.extend(this.options(element), arguments[2] || {});
910
+ var options = Object.extend(this.options(element), arguments[2] || { });
881
911
 
882
- var nodeMap = {};
912
+ var nodeMap = { };
883
913
  this.findElements(element, options).each( function(n) {
884
914
  if (n.id.match(options.format))
885
915
  nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
@@ -897,7 +927,7 @@ var Sortable = {
897
927
 
898
928
  serialize: function(element) {
899
929
  element = $(element);
900
- var options = Object.extend(Sortable.options(element), arguments[1] || {});
930
+ var options = Object.extend(Sortable.options(element), arguments[1] || { });
901
931
  var name = encodeURIComponent(
902
932
  (arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
903
933
 
@@ -921,7 +951,7 @@ Element.isParent = function(child, element) {
921
951
  return Element.isParent(child.parentNode, element);
922
952
  }
923
953
 
924
- Element.findChildren = function(element, only, recursive, tagName) {
954
+ Element.findChildren = function(element, only, recursive, tagName) {
925
955
  if(!element.hasChildNodes()) return null;
926
956
  tagName = tagName.toUpperCase();
927
957
  if(only) only = [only].flatten();
@@ -1,4 +1,6 @@
1
- // Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
1
+ // script.aculo.us effects.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)
2
4
  // Contributors:
3
5
  // Justin Palmer (http://encytemedia.com/)
4
6
  // Mark Pilgrim (http://diveintomark.org/)
@@ -11,17 +13,17 @@
11
13
  // returns self (or first argument) if not convertable
12
14
  String.prototype.parseColor = function() {
13
15
  var color = '#';
14
- if(this.slice(0,4) == 'rgb(') {
16
+ if (this.slice(0,4) == 'rgb(') {
15
17
  var cols = this.slice(4,this.length-1).split(',');
16
18
  var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
17
19
  } else {
18
- if(this.slice(0,1) == '#') {
19
- if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
20
- if(this.length==7) color = this.toLowerCase();
20
+ if (this.slice(0,1) == '#') {
21
+ if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
22
+ if (this.length==7) color = this.toLowerCase();
21
23
  }
22
24
  }
23
- return(color.length==7 ? color : (arguments[0] || this));
24
- }
25
+ return (color.length==7 ? color : (arguments[0] || this));
26
+ };
25
27
 
26
28
  /*--------------------------------------------------------------------------*/
27
29
 
@@ -30,7 +32,7 @@ Element.collectTextNodes = function(element) {
30
32
  return (node.nodeType==3 ? node.nodeValue :
31
33
  (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
32
34
  }).flatten().join('');
33
- }
35
+ };
34
36
 
35
37
  Element.collectTextNodesIgnoreClass = function(element, className) {
36
38
  return $A($(element).childNodes).collect( function(node) {
@@ -38,47 +40,18 @@ Element.collectTextNodesIgnoreClass = function(element, className) {
38
40
  ((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
39
41
  Element.collectTextNodesIgnoreClass(node, className) : ''));
40
42
  }).flatten().join('');
41
- }
43
+ };
42
44
 
43
45
  Element.setContentZoom = function(element, percent) {
44
46
  element = $(element);
45
47
  element.setStyle({fontSize: (percent/100) + 'em'});
46
- if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
48
+ if (Prototype.Browser.WebKit) window.scrollBy(0,0);
47
49
  return element;
48
- }
49
-
50
- Element.getOpacity = function(element){
51
- element = $(element);
52
- var opacity;
53
- if (opacity = element.getStyle('opacity'))
54
- return parseFloat(opacity);
55
- if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
56
- if(opacity[1]) return parseFloat(opacity[1]) / 100;
57
- return 1.0;
58
- }
50
+ };
59
51
 
60
- Element.setOpacity = function(element, value){
61
- element= $(element);
62
- if (value == 1){
63
- element.setStyle({ opacity:
64
- (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
65
- 0.999999 : 1.0 });
66
- if(/MSIE/.test(navigator.userAgent) && !window.opera)
67
- element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
68
- } else {
69
- if(value < 0.00001) value = 0;
70
- element.setStyle({opacity: value});
71
- if(/MSIE/.test(navigator.userAgent) && !window.opera)
72
- element.setStyle(
73
- { filter: element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
74
- 'alpha(opacity='+value*100+')' });
75
- }
76
- return element;
77
- }
78
-
79
- Element.getInlineOpacity = function(element){
52
+ Element.getInlineOpacity = function(element){
80
53
  return $(element).style.opacity || '';
81
- }
54
+ };
82
55
 
83
56
  Element.forceRerendering = function(element) {
84
57
  try {
@@ -91,31 +64,63 @@ Element.forceRerendering = function(element) {
91
64
 
92
65
  /*--------------------------------------------------------------------------*/
93
66
 
94
- Array.prototype.call = function() {
95
- var args = arguments;
96
- this.each(function(f){ f.apply(this, args) });
97
- }
98
-
99
- /*--------------------------------------------------------------------------*/
100
-
101
67
  var Effect = {
102
68
  _elementDoesNotExistError: {
103
69
  name: 'ElementDoesNotExistError',
104
70
  message: 'The specified DOM element does not exist, but is required for this effect to operate'
105
71
  },
72
+ Transitions: {
73
+ linear: Prototype.K,
74
+ sinoidal: function(pos) {
75
+ return (-Math.cos(pos*Math.PI)/2) + 0.5;
76
+ },
77
+ reverse: function(pos) {
78
+ return 1-pos;
79
+ },
80
+ flicker: function(pos) {
81
+ var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
82
+ return pos > 1 ? 1 : pos;
83
+ },
84
+ wobble: function(pos) {
85
+ return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
86
+ },
87
+ pulse: function(pos, pulses) {
88
+ pulses = pulses || 5;
89
+ return (
90
+ ((pos % (1/pulses)) * pulses).round() == 0 ?
91
+ ((pos * pulses * 2) - (pos * pulses * 2).floor()) :
92
+ 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor())
93
+ );
94
+ },
95
+ spring: function(pos) {
96
+ return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
97
+ },
98
+ none: function(pos) {
99
+ return 0;
100
+ },
101
+ full: function(pos) {
102
+ return 1;
103
+ }
104
+ },
105
+ DefaultOptions: {
106
+ duration: 1.0, // seconds
107
+ fps: 100, // 100= assume 66fps max.
108
+ sync: false, // true for combining
109
+ from: 0.0,
110
+ to: 1.0,
111
+ delay: 0.0,
112
+ queue: 'parallel'
113
+ },
106
114
  tagifyText: function(element) {
107
- if(typeof Builder == 'undefined')
108
- throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
109
-
110
115
  var tagifyStyle = 'position:relative';
111
- if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
116
+ if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
112
117
 
113
118
  element = $(element);
114
119
  $A(element.childNodes).each( function(child) {
115
- if(child.nodeType==3) {
120
+ if (child.nodeType==3) {
116
121
  child.nodeValue.toArray().each( function(character) {
117
122
  element.insertBefore(
118
- Builder.node('span',{style: tagifyStyle},
123
+ new Element('span', {style: tagifyStyle}).update(
119
124
  character == ' ' ? String.fromCharCode(160) : character),
120
125
  child);
121
126
  });
@@ -125,8 +130,8 @@ var Effect = {
125
130
  },
126
131
  multiple: function(element, effect) {
127
132
  var elements;
128
- if(((typeof element == 'object') ||
129
- (typeof element == 'function')) &&
133
+ if (((typeof element == 'object') ||
134
+ Object.isFunction(element)) &&
130
135
  (element.length))
131
136
  elements = element;
132
137
  else
@@ -135,7 +140,7 @@ var Effect = {
135
140
  var options = Object.extend({
136
141
  speed: 0.1,
137
142
  delay: 0.0
138
- }, arguments[2] || {});
143
+ }, arguments[2] || { });
139
144
  var masterDelay = options.delay;
140
145
 
141
146
  $A(elements).each( function(element, index) {
@@ -152,53 +157,20 @@ var Effect = {
152
157
  effect = (effect || 'appear').toLowerCase();
153
158
  var options = Object.extend({
154
159
  queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
155
- }, arguments[2] || {});
160
+ }, arguments[2] || { });
156
161
  Effect[element.visible() ?
157
162
  Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
158
163
  }
159
164
  };
160
165
 
161
- var Effect2 = Effect; // deprecated
162
-
163
- /* ------------- transitions ------------- */
164
-
165
- Effect.Transitions = {
166
- linear: Prototype.K,
167
- sinoidal: function(pos) {
168
- return (-Math.cos(pos*Math.PI)/2) + 0.5;
169
- },
170
- reverse: function(pos) {
171
- return 1-pos;
172
- },
173
- flicker: function(pos) {
174
- return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
175
- },
176
- wobble: function(pos) {
177
- return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
178
- },
179
- pulse: function(pos, pulses) {
180
- pulses = pulses || 5;
181
- return (
182
- Math.round((pos % (1/pulses)) * pulses) == 0 ?
183
- ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
184
- 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
185
- );
186
- },
187
- none: function(pos) {
188
- return 0;
189
- },
190
- full: function(pos) {
191
- return 1;
192
- }
193
- };
166
+ Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
194
167
 
195
168
  /* ------------- core effects ------------- */
196
169
 
197
- Effect.ScopedQueue = Class.create();
198
- Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
170
+ Effect.ScopedQueue = Class.create(Enumerable, {
199
171
  initialize: function() {
200
172
  this.effects = [];
201
- this.interval = null;
173
+ this.interval = null;
202
174
  },
203
175
  _each: function(iterator) {
204
176
  this.effects._each(iterator);
@@ -206,7 +178,7 @@ Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
206
178
  add: function(effect) {
207
179
  var timestamp = new Date().getTime();
208
180
 
209
- var position = (typeof effect.options.queue == 'string') ?
181
+ var position = Object.isString(effect.options.queue) ?
210
182
  effect.options.queue : effect.options.queue.position;
211
183
 
212
184
  switch(position) {
@@ -229,115 +201,111 @@ Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
229
201
  effect.startOn += timestamp;
230
202
  effect.finishOn += timestamp;
231
203
 
232
- if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
204
+ if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
233
205
  this.effects.push(effect);
234
206
 
235
- if(!this.interval)
236
- this.interval = setInterval(this.loop.bind(this), 40);
207
+ if (!this.interval)
208
+ this.interval = setInterval(this.loop.bind(this), 15);
237
209
  },
238
210
  remove: function(effect) {
239
211
  this.effects = this.effects.reject(function(e) { return e==effect });
240
- if(this.effects.length == 0) {
212
+ if (this.effects.length == 0) {
241
213
  clearInterval(this.interval);
242
214
  this.interval = null;
243
215
  }
244
216
  },
245
217
  loop: function() {
246
218
  var timePos = new Date().getTime();
247
- this.effects.invoke('loop', timePos);
219
+ for(var i=0, len=this.effects.length;i<len;i++)
220
+ this.effects[i] && this.effects[i].loop(timePos);
248
221
  }
249
222
  });
250
223
 
251
224
  Effect.Queues = {
252
225
  instances: $H(),
253
226
  get: function(queueName) {
254
- if(typeof queueName != 'string') return queueName;
227
+ if (!Object.isString(queueName)) return queueName;
255
228
 
256
- if(!this.instances[queueName])
257
- this.instances[queueName] = new Effect.ScopedQueue();
258
-
259
- return this.instances[queueName];
229
+ return this.instances.get(queueName) ||
230
+ this.instances.set(queueName, new Effect.ScopedQueue());
260
231
  }
261
- }
232
+ };
262
233
  Effect.Queue = Effect.Queues.get('global');
263
234
 
264
- Effect.DefaultOptions = {
265
- transition: Effect.Transitions.sinoidal,
266
- duration: 1.0, // seconds
267
- fps: 25.0, // max. 25fps due to Effect.Queue implementation
268
- sync: false, // true for combining
269
- from: 0.0,
270
- to: 1.0,
271
- delay: 0.0,
272
- queue: 'parallel'
273
- }
274
-
275
- Effect.Base = function() {};
276
- Effect.Base.prototype = {
235
+ Effect.Base = Class.create({
277
236
  position: null,
278
237
  start: function(options) {
279
- this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
238
+ function codeForEvent(options,eventName){
239
+ return (
240
+ (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
241
+ (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
242
+ );
243
+ }
244
+ if (options && options.transition === false) options.transition = Effect.Transitions.linear;
245
+ this.options = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
280
246
  this.currentFrame = 0;
281
247
  this.state = 'idle';
282
248
  this.startOn = this.options.delay*1000;
283
- this.finishOn = this.startOn + (this.options.duration*1000);
249
+ this.finishOn = this.startOn+(this.options.duration*1000);
250
+ this.fromToDelta = this.options.to-this.options.from;
251
+ this.totalTime = this.finishOn-this.startOn;
252
+ this.totalFrames = this.options.fps*this.options.duration;
253
+
254
+ eval('this.render = function(pos){ '+
255
+ 'if (this.state=="idle"){this.state="running";'+
256
+ codeForEvent(this.options,'beforeSetup')+
257
+ (this.setup ? 'this.setup();':'')+
258
+ codeForEvent(this.options,'afterSetup')+
259
+ '};if (this.state=="running"){'+
260
+ 'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
261
+ 'this.position=pos;'+
262
+ codeForEvent(this.options,'beforeUpdate')+
263
+ (this.update ? 'this.update(pos);':'')+
264
+ codeForEvent(this.options,'afterUpdate')+
265
+ '}}');
266
+
284
267
  this.event('beforeStart');
285
- if(!this.options.sync)
286
- Effect.Queues.get(typeof this.options.queue == 'string' ?
268
+ if (!this.options.sync)
269
+ Effect.Queues.get(Object.isString(this.options.queue) ?
287
270
  'global' : this.options.queue.scope).add(this);
288
271
  },
289
272
  loop: function(timePos) {
290
- if(timePos >= this.startOn) {
291
- if(timePos >= this.finishOn) {
273
+ if (timePos >= this.startOn) {
274
+ if (timePos >= this.finishOn) {
292
275
  this.render(1.0);
293
276
  this.cancel();
294
277
  this.event('beforeFinish');
295
- if(this.finish) this.finish();
278
+ if (this.finish) this.finish();
296
279
  this.event('afterFinish');
297
280
  return;
298
281
  }
299
- var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
300
- var frame = Math.round(pos * this.options.fps * this.options.duration);
301
- if(frame > this.currentFrame) {
282
+ var pos = (timePos - this.startOn) / this.totalTime,
283
+ frame = (pos * this.totalFrames).round();
284
+ if (frame > this.currentFrame) {
302
285
  this.render(pos);
303
286
  this.currentFrame = frame;
304
287
  }
305
288
  }
306
289
  },
307
- render: function(pos) {
308
- if(this.state == 'idle') {
309
- this.state = 'running';
310
- this.event('beforeSetup');
311
- if(this.setup) this.setup();
312
- this.event('afterSetup');
313
- }
314
- if(this.state == 'running') {
315
- if(this.options.transition) pos = this.options.transition(pos);
316
- pos *= (this.options.to-this.options.from);
317
- pos += this.options.from;
318
- this.position = pos;
319
- this.event('beforeUpdate');
320
- if(this.update) this.update(pos);
321
- this.event('afterUpdate');
322
- }
323
- },
324
290
  cancel: function() {
325
- if(!this.options.sync)
326
- Effect.Queues.get(typeof this.options.queue == 'string' ?
291
+ if (!this.options.sync)
292
+ Effect.Queues.get(Object.isString(this.options.queue) ?
327
293
  'global' : this.options.queue.scope).remove(this);
328
294
  this.state = 'finished';
329
295
  },
330
296
  event: function(eventName) {
331
- if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
332
- if(this.options[eventName]) this.options[eventName](this);
297
+ if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
298
+ if (this.options[eventName]) this.options[eventName](this);
333
299
  },
334
300
  inspect: function() {
335
- return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
301
+ var data = $H();
302
+ for(property in this)
303
+ if (!Object.isFunction(this[property])) data.set(property, this[property]);
304
+ return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
336
305
  }
337
- }
306
+ });
338
307
 
339
- Effect.Parallel = Class.create();
340
- Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
308
+ Effect.Parallel = Class.create(Effect.Base, {
341
309
  initialize: function(effects) {
342
310
  this.effects = effects || [];
343
311
  this.start(arguments[1]);
@@ -350,35 +318,45 @@ Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
350
318
  effect.render(1.0);
351
319
  effect.cancel();
352
320
  effect.event('beforeFinish');
353
- if(effect.finish) effect.finish(position);
321
+ if (effect.finish) effect.finish(position);
354
322
  effect.event('afterFinish');
355
323
  });
356
324
  }
357
325
  });
358
326
 
359
- Effect.Event = Class.create();
360
- Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
327
+ Effect.Tween = Class.create(Effect.Base, {
328
+ initialize: function(object, from, to) {
329
+ object = Object.isString(object) ? $(object) : object;
330
+ var args = $A(arguments), method = args.last(),
331
+ options = args.length == 5 ? args[3] : null;
332
+ this.method = Object.isFunction(method) ? method.bind(object) :
333
+ Object.isFunction(object[method]) ? object[method].bind(object) :
334
+ function(value) { object[method] = value };
335
+ this.start(Object.extend({ from: from, to: to }, options || { }));
336
+ },
337
+ update: function(position) {
338
+ this.method(position);
339
+ }
340
+ });
341
+
342
+ Effect.Event = Class.create(Effect.Base, {
361
343
  initialize: function() {
362
- var options = Object.extend({
363
- duration: 0
364
- }, arguments[0] || {});
365
- this.start(options);
344
+ this.start(Object.extend({ duration: 0 }, arguments[0] || { }));
366
345
  },
367
346
  update: Prototype.emptyFunction
368
347
  });
369
348
 
370
- Effect.Opacity = Class.create();
371
- Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
349
+ Effect.Opacity = Class.create(Effect.Base, {
372
350
  initialize: function(element) {
373
351
  this.element = $(element);
374
- if(!this.element) throw(Effect._elementDoesNotExistError);
352
+ if (!this.element) throw(Effect._elementDoesNotExistError);
375
353
  // make this work on IE on elements without 'layout'
376
- if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
354
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
377
355
  this.element.setStyle({zoom: 1});
378
356
  var options = Object.extend({
379
357
  from: this.element.getOpacity() || 0.0,
380
358
  to: 1.0
381
- }, arguments[1] || {});
359
+ }, arguments[1] || { });
382
360
  this.start(options);
383
361
  },
384
362
  update: function(position) {
@@ -386,36 +364,30 @@ Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
386
364
  }
387
365
  });
388
366
 
389
- Effect.Move = Class.create();
390
- Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
367
+ Effect.Move = Class.create(Effect.Base, {
391
368
  initialize: function(element) {
392
369
  this.element = $(element);
393
- if(!this.element) throw(Effect._elementDoesNotExistError);
370
+ if (!this.element) throw(Effect._elementDoesNotExistError);
394
371
  var options = Object.extend({
395
372
  x: 0,
396
373
  y: 0,
397
374
  mode: 'relative'
398
- }, arguments[1] || {});
375
+ }, arguments[1] || { });
399
376
  this.start(options);
400
377
  },
401
378
  setup: function() {
402
- // Bug in Opera: Opera returns the "real" position of a static element or
403
- // relative element that does not have top/left explicitly set.
404
- // ==> Always set top and left for position relative elements in your stylesheets
405
- // (to 0 if you do not need them)
406
379
  this.element.makePositioned();
407
380
  this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
408
381
  this.originalTop = parseFloat(this.element.getStyle('top') || '0');
409
- if(this.options.mode == 'absolute') {
410
- // absolute movement, so we need to calc deltaX and deltaY
382
+ if (this.options.mode == 'absolute') {
411
383
  this.options.x = this.options.x - this.originalLeft;
412
384
  this.options.y = this.options.y - this.originalTop;
413
385
  }
414
386
  },
415
387
  update: function(position) {
416
388
  this.element.setStyle({
417
- left: Math.round(this.options.x * position + this.originalLeft) + 'px',
418
- top: Math.round(this.options.y * position + this.originalTop) + 'px'
389
+ left: (this.options.x * position + this.originalLeft).round() + 'px',
390
+ top: (this.options.y * position + this.originalTop).round() + 'px'
419
391
  });
420
392
  }
421
393
  });
@@ -423,30 +395,29 @@ Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
423
395
  // for backwards compatibility
424
396
  Effect.MoveBy = function(element, toTop, toLeft) {
425
397
  return new Effect.Move(element,
426
- Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
398
+ Object.extend({ x: toLeft, y: toTop }, arguments[3] || { }));
427
399
  };
428
400
 
429
- Effect.Scale = Class.create();
430
- Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
401
+ Effect.Scale = Class.create(Effect.Base, {
431
402
  initialize: function(element, percent) {
432
403
  this.element = $(element);
433
- if(!this.element) throw(Effect._elementDoesNotExistError);
404
+ if (!this.element) throw(Effect._elementDoesNotExistError);
434
405
  var options = Object.extend({
435
406
  scaleX: true,
436
407
  scaleY: true,
437
408
  scaleContent: true,
438
409
  scaleFromCenter: false,
439
- scaleMode: 'box', // 'box' or 'contents' or {} with provided values
410
+ scaleMode: 'box', // 'box' or 'contents' or { } with provided values
440
411
  scaleFrom: 100.0,
441
412
  scaleTo: percent
442
- }, arguments[2] || {});
413
+ }, arguments[2] || { });
443
414
  this.start(options);
444
415
  },
445
416
  setup: function() {
446
417
  this.restoreAfterFinish = this.options.restoreAfterFinish || false;
447
418
  this.elementPositioning = this.element.getStyle('position');
448
419
 
449
- this.originalStyle = {};
420
+ this.originalStyle = { };
450
421
  ['top','left','width','height','fontSize'].each( function(k) {
451
422
  this.originalStyle[k] = this.element.style[k];
452
423
  }.bind(this));
@@ -456,7 +427,7 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
456
427
 
457
428
  var fontSize = this.element.getStyle('font-size') || '100%';
458
429
  ['em','px','%','pt'].each( function(fontSizeType) {
459
- if(fontSize.indexOf(fontSizeType)>0) {
430
+ if (fontSize.indexOf(fontSizeType)>0) {
460
431
  this.fontSize = parseFloat(fontSize);
461
432
  this.fontSizeType = fontSizeType;
462
433
  }
@@ -465,60 +436,61 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
465
436
  this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
466
437
 
467
438
  this.dims = null;
468
- if(this.options.scaleMode=='box')
439
+ if (this.options.scaleMode=='box')
469
440
  this.dims = [this.element.offsetHeight, this.element.offsetWidth];
470
- if(/^content/.test(this.options.scaleMode))
441
+ if (/^content/.test(this.options.scaleMode))
471
442
  this.dims = [this.element.scrollHeight, this.element.scrollWidth];
472
- if(!this.dims)
443
+ if (!this.dims)
473
444
  this.dims = [this.options.scaleMode.originalHeight,
474
445
  this.options.scaleMode.originalWidth];
475
446
  },
476
447
  update: function(position) {
477
448
  var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
478
- if(this.options.scaleContent && this.fontSize)
449
+ if (this.options.scaleContent && this.fontSize)
479
450
  this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
480
451
  this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
481
452
  },
482
453
  finish: function(position) {
483
- if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
454
+ if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
484
455
  },
485
456
  setDimensions: function(height, width) {
486
- var d = {};
487
- if(this.options.scaleX) d.width = Math.round(width) + 'px';
488
- if(this.options.scaleY) d.height = Math.round(height) + 'px';
489
- if(this.options.scaleFromCenter) {
457
+ var d = { };
458
+ if (this.options.scaleX) d.width = width.round() + 'px';
459
+ if (this.options.scaleY) d.height = height.round() + 'px';
460
+ if (this.options.scaleFromCenter) {
490
461
  var topd = (height - this.dims[0])/2;
491
462
  var leftd = (width - this.dims[1])/2;
492
- if(this.elementPositioning == 'absolute') {
493
- if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
494
- if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
463
+ if (this.elementPositioning == 'absolute') {
464
+ if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
465
+ if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
495
466
  } else {
496
- if(this.options.scaleY) d.top = -topd + 'px';
497
- if(this.options.scaleX) d.left = -leftd + 'px';
467
+ if (this.options.scaleY) d.top = -topd + 'px';
468
+ if (this.options.scaleX) d.left = -leftd + 'px';
498
469
  }
499
470
  }
500
471
  this.element.setStyle(d);
501
472
  }
502
473
  });
503
474
 
504
- Effect.Highlight = Class.create();
505
- Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
475
+ Effect.Highlight = Class.create(Effect.Base, {
506
476
  initialize: function(element) {
507
477
  this.element = $(element);
508
- if(!this.element) throw(Effect._elementDoesNotExistError);
509
- var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
478
+ if (!this.element) throw(Effect._elementDoesNotExistError);
479
+ var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { });
510
480
  this.start(options);
511
481
  },
512
482
  setup: function() {
513
483
  // Prevent executing on elements not in the layout flow
514
- if(this.element.getStyle('display')=='none') { this.cancel(); return; }
484
+ if (this.element.getStyle('display')=='none') { this.cancel(); return; }
515
485
  // Disable background image during the effect
516
- this.oldStyle = {
517
- backgroundImage: this.element.getStyle('background-image') };
518
- this.element.setStyle({backgroundImage: 'none'});
519
- if(!this.options.endcolor)
486
+ this.oldStyle = { };
487
+ if (!this.options.keepBackgroundImage) {
488
+ this.oldStyle.backgroundImage = this.element.getStyle('background-image');
489
+ this.element.setStyle({backgroundImage: 'none'});
490
+ }
491
+ if (!this.options.endcolor)
520
492
  this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
521
- if(!this.options.restorecolor)
493
+ if (!this.options.restorecolor)
522
494
  this.options.restorecolor = this.element.getStyle('background-color');
523
495
  // init color calculations
524
496
  this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
@@ -526,7 +498,7 @@ Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype),
526
498
  },
527
499
  update: function(position) {
528
500
  this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
529
- return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
501
+ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) });
530
502
  },
531
503
  finish: function() {
532
504
  this.element.setStyle(Object.extend(this.oldStyle, {
@@ -535,30 +507,21 @@ Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype),
535
507
  }
536
508
  });
537
509
 
538
- Effect.ScrollTo = Class.create();
539
- Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
540
- initialize: function(element) {
541
- this.element = $(element);
542
- this.start(arguments[1] || {});
543
- },
544
- setup: function() {
545
- Position.prepare();
546
- var offsets = Position.cumulativeOffset(this.element);
547
- if(this.options.offset) offsets[1] += this.options.offset;
548
- var max = window.innerHeight ?
549
- window.height - window.innerHeight :
550
- document.body.scrollHeight -
551
- (document.documentElement.clientHeight ?
552
- document.documentElement.clientHeight : document.body.clientHeight);
553
- this.scrollStart = Position.deltaY;
554
- this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
555
- },
556
- update: function(position) {
557
- Position.prepare();
558
- window.scrollTo(Position.deltaX,
559
- this.scrollStart + (position*this.delta));
560
- }
561
- });
510
+ Effect.ScrollTo = function(element) {
511
+ var options = arguments[1] || { },
512
+ scrollOffsets = document.viewport.getScrollOffsets(),
513
+ elementOffsets = $(element).cumulativeOffset(),
514
+ max = (window.height || document.body.scrollHeight) - document.viewport.getHeight();
515
+
516
+ if (options.offset) elementOffsets[1] += options.offset;
517
+
518
+ return new Effect.Tween(null,
519
+ scrollOffsets.top,
520
+ elementOffsets[1] > max ? max : elementOffsets[1],
521
+ options,
522
+ function(p){ scrollTo(scrollOffsets.left, p.round()) }
523
+ );
524
+ };
562
525
 
563
526
  /* ------------- combination effects ------------- */
564
527
 
@@ -566,14 +529,15 @@ Effect.Fade = function(element) {
566
529
  element = $(element);
567
530
  var oldOpacity = element.getInlineOpacity();
568
531
  var options = Object.extend({
569
- from: element.getOpacity() || 1.0,
570
- to: 0.0,
571
- afterFinishInternal: function(effect) {
572
- if(effect.options.to!=0) return;
573
- effect.element.hide().setStyle({opacity: oldOpacity});
574
- }}, arguments[1] || {});
532
+ from: element.getOpacity() || 1.0,
533
+ to: 0.0,
534
+ afterFinishInternal: function(effect) {
535
+ if (effect.options.to!=0) return;
536
+ effect.element.hide().setStyle({opacity: oldOpacity});
537
+ }
538
+ }, arguments[1] || { });
575
539
  return new Effect.Opacity(element,options);
576
- }
540
+ };
577
541
 
578
542
  Effect.Appear = function(element) {
579
543
  element = $(element);
@@ -586,9 +550,9 @@ Effect.Appear = function(element) {
586
550
  },
587
551
  beforeSetup: function(effect) {
588
552
  effect.element.setOpacity(effect.options.from).show();
589
- }}, arguments[1] || {});
553
+ }}, arguments[1] || { });
590
554
  return new Effect.Opacity(element,options);
591
- }
555
+ };
592
556
 
593
557
  Effect.Puff = function(element) {
594
558
  element = $(element);
@@ -610,9 +574,9 @@ Effect.Puff = function(element) {
610
574
  },
611
575
  afterFinishInternal: function(effect) {
612
576
  effect.effects[0].element.hide().setStyle(oldStyle); }
613
- }, arguments[1] || {})
577
+ }, arguments[1] || { })
614
578
  );
615
- }
579
+ };
616
580
 
617
581
  Effect.BlindUp = function(element) {
618
582
  element = $(element);
@@ -624,9 +588,9 @@ Effect.BlindUp = function(element) {
624
588
  afterFinishInternal: function(effect) {
625
589
  effect.element.hide().undoClipping();
626
590
  }
627
- }, arguments[1] || {})
591
+ }, arguments[1] || { })
628
592
  );
629
- }
593
+ };
630
594
 
631
595
  Effect.BlindDown = function(element) {
632
596
  element = $(element);
@@ -643,8 +607,8 @@ Effect.BlindDown = function(element) {
643
607
  afterFinishInternal: function(effect) {
644
608
  effect.element.undoClipping();
645
609
  }
646
- }, arguments[1] || {}));
647
- }
610
+ }, arguments[1] || { }));
611
+ };
648
612
 
649
613
  Effect.SwitchOff = function(element) {
650
614
  element = $(element);
@@ -665,8 +629,8 @@ Effect.SwitchOff = function(element) {
665
629
  }
666
630
  })
667
631
  }
668
- }, arguments[1] || {}));
669
- }
632
+ }, arguments[1] || { }));
633
+ };
670
634
 
671
635
  Effect.DropOut = function(element) {
672
636
  element = $(element);
@@ -685,29 +649,35 @@ Effect.DropOut = function(element) {
685
649
  afterFinishInternal: function(effect) {
686
650
  effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
687
651
  }
688
- }, arguments[1] || {}));
689
- }
652
+ }, arguments[1] || { }));
653
+ };
690
654
 
691
655
  Effect.Shake = function(element) {
692
656
  element = $(element);
657
+ var options = Object.extend({
658
+ distance: 20,
659
+ duration: 0.5
660
+ }, arguments[1] || {});
661
+ var distance = parseFloat(options.distance);
662
+ var split = parseFloat(options.duration) / 10.0;
693
663
  var oldStyle = {
694
664
  top: element.getStyle('top'),
695
665
  left: element.getStyle('left') };
696
- return new Effect.Move(element,
697
- { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
666
+ return new Effect.Move(element,
667
+ { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) {
698
668
  new Effect.Move(effect.element,
699
- { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
669
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
700
670
  new Effect.Move(effect.element,
701
- { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
671
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
702
672
  new Effect.Move(effect.element,
703
- { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
673
+ { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
704
674
  new Effect.Move(effect.element,
705
- { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
675
+ { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) {
706
676
  new Effect.Move(effect.element,
707
- { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
677
+ { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
708
678
  effect.element.undoPositioned().setStyle(oldStyle);
709
679
  }}) }}) }}) }}) }}) }});
710
- }
680
+ };
711
681
 
712
682
  Effect.SlideDown = function(element) {
713
683
  element = $(element).cleanWhitespace();
@@ -723,7 +693,7 @@ Effect.SlideDown = function(element) {
723
693
  afterSetup: function(effect) {
724
694
  effect.element.makePositioned();
725
695
  effect.element.down().makePositioned();
726
- if(window.opera) effect.element.setStyle({top: ''});
696
+ if (window.opera) effect.element.setStyle({top: ''});
727
697
  effect.element.makeClipping().setStyle({height: '0px'}).show();
728
698
  },
729
699
  afterUpdateInternal: function(effect) {
@@ -733,23 +703,25 @@ Effect.SlideDown = function(element) {
733
703
  afterFinishInternal: function(effect) {
734
704
  effect.element.undoClipping().undoPositioned();
735
705
  effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
736
- }, arguments[1] || {})
706
+ }, arguments[1] || { })
737
707
  );
738
- }
708
+ };
739
709
 
740
710
  Effect.SlideUp = function(element) {
741
711
  element = $(element).cleanWhitespace();
742
712
  var oldInnerBottom = element.down().getStyle('bottom');
713
+ var elementDimensions = element.getDimensions();
743
714
  return new Effect.Scale(element, window.opera ? 0 : 1,
744
715
  Object.extend({ scaleContent: false,
745
716
  scaleX: false,
746
717
  scaleMode: 'box',
747
718
  scaleFrom: 100,
719
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
748
720
  restoreAfterFinish: true,
749
- beforeStartInternal: function(effect) {
721
+ afterSetup: function(effect) {
750
722
  effect.element.makePositioned();
751
723
  effect.element.down().makePositioned();
752
- if(window.opera) effect.element.setStyle({top: ''});
724
+ if (window.opera) effect.element.setStyle({top: ''});
753
725
  effect.element.makeClipping().show();
754
726
  },
755
727
  afterUpdateInternal: function(effect) {
@@ -757,12 +729,12 @@ Effect.SlideUp = function(element) {
757
729
  (effect.dims[0] - effect.element.clientHeight) + 'px' });
758
730
  },
759
731
  afterFinishInternal: function(effect) {
760
- effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
761
- effect.element.down().undoPositioned();
732
+ effect.element.hide().undoClipping().undoPositioned();
733
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
762
734
  }
763
- }, arguments[1] || {})
735
+ }, arguments[1] || { })
764
736
  );
765
- }
737
+ };
766
738
 
767
739
  // Bug in opera makes the TD containing this element expand for a instance after finish
768
740
  Effect.Squish = function(element) {
@@ -775,7 +747,7 @@ Effect.Squish = function(element) {
775
747
  effect.element.hide().undoClipping();
776
748
  }
777
749
  });
778
- }
750
+ };
779
751
 
780
752
  Effect.Grow = function(element) {
781
753
  element = $(element);
@@ -784,7 +756,7 @@ Effect.Grow = function(element) {
784
756
  moveTransition: Effect.Transitions.sinoidal,
785
757
  scaleTransition: Effect.Transitions.sinoidal,
786
758
  opacityTransition: Effect.Transitions.full
787
- }, arguments[1] || {});
759
+ }, arguments[1] || { });
788
760
  var oldStyle = {
789
761
  top: element.style.top,
790
762
  left: element.style.left,
@@ -849,7 +821,7 @@ Effect.Grow = function(element) {
849
821
  )
850
822
  }
851
823
  });
852
- }
824
+ };
853
825
 
854
826
  Effect.Shrink = function(element) {
855
827
  element = $(element);
@@ -858,7 +830,7 @@ Effect.Shrink = function(element) {
858
830
  moveTransition: Effect.Transitions.sinoidal,
859
831
  scaleTransition: Effect.Transitions.sinoidal,
860
832
  opacityTransition: Effect.Transitions.none
861
- }, arguments[1] || {});
833
+ }, arguments[1] || { });
862
834
  var oldStyle = {
863
835
  top: element.style.top,
864
836
  left: element.style.left,
@@ -903,11 +875,11 @@ Effect.Shrink = function(element) {
903
875
  effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
904
876
  }, options)
905
877
  );
906
- }
878
+ };
907
879
 
908
880
  Effect.Pulsate = function(element) {
909
881
  element = $(element);
910
- var options = arguments[1] || {};
882
+ var options = arguments[1] || { };
911
883
  var oldOpacity = element.getInlineOpacity();
912
884
  var transition = options.transition || Effect.Transitions.sinoidal;
913
885
  var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
@@ -916,7 +888,7 @@ Effect.Pulsate = function(element) {
916
888
  Object.extend(Object.extend({ duration: 2.0, from: 0,
917
889
  afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
918
890
  }, options), {transition: reverser}));
919
- }
891
+ };
920
892
 
921
893
  Effect.Fold = function(element) {
922
894
  element = $(element);
@@ -936,37 +908,71 @@ Effect.Fold = function(element) {
936
908
  afterFinishInternal: function(effect) {
937
909
  effect.element.hide().undoClipping().setStyle(oldStyle);
938
910
  } });
939
- }}, arguments[1] || {}));
911
+ }}, arguments[1] || { }));
940
912
  };
941
913
 
942
- Effect.Morph = Class.create();
943
- Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
914
+ Effect.Morph = Class.create(Effect.Base, {
944
915
  initialize: function(element) {
945
916
  this.element = $(element);
946
- if(!this.element) throw(Effect._elementDoesNotExistError);
917
+ if (!this.element) throw(Effect._elementDoesNotExistError);
947
918
  var options = Object.extend({
948
- style: ''
949
- }, arguments[1] || {});
919
+ style: { }
920
+ }, arguments[1] || { });
921
+
922
+ if (!Object.isString(options.style)) this.style = $H(options.style);
923
+ else {
924
+ if (options.style.include(':'))
925
+ this.style = options.style.parseStyle();
926
+ else {
927
+ this.element.addClassName(options.style);
928
+ this.style = $H(this.element.getStyles());
929
+ this.element.removeClassName(options.style);
930
+ var css = this.element.getStyles();
931
+ this.style = this.style.reject(function(style) {
932
+ return style.value == css[style.key];
933
+ });
934
+ options.afterFinishInternal = function(effect) {
935
+ effect.element.addClassName(effect.options.style);
936
+ effect.transforms.each(function(transform) {
937
+ effect.element.style[transform.style] = '';
938
+ });
939
+ }
940
+ }
941
+ }
950
942
  this.start(options);
951
943
  },
944
+
952
945
  setup: function(){
953
946
  function parseColor(color){
954
- if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
947
+ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
955
948
  color = color.parseColor();
956
949
  return $R(0,2).map(function(i){
957
950
  return parseInt( color.slice(i*2+1,i*2+3), 16 )
958
951
  });
959
952
  }
960
- this.transforms = this.options.style.parseStyle().map(function(property){
961
- var originalValue = this.element.getStyle(property[0]);
962
- return $H({
963
- style: property[0],
964
- originalValue: property[1].unit=='color' ?
965
- parseColor(originalValue) : parseFloat(originalValue || 0),
966
- targetValue: property[1].unit=='color' ?
967
- parseColor(property[1].value) : property[1].value,
968
- unit: property[1].unit
969
- });
953
+ this.transforms = this.style.map(function(pair){
954
+ var property = pair[0], value = pair[1], unit = null;
955
+
956
+ if (value.parseColor('#zzzzzz') != '#zzzzzz') {
957
+ value = value.parseColor();
958
+ unit = 'color';
959
+ } else if (property == 'opacity') {
960
+ value = parseFloat(value);
961
+ if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
962
+ this.element.setStyle({zoom: 1});
963
+ } else if (Element.CSS_LENGTH.test(value)) {
964
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
965
+ value = parseFloat(components[1]);
966
+ unit = (components.length == 3) ? components[2] : null;
967
+ }
968
+
969
+ var originalValue = this.element.getStyle(property);
970
+ return {
971
+ style: property.camelize(),
972
+ originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
973
+ targetValue: unit=='color' ? parseColor(value) : value,
974
+ unit: unit
975
+ };
970
976
  }.bind(this)).reject(function(transform){
971
977
  return (
972
978
  (transform.originalValue == transform.targetValue) ||
@@ -978,32 +984,35 @@ Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
978
984
  });
979
985
  },
980
986
  update: function(position) {
981
- var style = $H(), value = null;
982
- this.transforms.each(function(transform){
983
- value = transform.unit=='color' ?
984
- $R(0,2).inject('#',function(m,v,i){
985
- return m+(Math.round(transform.originalValue[i]+
986
- (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) :
987
- transform.originalValue + Math.round(
988
- ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
989
- style[transform.style] = value;
990
- });
991
- this.element.setStyle(style);
987
+ var style = { }, transform, i = this.transforms.length;
988
+ while(i--)
989
+ style[(transform = this.transforms[i]).style] =
990
+ transform.unit=='color' ? '#'+
991
+ (Math.round(transform.originalValue[0]+
992
+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
993
+ (Math.round(transform.originalValue[1]+
994
+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
995
+ (Math.round(transform.originalValue[2]+
996
+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
997
+ (transform.originalValue +
998
+ (transform.targetValue - transform.originalValue) * position).toFixed(3) +
999
+ (transform.unit === null ? '' : transform.unit);
1000
+ this.element.setStyle(style, true);
992
1001
  }
993
1002
  });
994
1003
 
995
- Effect.Transform = Class.create();
996
- Object.extend(Effect.Transform.prototype, {
1004
+ Effect.Transform = Class.create({
997
1005
  initialize: function(tracks){
998
1006
  this.tracks = [];
999
- this.options = arguments[1] || {};
1007
+ this.options = arguments[1] || { };
1000
1008
  this.addTracks(tracks);
1001
1009
  },
1002
1010
  addTracks: function(tracks){
1003
1011
  tracks.each(function(track){
1004
- var data = $H(track).values().first();
1012
+ track = $H(track);
1013
+ var data = track.values().first();
1005
1014
  this.tracks.push($H({
1006
- ids: $H(track).keys().first(),
1015
+ ids: track.keys().first(),
1007
1016
  effect: Effect.Morph,
1008
1017
  options: { style: data }
1009
1018
  }));
@@ -1013,76 +1022,101 @@ Object.extend(Effect.Transform.prototype, {
1013
1022
  play: function(){
1014
1023
  return new Effect.Parallel(
1015
1024
  this.tracks.map(function(track){
1016
- var elements = [$(track.ids) || $$(track.ids)].flatten();
1017
- return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1025
+ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
1026
+ var elements = [$(ids) || $$(ids)].flatten();
1027
+ return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
1018
1028
  }).flatten(),
1019
1029
  this.options
1020
1030
  );
1021
1031
  }
1022
1032
  });
1023
1033
 
1024
- Element.CSS_PROPERTIES = ['azimuth', 'backgroundAttachment', 'backgroundColor', 'backgroundImage',
1025
- 'backgroundPosition', 'backgroundRepeat', 'borderBottomColor', 'borderBottomStyle',
1026
- 'borderBottomWidth', 'borderCollapse', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth',
1027
- 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderSpacing', 'borderTopColor',
1028
- 'borderTopStyle', 'borderTopWidth', 'bottom', 'captionSide', 'clear', 'clip', 'color', 'content',
1029
- 'counterIncrement', 'counterReset', 'cssFloat', 'cueAfter', 'cueBefore', 'cursor', 'direction',
1030
- 'display', 'elevation', 'emptyCells', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch',
1031
- 'fontStyle', 'fontVariant', 'fontWeight', 'height', 'left', 'letterSpacing', 'lineHeight',
1032
- 'listStyleImage', 'listStylePosition', 'listStyleType', 'marginBottom', 'marginLeft', 'marginRight',
1033
- 'marginTop', 'markerOffset', 'marks', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'opacity',
1034
- 'orphans', 'outlineColor', 'outlineOffset', 'outlineStyle', 'outlineWidth', 'overflowX', 'overflowY',
1035
- 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'page', 'pageBreakAfter', 'pageBreakBefore',
1036
- 'pageBreakInside', 'pauseAfter', 'pauseBefore', 'pitch', 'pitchRange', 'position', 'quotes',
1037
- 'richness', 'right', 'size', 'speakHeader', 'speakNumeral', 'speakPunctuation', 'speechRate', 'stress',
1038
- 'tableLayout', 'textAlign', 'textDecoration', 'textIndent', 'textShadow', 'textTransform', 'top',
1039
- 'unicodeBidi', 'verticalAlign', 'visibility', 'voiceFamily', 'volume', 'whiteSpace', 'widows',
1040
- 'width', 'wordSpacing', 'zIndex'];
1034
+ Element.CSS_PROPERTIES = $w(
1035
+ 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
1036
+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1037
+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1038
+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1039
+ 'fontSize fontWeight height left letterSpacing lineHeight ' +
1040
+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1041
+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1042
+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1043
+ 'right textIndent top width wordSpacing zIndex');
1041
1044
 
1042
1045
  Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1043
1046
 
1047
+ String.__parseStyleElement = document.createElement('div');
1044
1048
  String.prototype.parseStyle = function(){
1045
- var element = Element.extend(document.createElement('div'));
1046
- element.innerHTML = '<div style="' + this + '"></div>';
1047
- var style = element.down().style, styleRules = $H();
1049
+ var style, styleRules = $H();
1050
+ if (Prototype.Browser.WebKit)
1051
+ style = new Element('div',{style:this}).style;
1052
+ else {
1053
+ String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
1054
+ style = String.__parseStyleElement.childNodes[0].style;
1055
+ }
1048
1056
 
1049
1057
  Element.CSS_PROPERTIES.each(function(property){
1050
- if(style[property]) styleRules[property] = style[property];
1058
+ if (style[property]) styleRules.set(property, style[property]);
1051
1059
  });
1052
1060
 
1053
- var result = $H();
1054
-
1055
- styleRules.each(function(pair){
1056
- var property = pair[0], value = pair[1], unit = null;
1057
-
1058
- if(value.parseColor('#zzzzzz') != '#zzzzzz') {
1059
- value = value.parseColor();
1060
- unit = 'color';
1061
- } else if(Element.CSS_LENGTH.test(value))
1062
- var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
1063
- value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
1064
-
1065
- result[property.underscore().dasherize()] = $H({ value:value, unit:unit });
1066
- }.bind(this));
1067
-
1068
- return result;
1061
+ if (Prototype.Browser.IE && this.include('opacity'))
1062
+ styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
1063
+
1064
+ return styleRules;
1069
1065
  };
1070
1066
 
1071
- Element.morph = function(element, style) {
1072
- new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1073
- return element;
1067
+ if (document.defaultView && document.defaultView.getComputedStyle) {
1068
+ Element.getStyles = function(element) {
1069
+ var css = document.defaultView.getComputedStyle($(element), null);
1070
+ return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
1071
+ styles[property] = css[property];
1072
+ return styles;
1073
+ });
1074
+ };
1075
+ } else {
1076
+ Element.getStyles = function(element) {
1077
+ element = $(element);
1078
+ var css = element.currentStyle, styles;
1079
+ styles = Element.CSS_PROPERTIES.inject({ }, function(hash, property) {
1080
+ hash.set(property, css[property]);
1081
+ return hash;
1082
+ });
1083
+ if (!styles.opacity) styles.set('opacity', element.getOpacity());
1084
+ return styles;
1085
+ };
1074
1086
  };
1075
1087
 
1076
- ['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
1077
- 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
1078
- function(f) { Element.Methods[f] = Element[f]; }
1088
+ Effect.Methods = {
1089
+ morph: function(element, style) {
1090
+ element = $(element);
1091
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
1092
+ return element;
1093
+ },
1094
+ visualEffect: function(element, effect, options) {
1095
+ element = $(element)
1096
+ var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
1097
+ new Effect[klass](element, options);
1098
+ return element;
1099
+ },
1100
+ highlight: function(element, options) {
1101
+ element = $(element);
1102
+ new Effect.Highlight(element, options);
1103
+ return element;
1104
+ }
1105
+ };
1106
+
1107
+ $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
1108
+ 'pulsate shake puff squish switchOff dropOut').each(
1109
+ function(effect) {
1110
+ Effect.Methods[effect] = function(element, options){
1111
+ element = $(element);
1112
+ Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
1113
+ return element;
1114
+ }
1115
+ }
1079
1116
  );
1080
1117
 
1081
- Element.Methods.visualEffect = function(element, effect, options) {
1082
- s = effect.gsub(/_/, '-').camelize();
1083
- effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1084
- new Effect[effect_class](element, options);
1085
- return $(element);
1086
- };
1118
+ $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
1119
+ function(f) { Effect.Methods[f] = Element[f]; }
1120
+ );
1087
1121
 
1088
- Element.addMethods();
1122
+ Element.addMethods(Effect.Methods);