rails 1.1.6 → 1.2.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 (104) hide show
  1. data/CHANGELOG +267 -2
  2. data/MIT-LICENSE +1 -1
  3. data/README +62 -63
  4. data/Rakefile +26 -15
  5. data/bin/process/inspector +3 -0
  6. data/configs/databases/frontbase.yml +28 -0
  7. data/configs/databases/mysql.yml +3 -2
  8. data/configs/databases/oracle.yml +10 -1
  9. data/configs/databases/sqlite3.yml +3 -0
  10. data/configs/lighttpd.conf +1 -0
  11. data/configs/routes.rb +1 -0
  12. data/environments/boot.rb +4 -3
  13. data/environments/environment.rb +9 -2
  14. data/environments/production.rb +1 -1
  15. data/helpers/application.rb +5 -2
  16. data/html/404.html +27 -5
  17. data/html/500.html +27 -5
  18. data/html/javascripts/controls.js +41 -23
  19. data/html/javascripts/dragdrop.js +105 -76
  20. data/html/javascripts/effects.js +293 -163
  21. data/html/javascripts/prototype.js +897 -389
  22. data/lib/breakpoint.rb +31 -1
  23. data/lib/breakpoint_client.rb +5 -5
  24. data/lib/code_statistics.rb +1 -1
  25. data/lib/commands/performance/profiler.rb +25 -9
  26. data/lib/commands/plugin.rb +69 -23
  27. data/lib/commands/process/inspector.rb +68 -0
  28. data/lib/commands/process/reaper.rb +88 -69
  29. data/lib/commands/process/spawner.rb +148 -33
  30. data/lib/commands/runner.rb +27 -6
  31. data/lib/commands/server.rb +18 -9
  32. data/lib/commands/servers/base.rb +19 -0
  33. data/lib/commands/servers/lighttpd.rb +20 -18
  34. data/lib/commands/servers/mongrel.rb +65 -0
  35. data/lib/console_sandbox.rb +2 -2
  36. data/lib/dispatcher.rb +67 -11
  37. data/lib/fcgi_handler.rb +52 -34
  38. data/lib/initializer.rb +190 -111
  39. data/lib/rails/version.rb +2 -2
  40. data/lib/rails_generator/base.rb +82 -24
  41. data/lib/rails_generator/commands.rb +87 -25
  42. data/lib/rails_generator/generated_attribute.rb +42 -0
  43. data/lib/rails_generator/generators/applications/app/app_generator.rb +13 -10
  44. data/lib/rails_generator/generators/components/controller/controller_generator.rb +1 -2
  45. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +10 -8
  46. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +1 -1
  47. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +4 -4
  48. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +1 -1
  49. data/lib/rails_generator/generators/components/migration/templates/migration.rb +1 -1
  50. data/lib/rails_generator/generators/components/model/USAGE +19 -12
  51. data/lib/rails_generator/generators/components/model/model_generator.rb +4 -0
  52. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +8 -2
  53. data/lib/rails_generator/generators/components/model/templates/migration.rb +3 -1
  54. data/lib/rails_generator/generators/components/observer/USAGE +15 -0
  55. data/lib/rails_generator/generators/components/observer/observer_generator.rb +16 -0
  56. data/lib/rails_generator/generators/components/observer/templates/observer.rb +2 -0
  57. data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +10 -0
  58. data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +4 -0
  59. data/lib/rails_generator/generators/components/plugin/templates/uninstall.rb +1 -0
  60. data/lib/rails_generator/generators/components/resource/resource_generator.rb +76 -0
  61. data/lib/rails_generator/generators/components/resource/templates/USAGE +18 -0
  62. data/lib/rails_generator/generators/components/resource/templates/controller.rb +2 -0
  63. data/lib/rails_generator/generators/components/resource/templates/fixtures.yml +11 -0
  64. data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +20 -0
  65. data/lib/rails_generator/generators/components/resource/templates/helper.rb +2 -0
  66. data/lib/rails_generator/generators/components/resource/templates/migration.rb +13 -0
  67. data/lib/rails_generator/generators/components/resource/templates/model.rb +2 -0
  68. data/lib/rails_generator/generators/components/resource/templates/unit_test.rb +10 -0
  69. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +10 -1
  70. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +11 -7
  71. data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +5 -1
  72. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +2 -2
  73. data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +1 -1
  74. data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +2 -2
  75. data/lib/rails_generator/generators/components/scaffold_resource/USAGE +29 -0
  76. data/lib/rails_generator/generators/components/scaffold_resource/scaffold_resource_generator.rb +92 -0
  77. data/lib/rails_generator/generators/components/scaffold_resource/templates/controller.rb +79 -0
  78. data/lib/rails_generator/generators/components/scaffold_resource/templates/fixtures.yml +11 -0
  79. data/lib/rails_generator/generators/components/scaffold_resource/templates/functional_test.rb +57 -0
  80. data/lib/rails_generator/generators/components/scaffold_resource/templates/helper.rb +2 -0
  81. data/lib/rails_generator/generators/components/scaffold_resource/templates/layout.rhtml +17 -0
  82. data/lib/rails_generator/generators/components/scaffold_resource/templates/migration.rb +13 -0
  83. data/lib/rails_generator/generators/components/scaffold_resource/templates/model.rb +2 -0
  84. data/lib/rails_generator/generators/components/scaffold_resource/templates/style.css +74 -0
  85. data/lib/rails_generator/generators/components/scaffold_resource/templates/unit_test.rb +10 -0
  86. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_edit.rhtml +19 -0
  87. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_index.rhtml +24 -0
  88. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_new.rhtml +18 -0
  89. data/lib/rails_generator/generators/components/scaffold_resource/templates/view_show.rhtml +10 -0
  90. data/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb +7 -1
  91. data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +5 -4
  92. data/lib/rails_generator/lookup.rb +1 -2
  93. data/lib/rails_generator/options.rb +6 -3
  94. data/lib/tasks/databases.rake +46 -20
  95. data/lib/tasks/documentation.rake +1 -0
  96. data/lib/tasks/framework.rake +1 -3
  97. data/lib/tasks/pre_namespace_aliases.rake +34 -27
  98. data/lib/tasks/rails.rb +2 -2
  99. data/lib/tasks/statistics.rake +6 -5
  100. data/lib/tasks/testing.rake +28 -13
  101. data/lib/tasks/tmp.rake +8 -1
  102. data/lib/test_help.rb +3 -2
  103. data/lib/webrick_server.rb +6 -8
  104. metadata +50 -9
