~ubuntu-branches/ubuntu/raring/ubiquity-slideshow-ubuntu/raring

« back to all changes in this revision

Viewing changes to slides/link/effects.js

  • Committer: Bazaar Package Importer
  • Author(s): Evan Dandrea, Dylan McCall, Evan Dandrea
  • Date: 2010-02-26 14:26:00 UTC
  • Revision ID: james.westby@ubuntu.com-20100226142600-5bulva07ptvdnzx3
Tags: 15
[ Dylan McCall ]
* Rearranged source package to closely mirror build output.
* Renamed ./slides to ./slideshows, reflecting new arrangement.
* Each slideshow now has a unique slideshow.conf file.
* Split link-core and link-default for slideshows. link-default
  is NOT symlinked to a central place, encouraging customization.
* Generated icons now go straight to the build directory.
* Merging new Xubuntu slideshow.
* Merging new visuals for Kubuntu slideshow.

[ Evan Dandrea ]
* Fix typo in Kubuntu chat slide.
* Move from po2html, which is no longer included in Debian, to po4a.
* Make each slideshow package Replace and Conflict the ubiquity-
  slideshow virtual package, to ensure that only one slideshow can be
  installed at a time and so we can put all of the files in a single
  location (LP: #526483).  The upgrade slideshows do the same with the
  ubiquity-slideshow-upgrade virtual package.
* Update update-launchpad-translations.sh to reflect recent directory
  layout changes.
* Update translations from Launchpad.
* Remove possibly inappropriate URL from br translation (LP: #528465).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
2
 
// 
3
 
// Permission is hereby granted, free of charge, to any person obtaining
4
 
// a copy of this software and associated documentation files (the
5
 
// "Software"), to deal in the Software without restriction, including
6
 
// without limitation the rights to use, copy, modify, merge, publish,
7
 
// distribute, sublicense, and/or sell copies of the Software, and to
8
 
// permit persons to whom the Software is furnished to do so, subject to
9
 
// the following conditions:
10
 
// 
11
 
// The above copyright notice and this permission notice shall be
12
 
// included in all copies or substantial portions of the Software.
13
 
//
14
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
 
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
 
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
 
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
 
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
 
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
 
//
22
 
// For details, see the script.aculo.us web site: http://script.aculo.us/
23
 
 
24
 
// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
25
 
 
26
 
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
27
 
// Contributors:
28
 
//  Justin Palmer (http://encytemedia.com/)
29
 
//  Mark Pilgrim (http://diveintomark.org/)
30
 
//  Martin Bialasinki
31
 
// 
32
 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
33
 
// For details, see the script.aculo.us web site: http://script.aculo.us/ 
34
 
 
35
 
// converts rgb() and #xxx to #xxxxxx format,  
36
 
// returns self (or first argument) if not convertable  
37
 
String.prototype.parseColor = function() {  
38
 
  var color = '#';
39
 
  if(this.slice(0,4) == 'rgb(') {  
40
 
    var cols = this.slice(4,this.length-1).split(',');  
41
 
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
42
 
  } else {  
43
 
    if(this.slice(0,1) == '#') {  
44
 
      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
45
 
      if(this.length==7) color = this.toLowerCase();  
46
 
    }  
47
 
  }  
48
 
  return(color.length==7 ? color : (arguments[0] || this));  
49
 
}
50
 
 
51
 
/*--------------------------------------------------------------------------*/
52
 
 
53
 
Element.collectTextNodes = function(element) {  
54
 
  return $A($(element).childNodes).collect( function(node) {
55
 
    return (node.nodeType==3 ? node.nodeValue : 
56
 
      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
57
 
  }).flatten().join('');
58
 
}
59
 
 
60
 
Element.collectTextNodesIgnoreClass = function(element, className) {  
61
 
  return $A($(element).childNodes).collect( function(node) {
62
 
    return (node.nodeType==3 ? node.nodeValue : 
63
 
      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
64
 
        Element.collectTextNodesIgnoreClass(node, className) : ''));
65
 
  }).flatten().join('');
66
 
}
67
 
 
68
 
Element.setContentZoom = function(element, percent) {
69
 
  element = $(element);  
70
 
  element.setStyle({fontSize: (percent/100) + 'em'});   
71
 
  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
72
 
  return element;
73
 
}
74
 
 
75
 
Element.getOpacity = function(element){
76
 
  return $(element).getStyle('opacity');
77
 
}
78
 
 
79
 
Element.setOpacity = function(element, value){
80
 
  return $(element).setStyle({opacity:value});
81
 
}
82
 
 
83
 
Element.getInlineOpacity = function(element){
84
 
  return $(element).style.opacity || '';
85
 
}
86
 
 
87
 
Element.forceRerendering = function(element) {
88
 
  try {
89
 
    element = $(element);
90
 
    var n = document.createTextNode(' ');
91
 
    element.appendChild(n);
92
 
    element.removeChild(n);
93
 
  } catch(e) { }
94
 
};
95
 
 
96
 
/*--------------------------------------------------------------------------*/
97
 
 
98
 
Array.prototype.call = function() {
99
 
  var args = arguments;
100
 
  this.each(function(f){ f.apply(this, args) });
101
 
}
102
 
 
103
 
/*--------------------------------------------------------------------------*/
104
 
 
105
 
var Effect = {
106
 
  _elementDoesNotExistError: {
107
 
    name: 'ElementDoesNotExistError',
108
 
    message: 'The specified DOM element does not exist, but is required for this effect to operate'
109
 
  },
110
 
  tagifyText: function(element) {
111
 
    if(typeof Builder == 'undefined')
112
 
      throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
113
 
      
114
 
    var tagifyStyle = 'position:relative';
115
 
    if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
116
 
    
117
 
    element = $(element);
118
 
    $A(element.childNodes).each( function(child) {
119
 
      if(child.nodeType==3) {
120
 
        child.nodeValue.toArray().each( function(character) {
121
 
          element.insertBefore(
122
 
            Builder.node('span',{style: tagifyStyle},
123
 
              character == ' ' ? String.fromCharCode(160) : character), 
124
 
              child);
125
 
        });
126
 
        Element.remove(child);
127
 
      }
128
 
    });
129
 
  },
130
 
  multiple: function(element, effect) {
131
 
    var elements;
132
 
    if(((typeof element == 'object') || 
133
 
        (typeof element == 'function')) && 
134
 
       (element.length))
135
 
      elements = element;
136
 
    else
137
 
      elements = $(element).childNodes;
138
 
      
139
 
    var options = Object.extend({
140
 
      speed: 0.1,
141
 
      delay: 0.0
142
 
    }, arguments[2] || {});
143
 
    var masterDelay = options.delay;
144
 
 
145
 
    $A(elements).each( function(element, index) {
146
 
      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
147
 
    });
148
 
  },
149
 
  PAIRS: {
150
 
    'slide':  ['SlideDown','SlideUp'],
151
 
    'blind':  ['BlindDown','BlindUp'],
152
 
    'appear': ['Appear','Fade']
153
 
  },
154
 
  toggle: function(element, effect) {
155
 
    element = $(element);
156
 
    effect = (effect || 'appear').toLowerCase();
157
 
    var options = Object.extend({
158
 
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
159
 
    }, arguments[2] || {});
160
 
    Effect[element.visible() ? 
161
 
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
162
 
  }
163
 
};
164
 
 
165
 
var Effect2 = Effect; // deprecated
166
 
 
167
 
/* ------------- transitions ------------- */
168
 
 
169
 
Effect.Transitions = {
170
 
  linear: Prototype.K,
171
 
  sinoidal: function(pos) {
172
 
    return (-Math.cos(pos*Math.PI)/2) + 0.5;
173
 
  },
174
 
  reverse: function(pos) {
175
 
    return 1-pos;
176
 
  },
177
 
  flicker: function(pos) {
178
 
    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
179
 
  },
180
 
  wobble: function(pos) {
181
 
    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
182
 
  },
183
 
  pulse: function(pos, pulses) { 
184
 
    pulses = pulses || 5; 
185
 
    return (
186
 
      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
187
 
            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
188
 
        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
189
 
      );
190
 
  },
191
 
  none: function(pos) {
192
 
    return 0;
193
 
  },
194
 
  full: function(pos) {
195
 
    return 1;
196
 
  }
197
 
};
198
 
 
199
 
/* ------------- core effects ------------- */
200
 
 
201
 
Effect.ScopedQueue = Class.create();
202
 
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
203
 
  initialize: function() {
204
 
    this.effects  = [];
205
 
    this.interval = null;
206
 
  },
207
 
  _each: function(iterator) {
208
 
    this.effects._each(iterator);
209
 
  },
210
 
  add: function(effect) {
211
 
    var timestamp = new Date().getTime();
212
 
    
213
 
    var position = (typeof effect.options.queue == 'string') ? 
214
 
      effect.options.queue : effect.options.queue.position;
215
 
    
216
 
    switch(position) {
217
 
      case 'front':
218
 
        // move unstarted effects after this effect  
219
 
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
220
 
            e.startOn  += effect.finishOn;
221
 
            e.finishOn += effect.finishOn;
222
 
          });
223
 
        break;
224
 
      case 'with-last':
225
 
        timestamp = this.effects.pluck('startOn').max() || timestamp;
226
 
        break;
227
 
      case 'end':
228
 
        // start effect after last queued effect has finished
229
 
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
230
 
        break;
231
 
    }
232
 
    
233
 
    effect.startOn  += timestamp;
234
 
    effect.finishOn += timestamp;
235
 
 
236
 
    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
237
 
      this.effects.push(effect);
238
 
    
239
 
    if(!this.interval) 
240
 
      this.interval = setInterval(this.loop.bind(this), 15);
241
 
  },
242
 
  remove: function(effect) {
243
 
    this.effects = this.effects.reject(function(e) { return e==effect });
244
 
    if(this.effects.length == 0) {
245
 
      clearInterval(this.interval);
246
 
      this.interval = null;
247
 
    }
248
 
  },
249
 
  loop: function() {
250
 
    var timePos = new Date().getTime();
251
 
    for(var i=0, len=this.effects.length;i<len;i++) 
252
 
      if(this.effects[i]) this.effects[i].loop(timePos);
253
 
  }
254
 
});
255
 
 
256
 
