rails 0.13.0 → 0.13.1

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.

@@ -112,12 +112,18 @@ Element.Class = {
112
112
  var Droppables = {
113
113
  drops: false,
114
114
 
115
+ remove: function(element) {
116
+ for(var i = 0; i < this.drops.length; i++)
117
+ if(this.drops[i].element == element)
118
+ this.drops.splice(i,1);
119
+ },
120
+
115
121
  add: function(element) {
116
122
  var element = $(element);
117
- var options = {
123
+ var options = Object.extend({
118
124
  greedy: true,
119
125
  hoverclass: null
120
- }.extend(arguments[1] || {});
126
+ }, arguments[1] || {});
121
127
 
122
128
  // cache containers
123
129
  if(options.containment) {
@@ -134,43 +140,42 @@ var Droppables = {
134
140
  options._containers.length-1;
135
141
  }
136
142
 
137
- if(element.style.position=='') //fix IE
138
- element.style.position = 'relative';
143
+ Element.makePositioned(element); // fix IE
139
144
 
140
- // activate the droppable
141
- element.droppable = options;
145
+ options.element = element;
142
146
 
147
+ // activate the droppable
143
148
  if(!this.drops) this.drops = [];
144
- this.drops.push(element);
149
+ this.drops.push(options);
145
150
  },
146
151
 
147
152
  is_contained: function(element, drop) {
148
- var containers = drop.droppable._containers;
153
+ var containers = drop._containers;
149
154
  var parentNode = element.parentNode;
150
- var i = drop.droppable._containers_length;
155
+ var i = drop._containers_length;
151
156
  do { if(parentNode==containers[i]) return true; } while (i--);
152
157
  return false;
153
158
  },
154
159
 
155
160
  is_affected: function(pX, pY, element, drop) {
156
161
  return (
157
- (drop!=element) &&
158
- ((!drop.droppable._containers) ||
162
+ (drop.element!=element) &&
163
+ ((!drop._containers) ||
159
164
  this.is_contained(element, drop)) &&
160
- ((!drop.droppable.accept) ||
161
- (Element.Class.has_any(element, drop.droppable.accept))) &&
162
- Position.within(drop, pX, pY) );
165
+ ((!drop.accept) ||
166
+ (Element.Class.has_any(element, drop.accept))) &&
167
+ Position.within(drop.element, pX, pY) );
163
168
  },
164
169
 
165
170
  deactivate: function(drop) {
166
- Element.Class.remove(drop, drop.droppable.hoverclass);
171
+ Element.Class.remove(drop.element, drop.hoverclass);
167
172
  this.last_active = null;
168
173
  },
169
174
 
170
175
  activate: function(drop) {
171
176
  if(this.last_active) this.deactivate(this.last_active);
172
- if(drop.droppable.hoverclass) {
173
- Element.Class.add(drop, drop.droppable.hoverclass);
177
+ if(drop.hoverclass) {
178
+ Element.Class.add(drop.element, drop.hoverclass);
174
179
  this.last_active = drop;
175
180
  }
176
181
  },
@@ -184,10 +189,9 @@ var Droppables = {
184
189
  var i = this.drops.length-1; do {
185
190
  var drop = this.drops[i];
186
191
  if(this.is_affected(pX, pY, element, drop)) {
187
- if(drop.droppable.onHover)
188
- drop.droppable.onHover(
189
- element, drop, Position.overlap(drop.droppable.overlap, drop));
190
- if(drop.droppable.greedy) {
192
+ if(drop.onHover)
193
+ drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
194
+ if(drop.greedy) {
191
195
  this.activate(drop);
192
196
  return;
193
197
  }
@@ -196,17 +200,13 @@ var Droppables = {
196
200
  },
197
201
 
198
202
  fire: function(event, element) {
199
- if(!this.drops) return;
200
- var pX = Event.pointerX(event);
201
- var pY = Event.pointerY(event);
203
+ if(!this.last_active) return;
202
204
  Position.prepare();
203
205
 
204
- var i = this.drops.length-1; do {
205
- var drop = this.drops[i];
206
- if(this.is_affected(pX, pY, element, drop))
207
- if(drop.droppable.onDrop)
208
- drop.droppable.onDrop(element);
209
- } while (i--);
206
+ if (this.is_affected(Event.pointerX(event), Event.pointerY(event), element, this.last_active))
207
+ if (this.last_active.onDrop)
208
+ this.last_active.onDrop(element, this.last_active);
209
+
210
210
  },
211
211
 
212
212
  reset: function() {
@@ -220,6 +220,11 @@ Draggables = {
220
220
  addObserver: function(observer) {
221
221
  this.observers.push(observer);
222
222
  },
223
+ removeObserver: function(element) { // element instead of obsever fixes mem leaks
224
+ for(var i = 0; i < this.observers.length; i++)
225
+ if(this.observers[i].element && (this.observers[i].element == element))
226
+ this.observers.splice(i,1);
227
+ },
223
228
  notify: function(eventName, draggable) { // 'onStart', 'onEnd'
224
229
  for(var i = 0; i < this.observers.length; i++)
225
230
  this.observers[i][eventName](draggable);
@@ -231,7 +236,7 @@ Draggables = {
231
236
  Draggable = Class.create();
232
237
  Draggable.prototype = {
233
238
  initialize: function(element) {
234
- var options = {
239
+ var options = Object.extend({
235
240
  handle: false,
236
241
  starteffect: function(element) {
237
242
  new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
@@ -244,15 +249,12 @@ Draggable.prototype = {
244
249
  },
245
250
  zindex: 1000,
246
251
  revert: false
247
- }.extend(arguments[1] || {});
252
+ }, arguments[1] || {});
248
253
 
249
254
  this.element = $(element);
250
- this.element.drag = this;
251
255
  this.handle = options.handle ? $(options.handle) : this.element;
252
256
 
253
- // fix IE
254
- if(!this.element.style.position)
255
- this.element.style.position = 'relative';
257
+ Element.makePositioned(this.element); // fix IE
256
258
 
257
259
  this.offsetX = 0;
258
260
  this.offsetY = 0;
@@ -267,9 +269,21 @@ Draggable.prototype = {
267
269
  this.active = false;
268
270
  this.dragging = false;
269
271
 
270
- Event.observe(this.handle, "mousedown", this.startDrag.bindAsEventListener(this));
271
- Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this));
272
- Event.observe(document, "mousemove", this.update.bindAsEventListener(this));
272
+ this.eventMouseDown = this.startDrag.bindAsEventListener(this);
273
+ this.eventMouseUp = this.endDrag.bindAsEventListener(this);
274
+ this.eventMouseMove = this.update.bindAsEventListener(this);
275
+ this.eventKeypress = this.keyPress.bindAsEventListener(this);
276
+
277
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
278
+ Event.observe(document, "mouseup", this.eventMouseUp);
279
+ Event.observe(document, "mousemove", this.eventMouseMove);
280
+ Event.observe(document, "keypress", this.eventKeypress);
281
+ },
282
+ destroy: function() {
283
+ Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
284
+ Event.stopObserving(document, "mouseup", this.eventMouseUp);
285
+ Event.stopObserving(document, "mousemove", this.eventMouseMove);
286
+ Event.stopObserving(document, "keypress", this.eventKeypress);
273
287
  },
274
288
  currentLeft: function() {
275
289
  return parseInt(this.element.style.left || '0');
@@ -290,31 +304,43 @@ Draggable.prototype = {
290
304
  Event.stop(event);
291
305
  }
292
306
  },
293
- endDrag: function(event) {
294
- if(this.active && this.dragging) {
295
- this.active = false;
296
- this.dragging = false;
307
+ finishDrag: function(event, success) {
308
+ this.active = false;
309
+ this.dragging = false;
310
+
311
+ if(success) Droppables.fire(event, this.element);
312
+ Draggables.notify('onEnd', this);
313
+
314
+ var revert = this.options.revert;
315
+ if(revert && typeof revert == 'function') revert = revert(this.element);
297
316
 
298
- Droppables.fire(event, this.element);
299
- Draggables.notify('onEnd', this);
317
+ if(revert && this.options.reverteffect) {
318
+ this.options.reverteffect(this.element,
319
+ this.currentTop()-this.originalTop,
320
+ this.currentLeft()-this.originalLeft);
321
+ } else {
322
+ this.originalLeft = this.currentLeft();
323
+ this.originalTop = this.currentTop();
324
+ }
325
+
326
+ this.element.style.zIndex = this.originalZ;
300
327
 
301
- var revert = this.options.revert;
302
- if(revert && typeof revert == 'function') revert = revert(this.element);
328
+ if(this.options.endeffect)
329
+ this.options.endeffect(this.element);
303
330
 
304
- if(revert && this.options.reverteffect) {
305
- this.options.reverteffect(this.element,
306
- this.currentTop()-this.originalTop,
307
- this.currentLeft()-this.originalLeft);
308
- } else {
309
- this.originalLeft = this.currentLeft();
310
- this.originalTop = this.currentTop();
331
+ Droppables.reset();
332
+ },
333
+ keyPress: function(event) {
334
+ if(this.active) {
335
+ if(event.keyCode==Event.KEY_ESC) {
336
+ this.finishDrag(event, false);
337
+ Event.stop(event);
311
338
  }
312
- this.element.style.zIndex = this.originalZ;
313
-
314
- if(this.options.endeffect)
315
- this.options.endeffect(this.element);
316
-
317
- Droppables.reset();
339
+ }
340
+ },
341
+ endDrag: function(event) {
342
+ if(this.active && this.dragging) {
343
+ this.finishDrag(event, true);
318
344
  Event.stop(event);
319
345
  }
320
346
  this.active = false;
@@ -372,9 +398,32 @@ SortableObserver.prototype = {
372
398
  }
373
399
 
374
400
  Sortable = {
401
+ sortables: new Array(),
402
+ options: function(element){
403
+ var element = $(element);
404
+ for(var i=0;i<this.sortables.length;i++)
405
+ if(this.sortables[i].element == element)
406
+ return this.sortables[i];
407
+ return null;
408
+ },
409
+ destroy: function(element){
410
+ var element = $(element);
411
+ for(var i=0;i<this.sortables.length;i++) {
412
+ if(this.sortables[i].element == element) {
413
+ var s = this.sortables[i];
414
+ Draggables.removeObserver(s.element);
415
+ for(var j=0;j<s.droppables.length;j++)
416
+ Droppables.remove(s.droppables[j]);
417
+ for(var j=0;j<s.draggables.length;j++)
418
+ s.draggables[j].destroy();
419
+ this.sortables.splice(i,1);
420
+ }
421
+ }
422
+ },
375
423
  create: function(element) {
376
424
  var element = $(element);
377
- var options = {
425
+ var options = Object.extend({
426
+ element: element,
378
427
  tag: 'li', // assumes li children, override with tag: 'tagname'
379
428
  overlap: 'vertical', // one of 'vertical', 'horizontal'
380
429
  constraint: 'vertical', // one of 'vertical', 'horizontal', false
@@ -384,8 +433,10 @@ Sortable = {
384
433
  hoverclass: null,
385
434
  onChange: function() {},
386
435
  onUpdate: function() {}
387
- }.extend(arguments[1] || {});
388
- element.sortable = options;
436
+ }, arguments[1] || {});
437
+
438
+ // clear any old sortable with same element
439
+ this.destroy(element);
389
440
 
390
441
  // build options for the draggables
391
442
  var options_for_draggable = {
@@ -435,8 +486,8 @@ Sortable = {
435
486
  // fix for gecko engine
436
487
  Element.cleanWhitespace(element);
437
488
 
438
- // for onupdate
439
- Draggables.addObserver(new SortableObserver(element, options.onUpdate));
489
+ options.draggables = [];
490
+ options.droppables = [];
440
491
 
441
492
  // make it so
442
493
  var elements = element.childNodes;
@@ -448,18 +499,28 @@ Sortable = {
448
499
  var handle = options.handle ?
449
500
  Element.Class.childrenWith(elements[i], options.handle)[0] : elements[i];
450
501
 
451
- new Draggable(elements[i], options_for_draggable.extend({ handle: handle }));
502
+ options.draggables.push(new Draggable(elements[i], Object.extend(options_for_draggable, { handle: handle })));
503
+
452
504
  Droppables.add(elements[i], options_for_droppable);
505
+ options.droppables.push(elements[i]);
506
+
453
507
  }
454
508
 
509
+ // keep reference
510
+ this.sortables.push(options);
511
+
512
+ // for onupdate
513
+ Draggables.addObserver(new SortableObserver(element, options.onUpdate));
514
+
455
515
  },
456
516
  serialize: function(element) {
457
517
  var element = $(element);
458
- var options = {
459
- tag: element.sortable.tag,
460
- only: element.sortable.only,
518
+ var sortableOptions = this.options(element);
519
+ var options = Object.extend({
520
+ tag: sortableOptions.tag,
521
+ only: sortableOptions.only,
461
522
  name: element.id
462
- }.extend(arguments[1] || {});
523
+ }, arguments[1] || {});
463
524
 
464
525
  var items = $(element).childNodes;
465
526
  var queryComponents = new Array();
@@ -46,15 +46,33 @@ Effect.Transitions.wobble = function(pos) {
46
46
  return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
47
47
  }
48
48
  Effect.Transitions.pulse = function(pos) {
49
- return (Math.floor(pos*10) % 2 == 0 ?
49
+ return (Math.floor(pos*10) % 2 == 0 ?
50
50
  (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
51
51
  }
52
-
53
52
  Effect.Transitions.none = function(pos) {
54
- return 0;
53
+ return 0;
55
54
  }
56
55
  Effect.Transitions.full = function(pos) {
57
- return 1;
56
+ return 1;
57
+ }
58
+
59
+ /* ------------- element ext -------------- */
60
+
61
+ Element.makePositioned = function(element) {
62
+ element = $(element);
63
+ if(element.style.position == "")
64
+ element.style.position = "relative";
65
+ }
66
+
67
+ Element.makeClipping = function(element) {
68
+ element = $(element);
69
+ element._overflow = element.style.overflow || 'visible';
70
+ if(element._overflow!='hidden') element.style.overflow = 'hidden';
71
+ }
72
+
73
+ Element.undoClipping = function(element) {
74
+ element = $(element);
75
+ if(element._overflow!='hidden') element.style.overflow = element._overflow;
58
76
  }
59
77
 
60
78
  /* ------------- core effects ------------- */
@@ -62,33 +80,33 @@ Effect.Transitions.full = function(pos) {
62
80
  Effect.Base = function() {};
63
81
  Effect.Base.prototype = {
64
82
  setOptions: function(options) {
65
- this.options = {
83
+ this.options = Object.extend({
66
84
  transition: Effect.Transitions.sinoidal,
67
85
  duration: 1.0, // seconds
68
86
  fps: 25.0, // max. 100fps
69
87
  sync: false, // true for combining
70
88
  from: 0.0,
71
89
  to: 1.0
72
- }.extend(options || {});
90
+ }, options || {});
73
91
  },
74
92
  start: function(options) {
75
93
  this.setOptions(options || {});
76
- this.currentFrame = 0;
77
- this.startOn = new Date().getTime();
78
- this.finishOn = this.startOn + (this.options.duration*1000);
94
+ this.currentFrame = 0;
95
+ this.startOn = new Date().getTime();
96
+ this.finishOn = this.startOn + (this.options.duration*1000);
79
97
  if(this.options.beforeStart) this.options.beforeStart(this);
80
98
  if(!this.options.sync) this.loop();
81
99
  },
82
100
  loop: function() {
83
- timePos = new Date().getTime();
101
+ var timePos = new Date().getTime();
84
102
  if(timePos >= this.finishOn) {
85
103
  this.render(this.options.to);
86
104
  if(this.finish) this.finish();
87
105
  if(this.options.afterFinish) this.options.afterFinish(this);
88
106
  return;
89
107
  }
90
- pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
91
- frame = Math.round(pos * this.options.fps * this.options.duration);
108
+ var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
109
+ var frame = Math.round(pos * this.options.fps * this.options.duration);
92
110
  if(frame > this.currentFrame) {
93
111
  this.render(pos);
94
112
  this.currentFrame = frame;
@@ -97,7 +115,7 @@ Effect.Base.prototype = {
97
115
  },
98
116
  render: function(pos) {
99
117
  if(this.options.transition) pos = this.options.transition(pos);
100
- pos = pos * (this.options.to-this.options.from);
118
+ pos *= (this.options.to-this.options.from);
101
119
  pos += this.options.from;
102
120
  if(this.options.beforeUpdate) this.options.beforeUpdate(this);
103
121
  if(this.update) this.update(pos);
@@ -109,32 +127,32 @@ Effect.Base.prototype = {
109
127
  }
110
128
 
111
129
  Effect.Parallel = Class.create();
112
- Effect.Parallel.prototype = (new Effect.Base()).extend({
113
- initialize: function(effects) {
114
- this.effects = effects || [];
115
- this.start(arguments[1]);
116
- },
117
- update: function(position) {
118
- for (var i = 0; i < this.effects.length; i++)
119
- this.effects[i].render(position);
120
- },
121
- finish: function(position) {
122
- for (var i = 0; i < this.effects.length; i++)
123
- if(this.effects[i].finish) this.effects[i].finish(position);
124
- }
125
- });
130
+ Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
131
+ initialize: function(effects) {
132
+ this.effects = effects || [];
133
+ this.start(arguments[1]);
134
+ },
135
+ update: function(position) {
136
+ for (var i = 0; i < this.effects.length; i++)
137
+ this.effects[i].render(position);
138
+ },
139
+ finish: function(position) {
140
+ for (var i = 0; i < this.effects.length; i++)
141
+ if(this.effects[i].finish) this.effects[i].finish(position);
142
+ }
143
+ });
126
144
 
127
145
  // Internet Explorer caveat: works only on elements the have
128
146
  // a 'layout', meaning having a given width or height.
129
147
  // There is no way to safely set this automatically.
130
148
  Effect.Opacity = Class.create();
131
- Effect.Opacity.prototype = (new Effect.Base()).extend({
149
+ Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
132
150
  initialize: function(element) {
133
151
  this.element = $(element);
134
- options = {
152
+ options = Object.extend({
135
153
  from: 0.0,
136
154
  to: 1.0
137
- }.extend(arguments[1] || {});
155
+ }, arguments[1] || {});
138
156
  this.start(options);
139
157
  },
140
158
  update: function(position) {
@@ -148,45 +166,44 @@ Effect.Opacity.prototype = (new Effect.Base()).extend({
148
166
  });
149
167
 
150
168
  Effect.MoveBy = Class.create();
151
- Effect.MoveBy.prototype = (new Effect.Base()).extend({
152
- initialize: function(element, toTop, toLeft) {
153
- this.element = $(element);
154
- this.originalTop = parseFloat(this.element.style.top || '0');
155
- this.originalLeft = parseFloat(this.element.style.left || '0');
156
- this.toTop = toTop;
157
- this.toLeft = toLeft;
158
- if(this.element.style.position == "")
159
- this.element.style.position = "relative";
160
- this.start(arguments[3]);
161
- },
162
- update: function(position) {
163
- topd = this.toTop * position + this.originalTop;
164
- leftd = this.toLeft * position + this.originalLeft;
165
- this.setPosition(topd, leftd);
166
- },
167
- setPosition: function(topd, leftd) {
168
- this.element.style.top = topd + "px";
169
- this.element.style.left = leftd + "px";
170
- }
169
+ Object.extend(Object.extend(Effect.MoveBy.prototype, Effect.Base.prototype), {
170
+ initialize: function(element, toTop, toLeft) {
171
+ this.element = $(element);
172
+ this.originalTop = parseFloat(this.element.style.top || '0');
173
+ this.originalLeft = parseFloat(this.element.style.left || '0');
174
+ this.toTop = toTop;
175
+ this.toLeft = toLeft;
176
+ Element.makePositioned(this.element);
177
+ this.start(arguments[3]);
178
+ },
179
+ update: function(position) {
180
+ topd = this.toTop * position + this.originalTop;
181
+ leftd = this.toLeft * position + this.originalLeft;
182
+ this.setPosition(topd, leftd);
183
+ },
184
+ setPosition: function(topd, leftd) {
185
+ this.element.style.top = topd + "px";
186
+ this.element.style.left = leftd + "px";
187
+ }
171
188
  });
172
189
 
173
190
  Effect.Scale = Class.create();
174
- Effect.Scale.prototype = (new Effect.Base()).extend({
191
+ Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
175
192
  initialize: function(element, percent) {
176
193
  this.element = $(element)
177
- options = {
194
+ options = Object.extend({
178
195
  scaleX: true,
179
196
  scaleY: true,
180
197
  scaleContent: true,
181
198
  scaleFromCenter: false,
182
199
  scaleMode: 'box', // 'box' or 'contents' or {} with provided values
183
200
  scaleFrom: 100.0
184
- }.extend(arguments[2] || {});
201
+ }, arguments[2] || {});
185
202
  this.originalTop = this.element.offsetTop;
186
203
  this.originalLeft = this.element.offsetLeft;
187
- if (this.element.style.fontSize=="") this.sizeEm = 1.0;
188
- if (this.element.style.fontSize && this.element.style.fontSize.indexOf("em")>0)
189
- this.sizeEm = parseFloat(this.element.style.fontSize);
204
+ if(this.element.style.fontSize=="") this.sizeEm = 1.0;
205
+ if(this.element.style.fontSize && this.element.style.fontSize.indexOf("em")>0)
206
+ this.sizeEm = parseFloat(this.element.style.fontSize);
190
207
  this.factor = (percent/100.0) - (options.scaleFrom/100.0);
191
208
  if(options.scaleMode=='box') {
192
209
  this.originalHeight = this.element.clientHeight;
@@ -207,8 +224,8 @@ Effect.Scale.prototype = (new Effect.Base()).extend({
207
224
  if(this.options.scaleContent && this.sizeEm)
208
225
  this.element.style.fontSize = this.sizeEm*currentScale + "em";
209
226
  this.setDimensions(
210
- this.originalWidth * currentScale,
211
- this.originalHeight * currentScale);
227
+ this.originalWidth * currentScale,
228
+ this.originalHeight * currentScale);
212
229
  },
213
230
 
214
231
  setDimensions: function(width, height) {
@@ -229,7 +246,7 @@ Effect.Scale.prototype = (new Effect.Base()).extend({
229
246
  });
230
247
 
231
248
  Effect.Highlight = Class.create();
232
- Effect.Highlight.prototype = (new Effect.Base()).extend({
249
+ Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
233
250
  initialize: function(element) {
234
251
  this.element = $(element);
235
252
 
@@ -242,10 +259,11 @@ Effect.Highlight.prototype = (new Effect.Base()).extend({
242
259
  var cols = current.slice(4,current.length-1).split(',');
243
260
  var i=0; do { endcolor += parseInt(cols[i]).toColorPart() } while (++i<3); }
244
261
 
245
- var options = {
246
- startcolor: "#ffff99",
247
- endcolor: endcolor
248
- }.extend(arguments[1] || {});
262
+ var options = Object.extend({
263
+ startcolor: "#ffff99",
264
+ endcolor: endcolor,
265
+ restorecolor: current
266
+ }, arguments[1] || {});
249
267
 
250
268
  // init color calculations
251
269
  this.colors_base = [
@@ -266,25 +284,49 @@ Effect.Highlight.prototype = (new Effect.Base()).extend({
266
284
  Math.round(this.colors_base[2]+(this.colors_delta[2]*position)) ];
267
285
  this.element.style.backgroundColor = "#" +
268
286
  colors[0].toColorPart() + colors[1].toColorPart() + colors[2].toColorPart();
287
+ },
288
+ finish: function() {
289
+ this.element.style.backgroundColor = this.options.restorecolor;
269
290
  }
270
291
  });
271
292
 
293
+ Effect.ScrollTo = Class.create();
294
+ Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
295
+ initialize: function(element) {
296
+ this.element = $(element);
297
+ Position.prepare();
298
+ var offsets = Position.cumulativeOffset(this.element);
299
+ var max = window.innerHeight ?
300
+ window.height - window.innerHeight :
301
+ document.body.scrollHeight -
302
+ (document.documentElement.clientHeight ?
303
+ document.documentElement.clientHeight : document.body.clientHeight);
304
+ this.scrollStart = Position.deltaY;
305
+ this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
306
+ this.start(arguments[1] || {});
307
+ },
308
+ update: function(position) {
309
+ Position.prepare();
310
+ window.scrollTo(Position.deltaX,
311
+ this.scrollStart + (position*this.delta));
312
+ }
313
+ });
272
314
 
273
315
  /* ------------- prepackaged effects ------------- */
274
316
 
275
- Effect.Fade = function(element) {
276
- options = {
317
+ Effect.Fade = function(element) {
318
+ options = Object.extend({
277
319
  from: 1.0,
278
320
  to: 0.0,
279
321
  afterFinish: function(effect)
280
322
  { Element.hide(effect.element);
281
323
  effect.setOpacity(1); }
282
- }.extend(arguments[1] || {});
324
+ }, arguments[1] || {});
283
325
  new Effect.Opacity(element,options);
284
326
  }
285
327
 
286
- Effect.Appear = function(element) {
287
- options = {
328
+ Effect.Appear = function(element) {
329
+ options = Object.extend({
288
330
  from: 0.0,
289
331
  to: 1.0,
290
332
  beforeStart: function(effect)
@@ -292,7 +334,7 @@ Effect.Appear = function(element) {
292
334
  Element.show(effect.element); },
293
335
  afterUpdate: function(effect)
294
336
  { Element.show(effect.element); }
295
- }.extend(arguments[1] || {});
337
+ }, arguments[1] || {});
296
338
  new Effect.Opacity(element,options);
297
339
  }
298
340
 
@@ -310,34 +352,32 @@ Effect.Puff = function(element) {
310
352
  }
311
353
 
312
354
  Effect.BlindUp = function(element) {
313
- $(element)._overflow = $(element).style.overflow || 'visible';
314
- $(element).style.overflow = 'hidden';
355
+ Element.makeClipping(element);
315
356
  new Effect.Scale(element, 0,
316
- { scaleContent: false,
357
+ Object.extend({ scaleContent: false,
317
358
  scaleX: false,
318
359
  afterFinish: function(effect)
319
360
  {
320
361
  Element.hide(effect.element);
321
- effect.element.style.overflow = effect.element._overflow;
362
+ Element.undoClipping(effect.element);
322
363
  }
323
- }.extend(arguments[1] || {})
364
+ }, arguments[1] || {})
324
365
  );
325
366
  }
326
367
 
327
368
  Effect.BlindDown = function(element) {
328
369
  $(element).style.height = '0px';
329
- $(element)._overflow = $(element).style.overflow || 'visible';
330
- $(element).style.overflow = 'hidden';
370
+ Element.makeClipping(element);
331
371
  Element.show(element);
332
372
  new Effect.Scale(element, 100,
333
- { scaleContent: false,
373
+ Object.extend({ scaleContent: false,
334
374
  scaleX: false,
335
375
  scaleMode: 'contents',
336
376
  scaleFrom: 0,
337
377
  afterFinish: function(effect) {
338
- effect.element.style.overflow = effect.element._overflow;
378
+ Element.undoClipping(effect.element);
339
379
  }
340
- }.extend(arguments[1] || {})
380
+ }, arguments[1] || {})
341
381
  );
342
382
  }
343
383
 
@@ -346,7 +386,7 @@ Effect.SwitchOff = function(element) {
346
386
  { duration: 0.4,
347
387
  transition: Effect.Transitions.flicker,
348
388
  afterFinish: function(effect)
349
- { effect.element.style.overflow = 'hidden';
389
+ { effect.element.style.overflow = 'hidden';
350
390
  new Effect.Scale(effect.element, 1,
351
391
  { duration: 0.3, scaleFromCenter: true,
352
392
  scaleX: false, scaleContent: false,
@@ -356,7 +396,7 @@ Effect.SwitchOff = function(element) {
356
396
  afterFinish: function(effect) { Element.hide(effect.element); }
357
397
  } )
358
398
  }
359
- } )
399
+ } );
360
400
  }
361
401
 
362
402
  Effect.DropOut = function(element) {
@@ -386,13 +426,14 @@ Effect.Shake = function(element) {
386
426
  }
387
427
 
388
428
  Effect.SlideDown = function(element) {
389
- $(element)._overflow = $(element).style.overflow || 'visible';
390
- $(element).style.height = '0px';
391
- $(element).style.overflow = 'hidden';
392
- $(element).firstChild.style.position = 'relative';
429
+ element = $(element);
430
+ element.style.height = '0px';
431
+ Element.makeClipping(element);
432
+ Element.cleanWhitespace(element);
433
+ Element.makePositioned(element.firstChild);
393
434
  Element.show(element);
394
435
  new Effect.Scale(element, 100,
395
- { scaleContent: false,
436
+ Object.extend({ scaleContent: false,
396
437
  scaleX: false,
397
438
  scaleMode: 'contents',
398
439
  scaleFrom: 0,
@@ -400,18 +441,19 @@ Effect.SlideDown = function(element) {
400
441
  { effect.element.firstChild.style.bottom =
401
442
  (effect.originalHeight - effect.element.clientHeight) + 'px'; },
402
443
  afterFinish: function(effect)
403
- { effect.element.style.overflow = effect.element._overflow; }
404
- }.extend(arguments[1] || {})
444
+ { Element.undoClipping(effect.element); }
445
+ }, arguments[1] || {})
405
446
  );
406
447
  }
407
448
 
408
449
  Effect.SlideUp = function(element) {
409
- $(element)._overflow = $(element).style.overflow || 'visible';
410
- $(element).style.overflow = 'hidden';
411
- $(element).firstChild.style.position = 'relative';
450
+ element = $(element);
451
+ Element.makeClipping(element);
452
+ Element.cleanWhitespace(element);
453
+ Element.makePositioned(element.firstChild);
412
454
  Element.show(element);
413
455
  new Effect.Scale(element, 0,
414
- { scaleContent: false,
456
+ Object.extend({ scaleContent: false,
415
457
  scaleX: false,
416
458
  afterUpdate: function(effect)
417
459
  { effect.element.firstChild.style.bottom =
@@ -419,9 +461,9 @@ Effect.SlideUp = function(element) {
419
461
  afterFinish: function(effect)
420
462
  {
421
463
  Element.hide(effect.element);
422
- effect.element.style.overflow = effect.element._overflow;
464
+ Element.undoClipping(effect.element);
423
465
  }
424
- }.extend(arguments[1] || {})
466
+ }, arguments[1] || {})
425
467
  );
426
468
  }
427
469
 
@@ -540,14 +582,14 @@ Effect.Pulsate = function(element) {
540
582
  var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
541
583
  reverser.bind(transition);
542
584
  new Effect.Opacity(element,
543
- { duration: 3.0,
585
+ Object.extend(Object.extend({ duration: 3.0,
544
586
  afterFinish: function(effect) { Element.show(effect.element); }
545
- }.extend(options).extend({transition: reverser}));
587
+ }, options), {transition: reverser}));
546
588
  }
547
589
 
548
590
  Effect.Fold = function(element) {
549
591
  $(element).style.overflow = 'hidden';
550
- new Effect.Scale(element, 5, {
592
+ new Effect.Scale(element, 5, Object.extend({
551
593
  scaleContent: false,
552
594
  scaleTo: 100,
553
595
  scaleX: false,
@@ -557,7 +599,7 @@ Effect.Fold = function(element) {
557
599
  scaleTo: 0,
558
600
  scaleY: false,
559
601
  afterFinish: function(effect) { Element.hide(effect.element) } });
560
- }}.extend(arguments[1] || {}));
602
+ }}, arguments[1] || {}));
561
603
  }
562
604
 
563
605
  // old: new Effect.ContentZoom(element, percent)