@@ -1,9 +1,11 @@
1
- // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
- // (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
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)
3
3
  //
4
- // See scriptaculous.js for full license.
4
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
5
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
5
6
 
6
- /*--------------------------------------------------------------------------*/
7
+ if(typeof Effect == 'undefined')
8
+ throw("dragdrop.js requires including script.aculo.us' effects.js library");
7
9
 
8
10
  var Droppables = {
9
11
  drops: [],
@@ -145,8 +147,16 @@ var Draggables = {
145
147
  },
146
148
 
147
149
  activate: function(draggable) {
148
- window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
149
- this.activeDraggable = draggable;
150
+ if(draggable.options.delay) {
151
+ this._timeout = setTimeout(function() {
152
+ Draggables._timeout = null;
153
+ window.focus();
154
+ Draggables.activeDraggable = draggable;
155
+ }.bind(this), draggable.options.delay);
156
+ } else {
157
+ window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
158
+ this.activeDraggable = draggable;
159
+ }
150
160
  },
151
161
 
152
162
  deactivate: function() {
@@ -160,10 +170,15 @@ var Draggables = {
160
170
  // the same coordinates, prevent needless redrawing (moz bug?)
161
171
  if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
162
172
  this._lastPointer = pointer;
173
+
163
174
  this.activeDraggable.updateDrag(event, pointer);
164
175
  },
165
176
 
166
177
  endDrag: function(event) {
178
+ if(this._timeout) {
179
+ clearTimeout(this._timeout);
180
+ this._timeout = null;
181
+ }
167
182
  if(!this.activeDraggable) return;
168
183
  this._lastPointer = null;
169
184
  this.activeDraggable.endDrag(event);
@@ -190,6 +205,7 @@ var Draggables = {
190
205
  this.observers.each( function(o) {
191
206
  if(o[eventName]) o[eventName](eventName, draggable, event);
192
207
  });
208
+ if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
193
209
  },
194
210
 
195
211
  _cacheObserverCallbacks: function() {
@@ -204,39 +220,59 @@ var Draggables = {
204
220
  /*--------------------------------------------------------------------------*/
205
221
 
206
222
  var Draggable = Class.create();
223
+ Draggable._dragging = {};
224
+
207
225
  Draggable.prototype = {
208
226
  initialize: function(element) {
209
- var options = Object.extend({
227
+ var defaults = {
210
228
  handle: false,
211
- starteffect: function(element) {
212
- new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
213
- },
214
229
  reverteffect: function(element, top_offset, left_offset) {
215
230
  var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
216
- element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
231
+ new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
232
+ queue: {scope:'_draggable', position:'end'}
233
+ });
217
234
  },
218
- endeffect: function(element) {
219
- new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
235
+ endeffect: function(element) {
236
+ var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
237
+ new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity,
238
+ queue: {scope:'_draggable', position:'end'},
239
+ afterFinish: function(){
240
+ Draggable._dragging[element] = false
241
+ }
242
+ });
220
243
  },
221
244
  zindex: 1000,
222
245
  revert: false,
223
246
  scroll: false,
224
247
  scrollSensitivity: 20,
225
248
  scrollSpeed: 15,
226
- snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
227
- }, arguments[1] || {});
249
+ snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] }
250
+ delay: 0
251
+ };
252
+
253
+ if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
254
+ Object.extend(defaults, {
255
+ starteffect: function(element) {
256
+ element._opacity = Element.getOpacity(element);
257
+ Draggable._dragging[element] = true;
258
+ new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7});
259
+ }
260
+ });
261
+
262
+ var options = Object.extend(defaults, arguments[1] || {});
228
263
 
229
264
  this.element = $(element);
230
265
 
231
- if(options.handle && (typeof options.handle == 'string')) {
232
- var h = Element.childrenWithClassName(this.element, options.handle, true);
233
- if(h.length>0) this.handle = h[0];
234
- }
266
+ if(options.handle && (typeof options.handle == 'string'))
267
+ this.handle = this.element.down('.'+options.handle, 0);
268
+
235
269
  if(!this.handle) this.handle = $(options.handle);
236
270
  if(!this.handle) this.handle = this.element;
237
271
 
238
- if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML)
272
+ if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
239
273
  options.scroll = $(options.scroll);
274
+ this._isScrollChild = Element.childOf(this.element, options.scroll);
275
+ }
240
276
 
241
277
  Element.makePositioned(this.element); // fix IE
242
278
 
@@ -262,6 +298,8 @@ Draggable.prototype = {
262
298
  },
263
299
 
264
300
  initDrag: function(event) {
301
+ if(typeof Draggable._dragging[this.element] != 'undefined' &&
302
+ Draggable._dragging[this.element]) return;
265
303
  if(Event.isLeftClick(event)) {
266
304
  // abort on form elements, fixes a Firefox issue
267
305
  var src = Event.element(event);
@@ -272,11 +310,6 @@ Draggable.prototype = {
272
310
  src.tagName=='BUTTON' ||
273
311
  src.tagName=='TEXTAREA')) return;
274
312
 
275
- if(this.element._revert) {
276
- this.element._revert.cancel();
277
- this.element._revert = null;
278
- }
279
-
280
313
  var pointer = [Event.pointerX(event), Event.pointerY(event)];
281
314
  var pos = Position.cumulativeOffset(this.element);
282
315
  this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
@@ -312,6 +345,7 @@ Draggable.prototype = {
312
345
  }
313
346
 
314
347
  Draggables.notify('onStart', this, event);
348
+
315
349
  if(this.options.starteffect) this.options.starteffect(this.element);
316
350
  },