Effect.Queues = {
257
 
  instances: $H(),
258
 
  get: function(queueName) {
259
 
    if(typeof queueName != 'string') return queueName;
260
 
    
261
 
    if(!this.instances[queueName])
262
 
      this.instances[queueName] = new Effect.ScopedQueue();
263
 
      
264
 
    return this.instances[queueName];
265
 
  }
266
 
}
267
 
Effect.Queue = Effect.Queues.get('global');
268
 
 
269
 
Effect.DefaultOptions = {
270
 
  transition: Effect.Transitions.sinoidal,
271
 
  duration:   1.0,   // seconds
272
 
  fps:        60.0,  // max. 60fps due to Effect.Queue implementation
273
 
  sync:       false, // true for combining
274
 
  from:       0.0,
275
 
  to:         1.0,
276
 
  delay:      0.0,
277
 
  queue:      'parallel'
278
 
}
279
 
 
280
 
Effect.Base = function() {};
281
 
Effect.Base.prototype = {
282
 
  position: null,
283
 
  start: function(options) {
284
 
    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
285
 
    this.currentFrame = 0;
286
 
    this.state        = 'idle';
287
 
    this.startOn      = this.options.delay*1000;
288
 
    this.finishOn     = this.startOn + (this.options.duration*1000);
289
 
    this.event('beforeStart');
290
 
    if(!this.options.sync)
291
 
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
292
 
        'global' : this.options.queue.scope).add(this);
293
 
  },
