rails 1.2.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rails might be problematic. Click here for more details.

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