317
351
 
@@ -320,6 +354,7 @@ Draggable.prototype = {
320
354
  Position.prepare();
321
355
  Droppables.show(pointer, this.element);
322
356
  Draggables.notify('onDrag', this, event);
357
+
323
358
  this.draw(pointer);
324
359
  if(this.options.change) this.options.change(this);
325
360
 
@@ -331,8 +366,8 @@ Draggable.prototype = {
331
366
  with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
332
367
  } else {
333
368
  p = Position.page(this.options.scroll);
334
- p[0] += this.options.scroll.scrollLeft;
335
- p[1] += this.options.scroll.scrollTop;
369
+ p[0] += this.options.scroll.scrollLeft + Position.deltaX;
370
+ p[1] += this.options.scroll.scrollTop + Position.deltaY;
336
371
  p.push(p[0]+this.options.scroll.offsetWidth);
337
372
  p.push(p[1]+this.options.scroll.offsetHeight);
338
373
  }
@@ -378,7 +413,7 @@ Draggable.prototype = {
378
413
 
379
414
  if(this.options.endeffect)
380
415
  this.options.endeffect(this.element);
381
-
416
+
382
417
  Draggables.deactivate(this);
383
418
  Droppables.reset();
384
419
  },
@@ -398,10 +433,15 @@ Draggable.prototype = {
398
433
 
399
434
  draw: function(point) {
400
435
  var pos = Position.cumulativeOffset(this.element);
436
+ if(this.options.ghosting) {
437
+ var r = Position.realOffset(this.element);
438
+ pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
439
+ }
440
+
401
441
  var d = this.currentDelta();
402
442
  pos[0] -= d[0]; pos[1] -= d[1];
403
443
 
404
- if(this.options.scroll && (this.options.scroll != window)) {
444
+ if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
405
445
  pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
406
446
  pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
407
447
  }
@@ -412,7 +452,7 @@ Draggable.prototype = {
412
452
 
413
453
  if(this.options.snap) {
414
454
  if(typeof this.options.snap == 'function') {
415
- p = this.options.snap(p[0],p[1]);
455
+ p = this.options.snap(p[0],p[1],this);
416
456
  } else {
417
457
  if(this.options.snap instanceof Array) {
418
458
  p = p.map( function(v, i) {
@@ -428,6 +468,7 @@ Draggable.prototype = {
428
468
  style.left = p[0] + "px";
429
469
  if((!this.options.constraint) || (this.options.constraint=='vertical'))
430
470
  style.top = p[1] + "px";
471
+
431
472
  if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
432
473
  },
433
474
 
@@ -440,6 +481,7 @@ Draggable.prototype = {
440
481
  },
441
482
 
442
483
  startScrolling: function(speed) {
484
+ if(!(speed[0] || speed[1])) return;
443
485
  this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
444
486
  this.lastScrolled = new Date();
445
487
  this.scrollInterval = setInterval(this.scroll.bind(this), 10);
@@ -464,14 +506,16 @@ Draggable.prototype = {
464
506
  Position.prepare();
465
507
  Droppables.show(Draggables._lastPointer, this.element);
466
508
  Draggables.notify('onDrag', this);
467
- Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
468
- Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
469
- Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
470
- if (Draggables._lastScrollPointer[0] < 0)
471
- Draggables._lastScrollPointer[0] = 0;
472
- if (Draggables._lastScrollPointer[1] < 0)
473
- Draggables._lastScrollPointer[1] = 0;
474
- this.draw(Draggables._lastScrollPointer);
509
+ if (this._isScrollChild) {
510
+ Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
511
+ Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
512
+ Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
513
+ if (Draggables._lastScrollPointer[0] < 0)
514
+ Draggables._lastScrollPointer[0] = 0;
515
+ if (Draggables._lastScrollPointer[1] < 0)
516
+ Draggables._lastScrollPointer[1] = 0;
517
+ this.draw(Draggables._lastScrollPointer);
518
+ }
475
519
 
476
520
  if(this.options.change) this.options.change(this);
477
521
  },
@@ -523,6 +567,8 @@ SortableObserver.prototype = {
523
567
  }
524
568
 
525
569
  var Sortable = {
570
+ SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/,
571
+
526
572
  sortables: {},
527
573
 
528
574
  _findRootElement: function(element) {
@@ -563,12 +609,13 @@ var Sortable = {
563
609
  containment: element, // also takes array of elements (or id's); or false
564
610
  handle: false, // or a CSS class
565
611
  only: false,
612
+ delay: 0,
566
613
  hoverclass: null,
567
614
  ghosting: false,
568
615
  scroll: false,
569
616
  scrollSensitivity: 20,
570
617
  scrollSpeed: 15,
571
- format: /^[^_]*_(.*)$/,
618
+ format: this.SERIALIZE_RULE,
572
619
  onChange: Prototype.emptyFunction,
573
620
  onUpdate: Prototype.emptyFunction
574
621
  }, arguments[1] || {});
@@ -582,6 +629,7 @@ var Sortable = {
582
629
  scroll: options.scroll,
583
630
  scrollSpeed: options.scrollSpeed,
584
631
  scrollSensitivity: options.scrollSensitivity,
632
+ delay: options.delay,
585
633
  ghosting: options.ghosting,
586
634
  constraint: options.constraint,
587
635
  handle: options.handle };
@@ -610,7 +658,6 @@ var Sortable = {
610
658
  tree: options.tree,
611
659
  hoverclass: options.hoverclass,
612
660
  onHover: Sortable.onHover
613
- //greedy: !options.dropOnEmpty
614
661
  }
615
662
 
616
663
  var options_for_tree = {
@@ -635,7 +682,7 @@ var Sortable = {
635
682
  (this.findElements(element, options) || []).each( function(e) {
636
683
  // handles are per-draggable
637
684
  var handle = options.handle ?
638
- Element.childrenWithClassName(e, options.handle)[0] : e;
685
+ $(e).down('.'+options.handle,0) : e;
639
686
  options.draggables.push(
640
687
  new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
641
688
  Droppables.add(e, options_for_droppable);
@@ -706,7 +753,7 @@ var Sortable = {
706
753
  if(!Element.isParent(dropon, element)) {
707
754
  var index;
708
755
 
709
- var children = Sortable.findElements(dropon, {tag: droponOptions.tag});
756
+ var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only});
710
757
  var child = null;
711
758
 
712
759
  if(children) {
@@ -733,7 +780,7 @@ var Sortable = {
733
780
  },
734
781
 
735
782
  unmark: function() {
736
- if(Sortable._marker) Element.hide(Sortable._marker);
783
+ if(Sortable._marker) Sortable._marker.hide();
737
784
  },
738
785
 
739
786
  mark: function(dropon, position) {
@@ -742,23 +789,21 @@ var Sortable = {
742
789
  if(sortable && !sortable.ghosting) return;
743
790
 
744
791
  if(!Sortable._marker) {
745
- Sortable._marker = $('dropmarker') || document.createElement('DIV');
746
- Element.hide(Sortable._marker);
747
- Element.addClassName(Sortable._marker, 'dropmarker');
748
- Sortable._marker.style.position = 'absolute';
792
+ Sortable._marker =
793
+ ($('dropmarker') || Element.extend(document.createElement('DIV'))).
794
+ hide().addClassName('dropmarker').setStyle({position:'absolute'});
749
795
  document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
750
796
  }
751
797
  var offsets = Position.cumulativeOffset(dropon);
752
- Sortable._marker.style.left = offsets[0] + 'px';
753
- Sortable._marker.style.top = offsets[1] + 'px';
798
+ Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
754
799
 
755
800
  if(position=='after')
756
801
  if(sortable.overlap == 'horizontal')
757
- Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
802
+ Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'});
758
803
  else
759
- Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
804
+ Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'});
760
805
 
761
- Element.show(Sortable._marker);
806
+ Sortable._marker.show();
762
807
  },
763
808
 
764
809
  _tree: function(element, options, parent) {
@@ -773,9 +818,9 @@ var Sortable = {
773
818
  id: encodeURIComponent(match ? match[1] : null),
774
819
  element: element,
775
820
  parent: parent,
776
- children: new Array,
821
+ children: [],
777
822
  position: parent.children.length,
778
- container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase())
823
+ container: $(children[i]).down(options.treeTag)
779
824
  }
780
825
 
781
826
  /* Get the element containing the children and recurse over it */
@@ -788,17 +833,6 @@ var Sortable = {
788
833
  return parent;
789
834
  },
790
835
 
791
- /* Finds the first element of the given tag type within a parent element.
792
- Used for finding the first LI[ST] within a L[IST]I[TEM].*/
793
- _findChildrenElement: function (element, containerTag) {
794
- if (element && element.hasChildNodes)
795
- for (var i = 0; i < element.childNodes.length; ++i)
796
- if (element.childNodes[i].tagName == containerTag)
797
- return element.childNodes[i];
798
-
799
- return null;
800
- },
801
-
802
836
  tree: function(element) {
803
837
  element = $(element);
804
838
  var sortableOptions = this.options(element);
@@ -813,12 +847,12 @@ var Sortable = {
813
847
  var root = {
814
848
  id: null,
815
849
  parent: null,
816
- children: new Array,
850
+ children: [],
817
851
  container: element,
818
852
  position: 0
819
853
  }
820
854
 
821
- return Sortable._tree (element, options, root);
855
+ return Sortable._tree(element, options, root);
822
856
  },
823
857
 
824
858
  /* Construct a [i] index for a particular node */
@@ -867,7 +901,7 @@ var Sortable = {
867
901
 
868
902
  if (options.tree) {
869
903
  return Sortable.tree(element, arguments[1]).children.map( function (item) {
870
- return [name + Sortable._constructIndex(item) + "=" +
904
+ return [name + Sortable._constructIndex(item) + "[id]=" +
871
905
  encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
872
906
  }).flatten().join('&');
873
907
  } else {
@@ -878,12 +912,10 @@ var Sortable = {
878
912
  }
879
913
  }
880
914
 
881
- /* Returns true if child is contained within element */
915
+ // Returns true if child is contained within element
882
916
  Element.isParent = function(child, element) {
883
917
  if (!child.parentNode || child == element) return false;
884
-
885
918
  if (child.parentNode == element) return true;
886
-
887
919
  return Element.isParent(child.parentNode, element);
888
920
  }
889
921
 
@@ -906,8 +938,5 @@ Element.findChildren = function(element, only, recursive, tagName) {
906
938
  }
907
939
 
908
940
  Element.offsetSize = function (element, type) {
909
- if (type == 'vertical' || type == 'height')
910
- return element.offsetHeight;
911
- else
912
- return element.offsetWidth;
913
- }
941
+ return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
942
+ }
@@ -1,15 +1,16 @@
1
- // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
1
+ // Copyright (c) 2005, 2006 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/)
5
5
  // Martin Bialasinki
6
6
  //
7
- // See scriptaculous.js for full license.
7
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
8
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
8
9
 
9
10
  // converts rgb() and #xxx to #xxxxxx format,
10
11
  // returns self (or first argument) if not convertable
11
12
  String.prototype.parseColor = function() {
12
- var color = '#';
13
+ var color = '#';
13
14
  if(this.slice(0,4) == 'rgb(') {
14
15
  var cols = this.slice(4,this.length-1).split(',');
15
16
  var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
@@ -41,15 +42,17 @@ Element.collectTextNodesIgnoreClass = function(element, className) {
41
42
 
42
43
  Element.setContentZoom = function(element, percent) {
43
44
  element = $(element);
44
- Element.setStyle(element, {fontSize: (percent/100) + 'em'});
45
+ element.setStyle({fontSize: (percent/100) + 'em'});
45
46
  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
47
+ return element;
46
48
  }
47
49
 
48
- Element.getOpacity = function(element){
50
+ Element.getOpacity = function(element){
51
+ element = $(element);
49
52
  var opacity;
50
- if (opacity = Element.getStyle(element, 'opacity'))
53
+ if (opacity = element.getStyle('opacity'))
51
54
  return parseFloat(opacity);
52
- if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
55
+ if (opacity = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
53
56
  if(opacity[1]) return parseFloat(opacity[1]) / 100;
54
57
  return 1.0;
55
58
  }
@@ -57,34 +60,26 @@ Element.getOpacity = function(element){
57
60
  Element.setOpacity = function(element, value){
58
61
  element= $(element);
59
62
  if (value == 1){
60
- Element.setStyle(element, { opacity:
63
+ element.setStyle({ opacity:
61
64
  (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
62
- 0.999999 : null });
63
- if(/MSIE/.test(navigator.userAgent))
64
- Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
65
+ 0.999999 : 1.0 });
66
+ if(/MSIE/.test(navigator.userAgent) && !window.opera)
67
+ element.setStyle({filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
65
68
  } else {
66
69
  if(value < 0.00001) value = 0;
67
- Element.setStyle(element, {opacity: value});
68
- if(/MSIE/.test(navigator.userAgent))
69
- Element.setStyle(element,
70
- { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
71
- 'alpha(opacity='+value*100+')' });
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+')' });
72
75
  }
76
+ return element;
73
77
  }
74
78
 
75
79
  Element.getInlineOpacity = function(element){
76
80
  return $(element).style.opacity || '';
77
81
  }
78
82
 
79
- Element.childrenWithClassName = function(element, className, findFirst) {
80
- var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
81
- var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) {
82
- return (c.className && c.className.match(classNameRegExp));
83
- });
84
- if(!results) results = [];
85
- return results;
86
- }
87
-
88
83
  Element.forceRerendering = function(element) {
89
84
  try {
90
85
  element = $(element);
@@ -104,9 +99,17 @@ Array.prototype.call = function() {
104
99
  /*--------------------------------------------------------------------------*/
105
100
 
106
101
  var Effect = {
102
+ _elementDoesNotExistError: {
103
+ name: 'ElementDoesNotExistError',
104
+ message: 'The specified DOM element does not exist, but is required for this effect to operate'
105
+ },
107
106
  tagifyText: function(element) {
107
+ if(typeof Builder == 'undefined')
108
+ throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
109
+
108
110
  var tagifyStyle = 'position:relative';
109
- if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
111
+ if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
112
+
110
113
  element = $(element);
111
114
  $A(element.childNodes).each( function(child) {
112
115
  if(child.nodeType==3) {
@@ -159,33 +162,35 @@ var Effect2 = Effect; // deprecated
159
162
 
160
163
  /* ------------- transitions ------------- */
161
164
 
162
- Effect.Transitions = {}
163
-
164
- Effect.Transitions.linear = function(pos) {
165
- return pos;
166
- }
167
- Effect.Transitions.sinoidal = function(pos) {
168
- return (-Math.cos(pos*Math.PI)/2) + 0.5;
169
- }
170
- Effect.Transitions.reverse = function(pos) {
171
- return 1-pos;
172
- }
173
- Effect.Transitions.flicker = function(pos) {
174
- return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
175
- }
176
- Effect.Transitions.wobble = function(pos) {
177
- return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
178
- }
179
- Effect.Transitions.pulse = function(pos) {
180
- return (Math.floor(pos*10) % 2 == 0 ?
181
- (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
182
- }
183
- Effect.Transitions.none = function(pos) {
184
- return 0;
185
- }
186
- Effect.Transitions.full = function(pos) {
187
- return 1;
188
- }
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
+ };
189
194
 
190
195
  /* ------------- core effects ------------- */
191
196
 
@@ -212,6 +217,9 @@ Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
212
217
  e.finishOn += effect.finishOn;
213
218
  });
214
219
  break;
220
+ case 'with-last':
221
+ timestamp = this.effects.pluck('startOn').max() || timestamp;
222
+ break;
215
223
  case 'end':
216
224
  // start effect after last queued effect has finished
217
225
  timestamp = this.effects.pluck('finishOn').max() || timestamp;
@@ -348,12 +356,24 @@ Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
348
356
  }
349
357
  });
350
358
 
359
+ Effect.Event = Class.create();
360
+ Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
361
+ initialize: function() {
362
+ var options = Object.extend({
363
+ duration: 0
364
+ }, arguments[0] || {});
365
+ this.start(options);
366
+ },
367
+ update: Prototype.emptyFunction
368
+ });
369
+
351
370
  Effect.Opacity = Class.create();
352
371
  Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
353
372
  initialize: function(element) {
354
373
  this.element = $(element);
374
+ if(!this.element) throw(Effect._elementDoesNotExistError);
355
375
  // make this work on IE on elements without 'layout'
356
- if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
376
+ if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
357
377
  this.element.setStyle({zoom: 1});
358
378
  var options = Object.extend({
359
379
  from: this.element.getOpacity() || 0.0,
@@ -370,6 +390,7 @@ Effect.Move = Class.create();
370
390
  Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
371
391
  initialize: function(element) {
372
392
  this.element = $(element);
393
+ if(!this.element) throw(Effect._elementDoesNotExistError);
373
394
  var options = Object.extend({
374
395
  x: 0,
375
396
  y: 0,
@@ -393,8 +414,8 @@ Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
393
414
  },
394
415
  update: function(position) {
395
416
  this.element.setStyle({
396
- left: this.options.x * position + this.originalLeft + 'px',
397
- top: this.options.y * position + this.originalTop + 'px'
417
+ left: Math.round(this.options.x * position + this.originalLeft) + 'px',
418
+ top: Math.round(this.options.y * position + this.originalTop) + 'px'
398
419
  });
399
420
  }
400
421
  });
@@ -408,7 +429,8 @@ Effect.MoveBy = function(element, toTop, toLeft) {
408
429
  Effect.Scale = Class.create();
409
430
  Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
410
431
  initialize: function(element, percent) {
411
- this.element = $(element)
432
+ this.element = $(element);
433
+ if(!this.element) throw(Effect._elementDoesNotExistError);
412
434
  var options = Object.extend({
413
435
  scaleX: true,
414
436
  scaleY: true,
@@ -433,7 +455,7 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
433
455
  this.originalLeft = this.element.offsetLeft;
434
456
 
435
457
  var fontSize = this.element.getStyle('font-size') || '100%';
436
- ['em','px','%'].each( function(fontSizeType) {
458
+ ['em','px','%','pt'].each( function(fontSizeType) {
437
459
  if(fontSize.indexOf(fontSizeType)>0) {
438
460
  this.fontSize = parseFloat(fontSize);
439
461
  this.fontSizeType = fontSizeType;
@@ -458,12 +480,12 @@ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
458
480
  this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
459
481
  },
460
482
  finish: function(position) {
461
- if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
483
+ if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
462
484
  },
463
485
  setDimensions: function(height, width) {
464
486
  var d = {};
465
- if(this.options.scaleX) d.width = width + 'px';
466
- if(this.options.scaleY) d.height = height + 'px';
487
+ if(this.options.scaleX) d.width = Math.round(width) + 'px';
488
+ if(this.options.scaleY) d.height = Math.round(height) + 'px';
467
489
  if(this.options.scaleFromCenter) {
468
490
  var topd = (height - this.dims[0])/2;
469
491
  var leftd = (width - this.dims[1])/2;
@@ -483,6 +505,7 @@ Effect.Highlight = Class.create();
483
505
  Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
484
506
  initialize: function(element) {
485
507
  this.element = $(element);
508
+ if(!this.element) throw(Effect._elementDoesNotExistError);
486
509
  var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
487
510
  this.start(options);
488
511
  },
@@ -547,8 +570,7 @@ Effect.Fade = function(element) {
547
570
  to: 0.0,
548
571
  afterFinishInternal: function(effect) {
549
572
  if(effect.options.to!=0) return;
550
- effect.element.hide();
551
- effect.element.setStyle({opacity: oldOpacity});
573
+ effect.element.hide().setStyle({opacity: oldOpacity});
552
574
  }}, arguments[1] || {});
553
575
  return new Effect.Opacity(element,options);
554
576
  }
@@ -563,25 +585,31 @@ Effect.Appear = function(element) {
563
585
  effect.element.forceRerendering();
564
586
  },
565
587
  beforeSetup: function(effect) {
566
- effect.element.setOpacity(effect.options.from);
567
- effect.element.show();
588
+ effect.element.setOpacity(effect.options.from).show();
568
589
  }}, arguments[1] || {});
569
590
  return new Effect.Opacity(element,options);
570
591
  }
571
592
 
572
593
  Effect.Puff = function(element) {
573
594
  element = $(element);
574
- var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') };
595
+ var oldStyle = {
596
+ opacity: element.getInlineOpacity(),
597
+ position: element.getStyle('position'),
598
+ top: element.style.top,
599
+ left: element.style.left,
600
+ width: element.style.width,
601
+ height: element.style.height
602
+ };
575
603
  return new Effect.Parallel(
576
604
  [ new Effect.Scale(element, 200,
577
605
  { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
578
606
  new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
579
607
  Object.extend({ duration: 1.0,
580
608
  beforeSetupInternal: function(effect) {
581
- effect.effects[0].element.setStyle({position: 'absolute'}); },
609
+ Position.absolutize(effect.effects[0].element)
610
+ },
582
611
  afterFinishInternal: function(effect) {
583
- effect.effects[0].element.hide();
584
- effect.effects[0].element.setStyle(oldStyle); }
612
+ effect.effects[0].element.hide().setStyle(oldStyle); }
585
613
  }, arguments[1] || {})
586
614
  );
587
615
  }
@@ -589,13 +617,12 @@ Effect.Puff = function(element) {
589
617
  Effect.BlindUp = function(element) {
590
618
  element = $(element);
591
619
  element.makeClipping();
592
- return new Effect.Scale(element, 0,
620
+ return new Effect.Scale(element, 0,
593
621
  Object.extend({ scaleContent: false,
594
622
  scaleX: false,
595
623
  restoreAfterFinish: true,
596
624
  afterFinishInternal: function(effect) {
597
- effect.element.hide();
598
- effect.element.undoClipping();
625
+ effect.element.hide().undoClipping();
599
626
  }
600
627
  }, arguments[1] || {})
601
628
  );
@@ -604,28 +631,25 @@ Effect.BlindUp = function(element) {
604
631
  Effect.BlindDown = function(element) {
605
632
  element = $(element);
606
633
  var elementDimensions = element.getDimensions();
607
- return new Effect.Scale(element, 100,
608
- Object.extend({ scaleContent: false,
609
- scaleX: false,
610
- scaleFrom: 0,
611
- scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
612
- restoreAfterFinish: true,
613
- afterSetup: function(effect) {
614
- effect.element.makeClipping();
615
- effect.element.setStyle({height: '0px'});
616
- effect.element.show();
617
- },
618
- afterFinishInternal: function(effect) {
619
- effect.element.undoClipping();
620
- }
621
- }, arguments[1] || {})
622
- );
634
+ return new Effect.Scale(element, 100, Object.extend({
635
+ scaleContent: false,
636
+ scaleX: false,
637
+ scaleFrom: 0,
638
+ scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
639
+ restoreAfterFinish: true,
640
+ afterSetup: function(effect) {
641
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
642
+ },
643
+ afterFinishInternal: function(effect) {
644
+ effect.element.undoClipping();
645
+ }
646
+ }, arguments[1] || {}));
623
647
  }
624
648
 
625
649
  Effect.SwitchOff = function(element) {
626
650
  element = $(element);
627
651
  var oldOpacity = element.getInlineOpacity();
628
- return new Effect.Appear(element, {
652
+ return new Effect.Appear(element, Object.extend({
629
653
  duration: 0.4,
630
654
  from: 0,
631
655
  transition: Effect.Transitions.flicker,
@@ -634,18 +658,14 @@ Effect.SwitchOff = function(element) {
634
658
  duration: 0.3, scaleFromCenter: true,
635
659
  scaleX: false, scaleContent: false, restoreAfterFinish: true,
636
660
  beforeSetup: function(effect) {
637
- effect.element.makePositioned();
638
- effect.element.makeClipping();
661
+ effect.element.makePositioned().makeClipping();
639
662
  },
640
663
  afterFinishInternal: function(effect) {
641
- effect.element.hide();
642
- effect.element.undoClipping();
643
- effect.element.undoPositioned();
644
- effect.element.setStyle({opacity: oldOpacity});
664
+ effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
645
665
  }
646
666
  })
647
667
  }
648
- });
668
+ }, arguments[1] || {}));
649
669
  }
650
670
 
651
671
  Effect.DropOut = function(element) {
@@ -663,9 +683,7 @@ Effect.DropOut = function(element) {
663
683
  effect.effects[0].element.makePositioned();
664
684
  },
665
685
  afterFinishInternal: function(effect) {
666
- effect.effects[0].element.hide();
667
- effect.effects[0].element.undoPositioned();
668
- effect.effects[0].element.setStyle(oldStyle);
686
+ effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
669
687
  }
670
688
  }, arguments[1] || {}));
671
689
  }
@@ -687,54 +705,42 @@ Effect.Shake = function(element) {
687
705
  { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
688
706
  new Effect.Move(effect.element,
689
707
  { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
690
- effect.element.undoPositioned();
691
- effect.element.setStyle(oldStyle);
708
+ effect.element.undoPositioned().setStyle(oldStyle);
692
709
  }}) }}) }}) }}) }}) }});
693
710
  }
694
711
 
695
712
  Effect.SlideDown = function(element) {
696
- element = $(element);
697
- element.cleanWhitespace();
713
+ element = $(element).cleanWhitespace();
698
714
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
699
- var oldInnerBottom = $(element.firstChild).getStyle('bottom');
715
+ var oldInnerBottom = element.down().getStyle('bottom');
700
716
  var elementDimensions = element.getDimensions();
701
717
  return new Effect.Scale(element, 100, Object.extend({
702
718
  scaleContent: false,
703
719
  scaleX: false,
704
- scaleFrom: 0,
720
+ scaleFrom: window.opera ? 0 : 1,
705
721
  scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
706
722
  restoreAfterFinish: true,
707
723
  afterSetup: function(effect) {
708
724
  effect.element.makePositioned();
709
- effect.element.firstChild.makePositioned();
725
+ effect.element.down().makePositioned();
710
726
  if(window.opera) effect.element.setStyle({top: ''});
711
- effect.element.makeClipping();
712
- effect.element.setStyle({height: '0px'});
713
- effect.element.show(); },
727
+ effect.element.makeClipping().setStyle({height: '0px'}).show();
728
+ },
714
729
  afterUpdateInternal: function(effect) {
715
- effect.element.firstChild.setStyle({bottom:
730
+ effect.element.down().setStyle({bottom:
716
731
  (effect.dims[0] - effect.element.clientHeight) + 'px' });
717
732
  },
718
733
  afterFinishInternal: function(effect) {
719
- effect.element.undoClipping();
720
- // IE will crash if child is undoPositioned first
721
- if(/MSIE/.test(navigator.userAgent)){
722
- effect.element.undoPositioned();
723
- effect.element.firstChild.undoPositioned();
724
- }else{
725
- effect.element.firstChild.undoPositioned();
726
- effect.element.undoPositioned();
727
- }
728
- effect.element.firstChild.setStyle({bottom: oldInnerBottom}); }
734
+ effect.element.undoClipping().undoPositioned();
735
+ effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
729
736
  }, arguments[1] || {})
730
737
  );
731
738
  }
732
-
739
+
733
740
  Effect.SlideUp = function(element) {
734
- element = $(element);
735
- element.cleanWhitespace();
736
- var oldInnerBottom = $(element.firstChild).getStyle('bottom');
737
- return new Effect.Scale(element, 0,
741
+ element = $(element).cleanWhitespace();
742
+ var oldInnerBottom = element.down().getStyle('bottom');
743
+ return new Effect.Scale(element, window.opera ? 0 : 1,
738
744
  Object.extend({ scaleContent: false,
739
745
  scaleX: false,
740
746
  scaleMode: 'box',
@@ -742,32 +748,32 @@ Effect.SlideUp = function(element) {
742
748
  restoreAfterFinish: true,
743
749
  beforeStartInternal: function(effect) {
744
750
  effect.element.makePositioned();
745
- effect.element.firstChild.makePositioned();
751
+ effect.element.down().makePositioned();
746
752
  if(window.opera) effect.element.setStyle({top: ''});
747
- effect.element.makeClipping();
748
- effect.element.show(); },
753
+ effect.element.makeClipping().show();
754
+ },
749
755
  afterUpdateInternal: function(effect) {
750
- effect.element.firstChild.setStyle({bottom:
751
- (effect.dims[0] - effect.element.clientHeight) + 'px' }); },
756
+ effect.element.down().setStyle({bottom:
757
+ (effect.dims[0] - effect.element.clientHeight) + 'px' });
758
+ },
752
759
  afterFinishInternal: function(effect) {
753
- effect.element.hide();
754
- effect.element.undoClipping();
755
- effect.element.firstChild.undoPositioned();
756
- effect.element.undoPositioned();
757
- effect.element.setStyle({bottom: oldInnerBottom}); }
760
+ effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
761
+ effect.element.down().undoPositioned();
762
+ }
758
763
  }, arguments[1] || {})
759
764
  );
760
765
  }
761
766
 
762
767
  // Bug in opera makes the TD containing this element expand for a instance after finish
763
768
  Effect.Squish = function(element) {
764
- return new Effect.Scale(element, window.opera ? 1 : 0,
765
- { restoreAfterFinish: true,
766
- beforeSetup: function(effect) {
767
- effect.element.makeClipping(effect.element); },
768
- afterFinishInternal: function(effect) {
769
- effect.element.hide(effect.element);
770
- effect.element.undoClipping(effect.element); }
769
+ return new Effect.Scale(element, window.opera ? 1 : 0, {
770
+ restoreAfterFinish: true,
771
+ beforeSetup: function(effect) {
772
+ effect.element.makeClipping();
773
+ },
774
+ afterFinishInternal: function(effect) {
775
+ effect.element.hide().undoClipping();
776
+ }
771
777
  });
772
778
  }
773
779
 
@@ -823,9 +829,7 @@ Effect.Grow = function(element) {
823
829
  y: initialMoveY,
824
830
  duration: 0.01,
825
831
  beforeSetup: function(effect) {
826
- effect.element.hide();
827
- effect.element.makeClipping();
828
- effect.element.makePositioned();
832
+ effect.element.hide().makeClipping().makePositioned();
829
833
  },
830
834
  afterFinishInternal: function(effect) {
831
835
  new Effect.Parallel(
@@ -836,13 +840,10 @@ Effect.Grow = function(element) {
836
840
  sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
837
841
  ], Object.extend({
838
842
  beforeSetup: function(effect) {
839
- effect.effects[0].element.setStyle({height: '0px'});
840
- effect.effects[0].element.show();
843
+ effect.effects[0].element.setStyle({height: '0px'}).show();
841
844
  },
842
845
  afterFinishInternal: function(effect) {
843
- effect.effects[0].element.undoClipping();
844
- effect.effects[0].element.undoPositioned();
845
- effect.effects[0].element.setStyle(oldStyle);
846
+ effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
846
847
  }
847
848
  }, options)
848
849
  )
@@ -896,13 +897,10 @@ Effect.Shrink = function(element) {
896
897
  new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
897
898
  ], Object.extend({
898
899
  beforeStartInternal: function(effect) {
899
- effect.effects[0].element.makePositioned();
900
- effect.effects[0].element.makeClipping(); },
900
+ effect.effects[0].element.makePositioned().makeClipping();
901
+ },
901
902
  afterFinishInternal: function(effect) {
902
- effect.effects[0].element.hide();
903
- effect.effects[0].element.undoClipping();
904
- effect.effects[0].element.undoPositioned();
905
- effect.effects[0].element.setStyle(oldStyle); }
903
+ effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
906
904
  }, options)
907
905
  );
908
906
  }
@@ -912,10 +910,10 @@ Effect.Pulsate = function(element) {
912
910
  var options = arguments[1] || {};
913
911
  var oldOpacity = element.getInlineOpacity();
914
912
  var transition = options.transition || Effect.Transitions.sinoidal;
915
- var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
913
+ var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
916
914
  reverser.bind(transition);
917
915
  return new Effect.Opacity(element,
918
- Object.extend(Object.extend({ duration: 3.0, from: 0,
916
+ Object.extend(Object.extend({ duration: 2.0, from: 0,
919
917
  afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
920
918
  }, options), {transition: reverser}));
921
919
  }
@@ -927,7 +925,7 @@ Effect.Fold = function(element) {
927
925
  left: element.style.left,
928
926
  width: element.style.width,
929
927
  height: element.style.height };
930
- Element.makeClipping(element);
928
+ element.makeClipping();
931
929
  return new Effect.Scale(element, 5, Object.extend({
932
930
  scaleContent: false,
933
931
  scaleX: false,
@@ -936,15 +934,147 @@ Effect.Fold = function(element) {
936
934
  scaleContent: false,
937
935
  scaleY: false,
938
936
  afterFinishInternal: function(effect) {
939
- effect.element.hide();
940
- effect.element.undoClipping();
941
- effect.element.setStyle(oldStyle);
937
+ effect.element.hide().undoClipping().setStyle(oldStyle);
942
938
  } });
943
939
  }}, arguments[1] || {}));
944
940
  };
945
941
 
942
+ Effect.Morph = Class.create();
943
+ Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
944
+ initialize: function(element) {
945
+ this.element = $(element);
946
+ if(!this.element) throw(Effect._elementDoesNotExistError);
947
+ var options = Object.extend({
948
+ style: ''
949
+ }, arguments[1] || {});
950
+ this.start(options);
951
+ },
952
+ setup: function(){
953
+ function parseColor(color){
954
+ if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
955
+ color = color.parseColor();
956
+ return $R(0,2).map(function(i){
957
+ return parseInt( color.slice(i*2+1,i*2+3), 16 )
958
+ });
959
+ }
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
+ });
970
+ }.bind(this)).reject(function(transform){
971
+ return (
972
+ (transform.originalValue == transform.targetValue) ||
973
+ (
974
+ transform.unit != 'color' &&
975
+ (isNaN(transform.originalValue) || isNaN(transform.targetValue))
976
+ )
977
+ )
978
+ });
979
+ },
980
+ 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);
992
+ }
993
+ });
994
+
995
+ Effect.Transform = Class.create();
996
+ Object.extend(Effect.Transform.prototype, {
997
+ initialize: function(tracks){
998
+ this.tracks = [];
999
+ this.options = arguments[1] || {};
1000
+ this.addTracks(tracks);
1001
+ },
1002
+ addTracks: function(tracks){
1003
+ tracks.each(function(track){
1004
+ var data = $H(track).values().first();
1005
+ this.tracks.push($H({
1006
+ ids: $H(track).keys().first(),
1007
+ effect: Effect.Morph,
1008
+ options: { style: data }
1009
+ }));
1010
+ }.bind(this));
1011
+ return this;
1012
+ },
1013
+ play: function(){
1014
+ return new Effect.Parallel(
1015
+ 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)) });
1018
+ }).flatten(),
1019
+ this.options
1020
+ );
1021
+ }
1022
+ });
1023
+
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'];
1041
+
1042
+ Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1043
+
1044
+ 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();
1048
+
1049
+ Element.CSS_PROPERTIES.each(function(property){
1050
+ if(style[property]) styleRules[property] = style[property];
1051
+ });
1052
+
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;
1069
+ };
1070
+
1071
+ Element.morph = function(element, style) {
1072
+ new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1073
+ return element;
1074
+ };
1075
+
946
1076
  ['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
947
- 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each(
1077
+ 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
948
1078
  function(f) { Element.Methods[f] = Element[f]; }
949
1079
  );
950
1080