294
 
  loop: function(timePos) {
295
 
    if(timePos >= this.startOn) {
296
 
      if(timePos >= this.finishOn) {
297
 
        this.render(1.0);
298
 
        this.cancel();
299
 
        this.event('beforeFinish');
300
 
        if(this.finish) this.finish(); 
301
 
        this.event('afterFinish');
302
 
        return;  
303
 
      }
304
 
      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
305
 
      var frame = Math.round(pos * this.options.fps * this.options.duration);
306
 
      if(frame > this.currentFrame) {
307
 
        this.render(pos);
308
 
        this.currentFrame = frame;
309
 
      }
310
 
    }
311
 
  },
312
 
  render: function(pos) {
313
 
    if(this.state == 'idle') {
314
 
      this.state = 'running';
315
 
      this.event('beforeSetup');
316
 
      if(this.setup) this.setup();
317
 
      this.event('afterSetup');
318
 
    }
319
 
    if(this.state == 'running') {
320
 
      if(this.options.transition) pos = this.options.transition(pos);
321
 
      pos *= (this.options.to-this.options.from);
322
 
      pos += this.options.from;
323
 
      this.position = pos;
324
 
      this.event('beforeUpdate');
325
 
      if(this.update) this.update(pos);
326
 
      this.event('afterUpdate');
327
 
    }
328
 
  },
329
 
  cancel: function() {
330
 
    if(!this.options.sync)
331
 
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
332
 
        'global' : this.options.queue.scope).remove(this);
333
 
    this.state = 'finished';
334
 
  },
335
 
  event: function(eventName) {
336
 
    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
337
 
    if(this.options[eventName]) this.options[eventName](this);
338
 
  },
339
 
  inspect: function() {
340
 
    var data = $H();
341
 
    for(property in this)
342
 
      if(typeof this[property] != 'function') data[property] = this[property];
343
 
    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
344
 
  }
345
 
}
346
 
 
347
 
Effect.Parallel = Class.create();
348
 
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
349
 
  initialize: function(effects) {
350
 
    this.effects = effects || [];
351
 
    this.start(arguments[1]);
352
 
  },
353
 
  update: function(position) {
354
 
    this.effects.invoke('render', position);
355
 
  },
356
 
  finish: function(position) {
357
 
    this.effects.each( function(effect) {
358
 
      effect.render(1.0);
359
 
      effect.cancel();
360
 
      effect.event('beforeFinish');
361
 
      if(effect.finish) effect.finish(position);
362
 
      effect.event('afterFinish');
363
 
    });
364
 
  }
365
 
});
366
 
 
367
 
Effect.Event = Class.create();
368
 
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
369
 
  initialize: function() {
370
 
    var options = Object.extend({
371
 
      duration: 0
372
 
    }, arguments[0] || {});
373
 
    this.start(options);
374
 
  },
375
 
  update: Prototype.emptyFunction
376
 
});
377
 
 
378
 
Effect.Opacity = Class.create();
379
 
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
380
 
  initialize: function(element) {
381
 
    this.element = $(element);
382
 
    if(!this.element) throw(Effect._elementDoesNotExistError);
383
 
    // make this work on IE on elements without 'layout'
384
 
    if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
385
 
      this.element.setStyle({zoom: 1});
386
 
    var options = Object.extend({
387
 
      from: this.element.getOpacity() || 0.0,
388
 
      to:   1.0
389
 
    }, arguments[1] || {});
390
 
    this.start(options);
391
 
  },
392
 
  update: function(position) {
393
 
    this.element.setOpacity(position);
394
 
  }
395
 
});
396
 
 
397
 
Effect.Move = Class.create();
398
 
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
399
 
  initialize: function(element) {
400
 
    this.element = $(element);
401
 
    if(!this.element) throw(Effect._elementDoesNotExistError);
402
 
    var options = Object.extend({
403
 
      x:    0,
404
 
      y:    0,
405
 
      mode: 'relative'
406
 
    }, arguments[1] || {});
407
 
    this.start(options);
408
 
  },
409
 
  setup: function() {
410
 
    // Bug in Opera: Opera returns the "real" position of a static element or
411
 
    // relative element that does not have top/left explicitly set.
412
 
    // ==> Always set top and left for position relative elements in your stylesheets 
413
 
    // (to 0 if you do not need them) 
414
 
    this.element.makePositioned();
415
 
    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
416
 
    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
417
 
    if(this.options.mode == 'absolute') {
418
 
      // absolute movement, so we need to calc deltaX and deltaY
419
 
      this.options.x = this.options.x - this.originalLeft;
420
 
      this.options.y = this.options.y - this.originalTop;
421
 
    }
422
 
  },
423
 
  update: function(position) {
424
 
    this.element.setStyle({
425
 
      left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
426
 
      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
427
 
    });
428
 
  }
429
 
});
430
 
 
431
 
// for backwards compatibility
432
 
Effect.MoveBy = function(element, toTop, toLeft) {
433
 
  return new Effect.Move(element, 
434
 
    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
435
 
};
436
 
 
437
 
Effect.Scale = Class.create();
438
 
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
439
 
  initialize: function(element, percent) {
440
 
    this.element = $(element);
441
 
    if(!this.element) throw(Effect._elementDoesNotExistError);
442
 
    var options = Object.extend({
443
 
      scaleX: true,
444
 
      scaleY: true,
445
 
      scaleContent: true,
446
 
      scaleFromCenter: false,
447
 
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
448
 
      scaleFrom: 100.0,
449
 
      scaleTo:   percent
450
 
    }, arguments[2] || {});
451
 
    this.start(options);
452
 
  },
453
 
  setup: function() {
454
 
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
455
 
    this.elementPositioning = this.element.getStyle('position');
456
 
    
457
 
    this.originalStyle = {};
458
 
    ['top','left','width','height','fontSize'].each( function(k) {
459
 
      this.originalStyle[k] = this.element.style[k];
460
 
    }.bind(this));
461
 
      
462
 
    this.originalTop  = this.element.offsetTop;
463
 
    this.originalLeft = this.element.offsetLeft;
464
 
    
465
 
    var fontSize = this.element.getStyle('font-size') || '100%';
466
 
    ['em','px','%','pt'].each( function(fontSizeType) {
467
 
      if(fontSize.indexOf(fontSizeType)>0) {
468
 
        this.fontSize     = parseFloat(fontSize);
469
 
        this.fontSizeType = fontSizeType;
470
 
      }
471
 
    }.bind(this));
472
 
    
473
 
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
474
 
    
475
 
    this.dims = null;
476
 
    if(this.options.scaleMode=='box')
477
 
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
478
 
    if(/^content/.test(this.options.scaleMode))
479
 
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
480
 
    if(!this.dims)
481
 
      this.dims = [this.options.scaleMode.originalHeight,
482
 
                   this.options.scaleMode.originalWidth];
483
 
  },
484
 
  update: function(position) {
485
 
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
486
 
    if(this.options.scaleContent && this.fontSize)
487
 
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
488
 
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
489
 
  },
490
 
  finish: function(position) {
491
 
    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
492
 
  },
493
 
  setDimensions: function(height, width) {
494
 
    var d = {};
495
 
    if(this.options.scaleX) d.width = Math.round(width) + 'px';
496
 
    if(this.options.scaleY) d.height = Math.round(height) + 'px';
497
 
    if(this.options.scaleFromCenter) {
498
 
      var topd  = (height - this.dims[0])/2;
499
 
      var leftd = (width  - this.dims[1])/2;
500
 
      if(this.elementPositioning == 'absolute') {
501
 
        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
502
 
        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
503
 
      } else {
504
 
        if(this.options.scaleY) d.top = -topd + 'px';
505
 
        if(this.options.scaleX) d.left = -leftd + 'px';
506
 
      }
507
 
    }
508
 
    this.element.setStyle(d);
509
 
  }
510
 
});
511
 
 
512
 
Effect.Highlight = Class.create();
513
 
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
514
 
  initialize: function(element) {
515
 
    this.element = $(element);
516
 
    if(!this.element) throw(Effect._elementDoesNotExistError);
517
 
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
518
 
    this.start(options);
519
 
  },
520
 
  setup: function() {
521
 
    // Prevent executing on elements not in the layout flow
522
 
    if(this.element.getStyle('display')=='none') { this.cancel(); return; }
523
 
    // Disable background image during the effect
524
 
    this.oldStyle = {};
525
 
    if (!this.options.keepBackgroundImage) {
526
 
      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
527
 
      this.element.setStyle({backgroundImage: 'none'});
528
 
    }
529
 
    if(!this.options.endcolor)
530
 
      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
531
 
    if(!this.options.restorecolor)
532
 
      this.options.restorecolor = this.element.getStyle('background-color');
533
 
    // init color calculations
534
 
    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
535
 
    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
536
 
  },
537
 
  update: function(position) {
538
 
    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
539
 
      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
540
 
  },
541
 
  finish: function() {
542
 
    this.element.setStyle(Object.extend(this.oldStyle, {
543
 
      backgroundColor: this.options.restorecolor
544
 
    }));
545
 
  }
546
 
});
547
 
 
548
 
Effect.ScrollTo = Class.create();
549
 
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
550
 
  initialize: function(element) {
551
 
    this.element = $(element);
552
 
    this.start(arguments[1] || {});
553
 
  },
554
 
  setup: function() {
555
 
    Position.prepare();
556
 
    var offsets = Position.cumulativeOffset(this.element);
557
 
    if(this.options.offset) offsets[1] += this.options.offset;
558
 
    var max = window.innerHeight ? 
559
 
      window.height - window.innerHeight :
560
 
      document.body.scrollHeight - 
561
 
        (document.documentElement.clientHeight ? 
562
 
          document.documentElement.clientHeight : document.body.clientHeight);
563
 
    this.scrollStart = Position.deltaY;
564
 
    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
565
 
  },
566
 
  update: function(position) {
567
 
    Position.prepare();
568
 
    window.scrollTo(Position.deltaX, 
569
 
      this.scrollStart + (position*this.delta));
570
 
  }
571
 
});
572
 
 
573
 
/* ------------- combination effects ------------- */
574
 
 
575
 
Effect.Fade = function(element) {
576
 
  element = $(element);
577
 
  var oldOpacity = element.getInlineOpacity();
578
 
  var options = Object.extend({
579
 
  from: element.getOpacity() || 1.0,
580
 
  to:   0.0,
581
 
  afterFinishInternal: function(effect) { 
582
 
    if(effect.options.to!=0) return;
583
 
    effect.element.hide().setStyle({opacity: oldOpacity}); 
584
 
  }}, arguments[1] || {});
585
 
  return new Effect.Opacity(element,options);
586
 
}
587
 
 
588
 
Effect.Appear = function(element) {
589
 
  element = $(element);
590
 
  var options = Object.extend({
591
 
  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
592
 
  to:   1.0,
593
 
  // force Safari to render floated elements properly
594
 
  afterFinishInternal: function(effect) {
595
 
    effect.element.forceRerendering();
596
 
  },
597
 
  beforeSetup: function(effect) {
598
 
    effect.element.setOpacity(effect.options.from).show(); 
599
 
  }}, arguments[1] || {});
600
 
  return new Effect.Opacity(element,options);
601
 
}
602
 
 
603
 
Effect.Puff = function(element) {
604
 
  element = $(element);
605
 
  var oldStyle = { 
606
 
    opacity: element.getInlineOpacity(), 
607
 
    position: element.getStyle('position'),
608
 
    top:  element.style.top,
609
 
    left: element.style.left,
610
 
    width: element.style.width,
611
 
    height: element.style.height
612
 
  };
613
 
  return new Effect.Parallel(
614
 
   [ new Effect.Scale(element, 200, 
615
 
      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
616
 
     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
617
 
     Object.extend({ duration: 1.0, 
618
 
      beforeSetupInternal: function(effect) {
619
 
        Position.absolutize(effect.effects[0].element)
620
 
      },
621
 
      afterFinishInternal: function(effect) {
622
 
         effect.effects[0].element.hide().setStyle(oldStyle); }
623
 
     }, arguments[1] || {})
624
 
   );
625
 
}
626
 
 
627
 
Effect.BlindUp = function(element) {
628
 
  element = $(element);
629
 
  element.makeClipping();
630
 
  return new Effect.Scale(element, 0,
631
 
    Object.extend({ scaleContent: false, 
632
 
      scaleX: false, 
633
 
      restoreAfterFinish: true,
634
 
      afterFinishInternal: function(effect) {
635
 
        effect.element.hide().undoClipping();
636
 
      } 
637
 
    }, arguments[1] || {})
638
 
  );
639
 
}
640
 
 
641
 
Effect.BlindDown = function(element) {
642
 
  element = $(element);
643
 
  var elementDimensions = element.getDimensions();
644
 
  return new Effect.Scale(element, 100, Object.extend({ 
645
 
    scaleContent: false, 
646
 
    scaleX: false,
647
 
    scaleFrom: 0,
648
 
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
649
 
    restoreAfterFinish: true,
650
 
    afterSetup: function(effect) {
651
 
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
652
 
    },  
653
 
    afterFinishInternal: function(effect) {
654
 
      effect.element.undoClipping();
655
 
    }
656
 
  }, arguments[1] || {}));
657
 
}
658
 
 
659
 
Effect.SwitchOff = function(element) {
660
 
  element = $(element);
661
 
  var oldOpacity = element.getInlineOpacity();
662
 
  return new Effect.Appear(element, Object.extend({
663
 
    duration: 0.4,
664
 
    from: 0,
665
 
    transition: Effect.Transitions.flicker,
666
 
    afterFinishInternal: function(effect) {
667
 
      new Effect.Scale(effect.element, 1, { 
668
 
        duration: 0.3, scaleFromCenter: true,
669
 
        scaleX: false, scaleContent: false, restoreAfterFinish: true,
670
 
        beforeSetup: function(effect) { 
671
 
          effect.element.makePositioned().makeClipping();
672
 
        },
673
 
        afterFinishInternal: function(effect) {
674
 
          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
675
 
        }
676
 
      })
677
 
    }
678
 
  }, arguments[1] || {}));
679
 
}
680
 
 
681
 
Effect.DropOut = function(element) {
682
 
  element = $(element);
683
 
  var oldStyle = {
684
 
    top: element.getStyle('top'),
685
 
    left: element.getStyle('left'),
686
 
    opacity: element.getInlineOpacity() };
687
 
  return new Effect.Parallel(
688
 
    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
689
 
      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
690
 
    Object.extend(
691
 
      { duration: 0.5,
692
 
        beforeSetup: function(effect) {
693
 
          effect.effects[0].element.makePositioned(); 
694
 
        },
695
 
        afterFinishInternal: function(effect) {
696
 
          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
697
 
        } 
698
 
      }, arguments[1] || {}));
699
 
}
700
 
 
701
 
Effect.Shake = function(element) {
702
 
  element = $(element);
703
 
  var oldStyle = {
704
 
    top: element.getStyle('top'),
705
 
    left: element.getStyle('left') };
706
 
    return new Effect.Move(element, 
707
 
      { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
708
 
    new Effect.Move(effect.element,
709
 
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
710
 
    new Effect.Move(effect.element,
711
 
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
712
 
    new Effect.Move(effect.element,
713
 
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
714
 
    new Effect.Move(effect.element,
715
 
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
716
 
    new Effect.Move(effect.element,
717
 
      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
718
 
        effect.element.undoPositioned().setStyle(oldStyle);
719
 
  }}) }}) }}) }}) }}) }});
720
 
}
721
 
 
722
 
Effect.SlideDown = function(element) {
723
 
  element = $(element).cleanWhitespace();
724
 
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
725
 
  var oldInnerBottom = element.down().getStyle('bottom');
726
 
  var elementDimensions = element.getDimensions();
727
 
  return new Effect.Scale(element, 100, Object.extend({ 
728
 
    scaleContent: false, 
729
 
    scaleX: false, 
730
 
    scaleFrom: window.opera ? 0 : 1,
731
 
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
732
 
    restoreAfterFinish: true,
733
 
    afterSetup: function(effect) {
734
 
      effect.element.makePositioned();
735
 
      effect.element.down().makePositioned();
736
 
      if(window.opera) effect.element.setStyle({top: ''});
737
 
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
738
 
    },
739
 
    afterUpdateInternal: function(effect) {
740
 
      effect.element.down().setStyle({bottom:
741
 
        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
742
 
    },
743
 
    afterFinishInternal: function(effect) {
744
 
      effect.element.undoClipping().undoPositioned();
745
 
      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
746
 
    }, arguments[1] || {})
747
 
  );
748
 
}
749
 
 
750
 
Effect.SlideUp = function(element) {
751
 
  element = $(element).cleanWhitespace();
752
 
  var oldInnerBottom = element.down().getStyle('bottom');
753
 
  return new Effect.Scale(element, window.opera ? 0 : 1,
754
 
   Object.extend({ scaleContent: false, 
755
 
    scaleX: false, 
756
 
    scaleMode: 'box',
757
 
    scaleFrom: 100,
758
 
    restoreAfterFinish: true,
759
 
    beforeStartInternal: function(effect) {
760
 
      effect.element.makePositioned();
761
 
      effect.element.down().makePositioned();
762
 
      if(window.opera) effect.element.setStyle({top: ''});
763
 
      effect.element.makeClipping().show();
764
 
    },  
765
 
    afterUpdateInternal: function(effect) {
766
 
      effect.element.down().setStyle({bottom:
767
 
        (effect.dims[0] - effect.element.clientHeight) + 'px' });
768
 
    },
769
 
    afterFinishInternal: function(effect) {
770
 
      effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
771
 
      effect.element.down().undoPositioned();
772
 
    }
773
 
   }, arguments[1] || {})
774
 
  );
775
 
}
776
 
 
777
 
// Bug in opera makes the TD containing this element expand for a instance after finish 
778
 
Effect.Squish = function(element) {
779
 
  return new Effect.Scale(element, window.opera ? 1 : 0, { 
780
 
    restoreAfterFinish: true,
781
 
    beforeSetup: function(effect) {
782
 
      effect.element.makeClipping(); 
783
 
    },  
784
 
    afterFinishInternal: function(effect) {
785
 
      effect.element.hide().undoClipping(); 
786
 
    }
787
 
  });
788
 
}
789
 
 
790
 
Effect.Grow = function(element) {
791
 
  element = $(element);
792
 
  var options = Object.extend({
793
 
    direction: 'center',
794
 
    moveTransition: Effect.Transitions.sinoidal,
795
 
    scaleTransition: Effect.Transitions.sinoidal,
796
 
    opacityTransition: Effect.Transitions.full
797
 
  }, arguments[1] || {});
798
 
  var oldStyle = {
799
 
    top: element.style.top,
800
 
    left: element.style.left,
801
 
    height: element.style.height,
802
 
    width: element.style.width,
803
 
    opacity: element.getInlineOpacity() };
804
 
 
805
 
  var dims = element.getDimensions();    
806
 
  var initialMoveX, initialMoveY;
807
 
  var moveX, moveY;
808
 
  
809
 
  switch (options.direction) {
810
 
    case 'top-left':
811
 
      initialMoveX = initialMoveY = moveX = moveY = 0; 
812
 
      break;
813
 
    case 'top-right':
814
 
      initialMoveX = dims.width;
815
 
      initialMoveY = moveY = 0;
816
 
      moveX = -dims.width;
817
 
      break;
818
 
    case 'bottom-left':
819
 
      initialMoveX = moveX = 0;
820
 
      initialMoveY = dims.height;
821
 
      moveY = -dims.height;
822
 
      break;
823
 
    case 'bottom-right':
824
 
      initialMoveX = dims.width;
825
 
      initialMoveY = dims.height;
826
 
      moveX = -dims.width;
827
 
      moveY = -dims.height;
828
 
      break;
829
 
    case 'center':
830
 
      initialMoveX = dims.width / 2;
831
 
      initialMoveY = dims.height / 2;
832
 
      moveX = -dims.width / 2;
833
 
      moveY = -dims.height / 2;
834
 
      break;
835
 
  }
836
 
  
837
 
  return new Effect.Move(element, {
838
 
    x: initialMoveX,
839
 
    y: initialMoveY,
840
 
    duration: 0.01, 
841
 
    beforeSetup: function(effect) {
842
 
      effect.element.hide().makeClipping().makePositioned();
843
 
    },
844
 
    afterFinishInternal: function(effect) {
845
 
      new Effect.Parallel(
846
 
        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
847
 
          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
848
 
          new Effect.Scale(effect.element, 100, {
849
 
            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
850
 
            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
851
 
        ], Object.extend({
852
 
             beforeSetup: function(effect) {
853
 
               effect.effects[0].element.setStyle({height: '0px'}).show(); 
854
 
             },
855
 
             afterFinishInternal: function(effect) {
856
 
               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
857
 
             }
858
 
           }, options)
859
 
      )
860
 
    }
861
 
  });
862
 
}
863
 
 
864
 
Effect.Shrink = function(element) {
865
 
  element = $(element);
866
 
  var options = Object.extend({
867
 
    direction: 'center',
868
 
    moveTransition: Effect.Transitions.sinoidal,
869
 
    scaleTransition: Effect.Transitions.sinoidal,
870
 
    opacityTransition: Effect.Transitions.none
871
 
  }, arguments[1] || {});
872
 
  var oldStyle = {
873
 
    top: element.style.top,
874
 
    left: element.style.left,
875
 
    height: element.style.height,
876
 
    width: element.style.width,
877
 
    opacity: element.getInlineOpacity() };
878
 
 
879
 
  var dims = element.getDimensions();
880
 
  var moveX, moveY;
881
 
  
882
 
  switch (options.direction) {
883
 
    case 'top-left':
884
 
      moveX = moveY = 0;
885
 
      break;
886
 
    case 'top-right':
887
 
      moveX = dims.width;
888
 
      moveY = 0;
889
 
      break;
890
 
    case 'bottom-left':
891
 
      moveX = 0;
892
 
      moveY = dims.height;
893
 
      break;
894
 
    case 'bottom-right':
895
 
      moveX = dims.width;
896
 
      moveY = dims.height;
897
 
      break;
898
 
    case 'center':  
899
 
      moveX = dims.width / 2;
900
 
      moveY = dims.height / 2;
901
 
      break;
902
 
  }
903
 
  
904
 
  return new Effect.Parallel(
905
 
    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
906
 
      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
907
 
      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
908
 
    ], Object.extend({            
909
 
         beforeStartInternal: function(effect) {
910
 
           effect.effects[0].element.makePositioned().makeClipping(); 
911
 
         },
912
 
         afterFinishInternal: function(effect) {
913
 
           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
914
 
       }, options)
915
 
  );
916
 
}
917
 
 
918
 
Effect.Pulsate = function(element) {
919
 
  element = $(element);
920
 
  var options    = arguments[1] || {};
921
 
  var oldOpacity = element.getInlineOpacity();
922
 
  var transition = options.transition || Effect.Transitions.sinoidal;
923
 
  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
924
 
  reverser.bind(transition);
925
 
  return new Effect.Opacity(element, 
926
 
    Object.extend(Object.extend({  duration: 2.0, from: 0,
927
 
      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
928
 
    }, options), {transition: reverser}));
929
 
}
930
 
 
931
 
Effect.Fold = function(element) {
932
 
  element = $(element);
933
 
  var oldStyle = {
934
 
    top: element.style.top,
935
 
    left: element.style.left,
936
 
    width: element.style.width,
937
 
    height: element.style.height };
938
 
  element.makeClipping();
939
 
  return new Effect.Scale(element, 5, Object.extend({   
940
 
    scaleContent: false,
941
 
    scaleX: false,
942
 
    afterFinishInternal: function(effect) {
943
 
    new Effect.Scale(element, 1, { 
944
 
      scaleContent: false, 
945
 
      scaleY: false,
946
 
      afterFinishInternal: function(effect) {
947
 
        effect.element.hide().undoClipping().setStyle(oldStyle);
948
 
      } });
949
 
  }}, arguments[1] || {}));
950
 
};
951
 
 
952
 
Effect.Morph = Class.create();
953
 
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
954
 
  initialize: function(element) {
955
 
    this.element = $(element);
956
 
    if(!this.element) throw(Effect._elementDoesNotExistError);
957
 
    var options = Object.extend({
958
 
      style: {}
959
 
    }, arguments[1] || {});
960
 
    if (typeof options.style == 'string') {
961
 
      if(options.style.indexOf(':') == -1) {
962
 
        var cssText = '', selector = '.' + options.style;
963
 
        $A(document.styleSheets).reverse().each(function(styleSheet) {
964
 
          if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
965
 
          else if (styleSheet.rules) cssRules = styleSheet.rules;
966
 
          $A(cssRules).reverse().each(function(rule) {
967
 
            if (selector == rule.selectorText) {
968
 
              cssText = rule.style.cssText;
969
 
              throw $break;
970
 
            }
971
 
          });
972
 
          if (cssText) throw $break;
973
 
        });
974
 
        this.style = cssText.parseStyle();
975
 
        options.afterFinishInternal = function(effect){
976
 
          effect.element.addClassName(effect.options.style);
977
 
          effect.transforms.each(function(transform) {
978
 
            if(transform.style != 'opacity')
979
 
              effect.element.style[transform.style.camelize()] = '';
980
 
          });
981
 
        }
982
 
      } else this.style = options.style.parseStyle();
983
 
    } else this.style = $H(options.style)
984
 
    this.start(options);
985
 
  },
986
 
  setup: function(){
987
 
    function parseColor(color){
988
 
      if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
989
 
      color = color.parseColor();
990
 
      return $R(0,2).map(function(i){
991
 
        return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
992
 
      });
993
 
    }
994
 
    this.transforms = this.style.map(function(pair){
995
 
      var property = pair[0].underscore().dasherize(), value = pair[1], unit = null;
996
 
 
997
 
      if(value.parseColor('#zzzzzz') != '#zzzzzz') {
998
 
        value = value.parseColor();
999
 
        unit  = 'color';
1000
 
      } else if(property == 'opacity') {
1001
 
        value = parseFloat(value);
1002
 
        if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
1003
 
          this.element.setStyle({zoom: 1});
1004
 
      } else if(Element.CSS_LENGTH.test(value)) 
1005
 
        var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
1006
 
          value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
1007
 
 
1008
 
      var originalValue = this.element.getStyle(property);
1009
 
      return $H({ 
1010
 
        style: property, 
1011
 
        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
1012
 
        targetValue: unit=='color' ? parseColor(value) : value,
1013
 
        unit: unit
1014
 
      });
1015
 
    }.bind(this)).reject(function(transform){
1016
 
      return (
1017
 
        (transform.originalValue == transform.targetValue) ||
1018
 
        (
1019
 
          transform.unit != 'color' &&
1020
 
          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
1021
 
        )
1022
 
      )
1023
 
    });
1024
 
  },
1025
 
  update: function(position) {
1026
 
    var style = $H(), value = null;
1027
 
    this.transforms.each(function(transform){
1028
 
      value = transform.unit=='color' ?
1029
 
        $R(0,2).inject('#',function(m,v,i){
1030
 
          return m+(Math.round(transform.originalValue[i]+
1031
 
            (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : 
1032
 
        transform.originalValue + Math.round(
1033
 
          ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
1034
 
      style[transform.style] = value;
1035
 
    });
1036
 
    this.element.setStyle(style);
1037
 
  }
1038
 
});
1039
 
 
1040
 
Effect.Transform = Class.create();
1041
 
Object.extend(Effect.Transform.prototype, {
1042
 
  initialize: function(tracks){
1043
 
    this.tracks  = [];
1044
 
    this.options = arguments[1] || {};
1045
 
    this.addTracks(tracks);
1046
 
  },
1047
 
  addTracks: function(tracks){
1048
 
    tracks.each(function(track){
1049
 
      var data = $H(track).values().first();
1050
 
      this.tracks.push($H({
1051
 
        ids:     $H(track).keys().first(),
1052
 
        effect:  Effect.Morph,
1053
 
        options: { style: data }
1054
 
      }));
1055
 
    }.bind(this));
1056
 
    return this;
1057
 
  },
1058
 
  play: function(){
1059
 
    return new Effect.Parallel(
1060
 
      this.tracks.map(function(track){
1061
 
        var elements = [$(track.ids) || $$(track.ids)].flatten();
1062
 
        return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1063
 
      }).flatten(),
1064
 
      this.options
1065
 
    );
1066
 
  }
1067
 
});
1068
 
 
1069
 
Element.CSS_PROPERTIES = $w(
1070
 
  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
1071
 
  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1072
 
  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1073
 
  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1074
 
  'fontSize fontWeight height left letterSpacing lineHeight ' +
1075
 
  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1076
 
  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1077
 
  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1078
 
  'right textIndent top width wordSpacing zIndex');
1079
 
  
1080
 
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1081
 
 
1082
 
String.prototype.parseStyle = function(){
1083
 
  var element = Element.extend(document.createElement('div'));
1084
 
  element.innerHTML = '<div style="' + this + '"></div>';
1085
 
  var style = element.down().style, styleRules = $H();
1086
 
  
1087
 
  Element.CSS_PROPERTIES.each(function(property){
1088
 
    if(style[property]) styleRules[property] = style[property]; 
1089
 
  });
1090
 
  if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
1091
 
    styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
1092
 
  }
1093
 
  return styleRules;
1094
 
};
1095
 
 
1096
 
Element.morph = function(element, style) {
1097
 
  new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1098
 
  return element;
1099
 
};
1100
 
 
1101
 
['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
1102
 
 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
1103
 
  function(f) { Element.Methods[f] = Element[f]; }
1104
 
);
1105
 
 
1106
 
Element.Methods.visualEffect = function(element, effect, options) {
1107
 
  s = effect.gsub(/_/, '-').camelize();
1108
 
  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1109
 
  new Effect[effect_class](element, options);
1110
 
  return $(element);
1111
 
};
1112
 
 
1113
 
Element.addMethods();