1
// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
3
// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
5
// Justin Palmer (http://encytemedia.com/)
6
// Mark Pilgrim (http://diveintomark.org/)
9
// script.aculo.us is freely distributable under the terms of an MIT-style license.
10
// For details, see the script.aculo.us web site: http://script.aculo.us/
12
// converts rgb() and #xxx to #xxxxxx format,
13
// returns self (or first argument) if not convertable
14
String.prototype.parseColor = function() {
16
if(this.slice(0,4) == 'rgb(') {
17
var cols = this.slice(4,this.length-1).split(',');
18
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
20
if(this.slice(0,1) == '#') {
21
if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
22
if(this.length==7) color = this.toLowerCase();
25
return(color.length==7 ? color : (arguments[0] || this));
28
/*--------------------------------------------------------------------------*/
30
Element.collectTextNodes = function(element) {
31
return $A($(element).childNodes).collect( function(node) {
32
return (node.nodeType==3 ? node.nodeValue :
33
(node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
34
}).flatten().join('');
37
Element.collectTextNodesIgnoreClass = function(element, className) {
38
return $A($(element).childNodes).collect( function(node) {
39
return (node.nodeType==3 ? node.nodeValue :
40
((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
41
Element.collectTextNodesIgnoreClass(node, className) : ''));
42
}).flatten().join('');
45
Element.setContentZoom = function(element, percent) {
47
element.setStyle({fontSize: (percent/100) + 'em'});
48
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
52
Element.getOpacity = function(element){
53
return $(element).getStyle('opacity');
56
Element.setOpacity = function(element, value){
57
return $(element).setStyle({opacity:value});
60
Element.getInlineOpacity = function(element){
61
return $(element).style.opacity || '';
64
Element.forceRerendering = function(element) {
67
var n = document.createTextNode(' ');
68
element.appendChild(n);
69
element.removeChild(n);
73
/*--------------------------------------------------------------------------*/
75
Array.prototype.call = function() {
77
this.each(function(f){ f.apply(this, args) });
80
/*--------------------------------------------------------------------------*/
83
_elementDoesNotExistError: {
84
name: 'ElementDoesNotExistError',
85
message: 'The specified DOM element does not exist, but is required for this effect to operate'
87
tagifyText: function(element) {
88
if(typeof Builder == 'undefined')
89
throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
91
var tagifyStyle = 'position:relative';
92
if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
95
$A(element.childNodes).each( function(child) {
96
if(child.nodeType==3) {
97
child.nodeValue.toArray().each( function(character) {
99
Builder.node('span',{style: tagifyStyle},
100
character == ' ' ? String.fromCharCode(160) : character),
103
Element.remove(child);
107
multiple: function(element, effect) {
109
if(((typeof element == 'object') ||
110
(typeof element == 'function')) &&
114
elements = $(element).childNodes;
116
var options = Object.extend({
119
}, arguments[2] || {});
120
var masterDelay = options.delay;
122
$A(elements).each( function(element, index) {
123
new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
127
'slide': ['SlideDown','SlideUp'],
128
'blind': ['BlindDown','BlindUp'],
129
'appear': ['Appear','Fade']
131
toggle: function(element, effect) {
132
element = $(element);
133
effect = (effect || 'appear').toLowerCase();
134
var options = Object.extend({
135
queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
136
}, arguments[2] || {});
137
Effect[element.visible() ?
138
Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
142
var Effect2 = Effect; // deprecated
144
/* ------------- transitions ------------- */
146
Effect.Transitions = {
148
sinoidal: function(pos) {
149
return (-Math.cos(pos*Math.PI)/2) + 0.5;
151
reverse: function(pos) {
154
flicker: function(pos) {
155
return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
157
wobble: function(pos) {
158
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
160
pulse: function(pos, pulses) {
161
pulses = pulses || 5;
163
Math.round((pos % (1/pulses)) * pulses) == 0 ?
164
((pos * pulses * 2) - Math.floor(pos * pulses * 2)) :
165
1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
168
none: function(pos) {
171
full: function(pos) {
176
/* ------------- core effects ------------- */
178
Effect.ScopedQueue = Class.create();
179
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
180
initialize: function() {
182
this.interval = null;
184
_each: function(iterator) {
185
this.effects._each(iterator);
187
add: function(effect) {
188
var timestamp = new Date().getTime();
190
var position = (typeof effect.options.queue == 'string') ?
191
effect.options.queue : effect.options.queue.position;
195
// move unstarted effects after this effect
196
this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
197
e.startOn += effect.finishOn;
198
e.finishOn += effect.finishOn;
202
timestamp = this.effects.pluck('startOn').max() || timestamp;
205
// start effect after last queued effect has finished
206
timestamp = this.effects.pluck('finishOn').max() || timestamp;
210
effect.startOn += timestamp;
211
effect.finishOn += timestamp;
213
if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
214
this.effects.push(effect);
217
this.interval = setInterval(this.loop.bind(this), 15);
219
remove: function(effect) {
220
this.effects = this.effects.reject(function(e) { return e==effect });
221
if(this.effects.length == 0) {
222
clearInterval(this.interval);
223
this.interval = null;
227
var timePos = new Date().getTime();
228
for(var i=0, len=this.effects.length;i<len;i++)
229
if(this.effects[i]) this.effects[i].loop(timePos);
235
get: function(queueName) {
236
if(typeof queueName != 'string') return queueName;
238
if(!this.instances[queueName])
239
this.instances[queueName] = new Effect.ScopedQueue();
241
return this.instances[queueName];
244
Effect.Queue = Effect.Queues.get('global');
246
Effect.DefaultOptions = {
247
transition: Effect.Transitions.sinoidal,
248
duration: 1.0, // seconds
249
fps: 60.0, // max. 60fps due to Effect.Queue implementation
250
sync: false, // true for combining
257
Effect.Base = function() {};
258
Effect.Base.prototype = {
260
start: function(options) {
261
this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
262
this.currentFrame = 0;
264
this.startOn = this.options.delay*1000;
265
this.finishOn = this.startOn + (this.options.duration*1000);
266
this.event('beforeStart');
267
if(!this.options.sync)
268
Effect.Queues.get(typeof this.options.queue == 'string' ?
269
'global' : this.options.queue.scope).add(this);
271
loop: function(timePos) {
272
if(timePos >= this.startOn) {
273
if(timePos >= this.finishOn) {
276
this.event('beforeFinish');
277
if(this.finish) this.finish();
278
this.event('afterFinish');
281
var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
282
var frame = Math.round(pos * this.options.fps * this.options.duration);
283
if(frame > this.currentFrame) {
285
this.currentFrame = frame;
289
render: function(pos) {
290
if(this.state == 'idle') {
291
this.state = 'running';
292
this.event('beforeSetup');
293
if(this.setup) this.setup();
294
this.event('afterSetup');
296
if(this.state == 'running') {
297
if(this.options.transition) pos = this.options.transition(pos);
298
pos *= (this.options.to-this.options.from);
299
pos += this.options.from;
301
this.event('beforeUpdate');
302
if(this.update) this.update(pos);
303
this.event('afterUpdate');
307
if(!this.options.sync)
308
Effect.Queues.get(typeof this.options.queue == 'string' ?
309
'global' : this.options.queue.scope).remove(this);
310
this.state = 'finished';
312
event: function(eventName) {
313
if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
314
if(this.options[eventName]) this.options[eventName](this);
316
inspect: function() {
318
for(property in this)
319
if(typeof this[property] != 'function') data[property] = this[property];
320
return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
324
Effect.Parallel = Class.create();
325
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
326
initialize: function(effects) {
327
this.effects = effects || [];
328
this.start(arguments[1]);
330
update: function(position) {
331
this.effects.invoke('render', position);
333
finish: function(position) {
334
this.effects.each( function(effect) {
337
effect.event('beforeFinish');
338
if(effect.finish) effect.finish(position);
339
effect.event('afterFinish');
344
Effect.Event = Class.create();
345
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
346
initialize: function() {
347
var options = Object.extend({
349
}, arguments[0] || {});
352
update: Prototype.emptyFunction
355
Effect.Opacity = Class.create();
356
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
357
initialize: function(element) {
358
this.element = $(element);
359
if(!this.element) throw(Effect._elementDoesNotExistError);
360
// make this work on IE on elements without 'layout'
361
if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
362
this.element.setStyle({zoom: 1});
363
var options = Object.extend({
364
from: this.element.getOpacity() || 0.0,
366
}, arguments[1] || {});
369
update: function(position) {
370
this.element.setOpacity(position);
374
Effect.Move = Class.create();
375
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
376
initialize: function(element) {
377
this.element = $(element);
378
if(!this.element) throw(Effect._elementDoesNotExistError);
379
var options = Object.extend({
383
}, arguments[1] || {});
387
// Bug in Opera: Opera returns the "real" position of a static element or
388
// relative element that does not have top/left explicitly set.
389
// ==> Always set top and left for position relative elements in your stylesheets
390
// (to 0 if you do not need them)
391
this.element.makePositioned();
392
this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
393
this.originalTop = parseFloat(this.element.getStyle('top') || '0');
394
if(this.options.mode == 'absolute') {
395
// absolute movement, so we need to calc deltaX and deltaY
396
this.options.x = this.options.x - this.originalLeft;
397
this.options.y = this.options.y - this.originalTop;
400
update: function(position) {
401
this.element.setStyle({
402
left: Math.round(this.options.x * position + this.originalLeft) + 'px',
403
top: Math.round(this.options.y * position + this.originalTop) + 'px'
408
// for backwards compatibility
409
Effect.MoveBy = function(element, toTop, toLeft) {
410
return new Effect.Move(element,
411
Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
414
Effect.Scale = Class.create();
415
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
416
initialize: function(element, percent) {
417
this.element = $(element);
418
if(!this.element) throw(Effect._elementDoesNotExistError);
419
var options = Object.extend({
423
scaleFromCenter: false,
424
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
427
}, arguments[2] || {});
431
this.restoreAfterFinish = this.options.restoreAfterFinish || false;
432
this.elementPositioning = this.element.getStyle('position');
434
this.originalStyle = {};
435
['top','left','width','height','fontSize'].each( function(k) {
436
this.originalStyle[k] = this.element.style[k];
439
this.originalTop = this.element.offsetTop;
440
this.originalLeft = this.element.offsetLeft;
442
var fontSize = this.element.getStyle('font-size') || '100%';
443
['em','px','%','pt'].each( function(fontSizeType) {
444
if(fontSize.indexOf(fontSizeType)>0) {
445
this.fontSize = parseFloat(fontSize);
446
this.fontSizeType = fontSizeType;
450
this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
453
if(this.options.scaleMode=='box')
454
this.dims = [this.element.offsetHeight, this.element.offsetWidth];
455
if(/^content/.test(this.options.scaleMode))
456
this.dims = [this.element.scrollHeight, this.element.scrollWidth];
458
this.dims = [this.options.scaleMode.originalHeight,
459
this.options.scaleMode.originalWidth];
461
update: function(position) {
462
var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
463
if(this.options.scaleContent && this.fontSize)
464
this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
465
this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
467
finish: function(position) {
468
if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
470
setDimensions: function(height, width) {
472
if(this.options.scaleX) d.width = Math.round(width) + 'px';
473
if(this.options.scaleY) d.height = Math.round(height) + 'px';
474
if(this.options.scaleFromCenter) {
475
var topd = (height - this.dims[0])/2;
476
var leftd = (width - this.dims[1])/2;
477
if(this.elementPositioning == 'absolute') {
478
if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
479
if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
481
if(this.options.scaleY) d.top = -topd + 'px';
482
if(this.options.scaleX) d.left = -leftd + 'px';
485
this.element.setStyle(d);
489
Effect.Highlight = Class.create();
490
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
491
initialize: function(element) {
492
this.element = $(element);
493
if(!this.element) throw(Effect._elementDoesNotExistError);
494
var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
498
// Prevent executing on elements not in the layout flow
499
if(this.element.getStyle('display')=='none') { this.cancel(); return; }
500
// Disable background image during the effect
502
if (!this.options.keepBackgroundImage) {
503
this.oldStyle.backgroundImage = this.element.getStyle('background-image');
504
this.element.setStyle({backgroundImage: 'none'});
506
if(!this.options.endcolor)
507
this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
508
if(!this.options.restorecolor)
509
this.options.restorecolor = this.element.getStyle('background-color');
510
// init color calculations
511
this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
512
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));
514
update: function(position) {
515
this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
516
return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
519
this.element.setStyle(Object.extend(this.oldStyle, {
520
backgroundColor: this.options.restorecolor
525
Effect.ScrollTo = Class.create();
526
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
527
initialize: function(element) {
528
this.element = $(element);
529
this.start(arguments[1] || {});
533
var offsets = Position.cumulativeOffset(this.element);
534
if(this.options.offset) offsets[1] += this.options.offset;
535
var max = window.innerHeight ?
536
window.height - window.innerHeight :
537
document.body.scrollHeight -
538
(document.documentElement.clientHeight ?
539
document.documentElement.clientHeight : document.body.clientHeight);
540
this.scrollStart = Position.deltaY;
541
this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
543
update: function(position) {
545
window.scrollTo(Position.deltaX,
546
this.scrollStart + (position*this.delta));
550
/* ------------- combination effects ------------- */
552
Effect.Fade = function(element) {
553
element = $(element);
554
var oldOpacity = element.getInlineOpacity();
555
var options = Object.extend({
556
from: element.getOpacity() || 1.0,
558
afterFinishInternal: function(effect) {
559
if(effect.options.to!=0) return;
560
effect.element.hide().setStyle({opacity: oldOpacity});
561
}}, arguments[1] || {});
562
return new Effect.Opacity(element,options);
565
Effect.Appear = function(element) {
566
element = $(element);
567
var options = Object.extend({
568
from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
570
// force Safari to render floated elements properly
571
afterFinishInternal: function(effect) {
572
effect.element.forceRerendering();
574
beforeSetup: function(effect) {
575
effect.element.setOpacity(effect.options.from).show();
576
}}, arguments[1] || {});
577
return new Effect.Opacity(element,options);
580
Effect.Puff = function(element) {
581
element = $(element);
583
opacity: element.getInlineOpacity(),
584
position: element.getStyle('position'),
585
top: element.style.top,
586
left: element.style.left,
587
width: element.style.width,
588
height: element.style.height
590
return new Effect.Parallel(
591
[ new Effect.Scale(element, 200,
592
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
593
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
594
Object.extend({ duration: 1.0,
595
beforeSetupInternal: function(effect) {
596
Position.absolutize(effect.effects[0].element)
598
afterFinishInternal: function(effect) {
599
effect.effects[0].element.hide().setStyle(oldStyle); }
600
}, arguments[1] || {})
604
Effect.BlindUp = function(element) {
605
element = $(element);
606
element.makeClipping();
607
return new Effect.Scale(element, 0,
608
Object.extend({ scaleContent: false,
610
restoreAfterFinish: true,
611
afterFinishInternal: function(effect) {
612
effect.element.hide().undoClipping();
614
}, arguments[1] || {})
618
Effect.BlindDown = function(element) {
619
element = $(element);
620
var elementDimensions = element.getDimensions();
621
return new Effect.Scale(element, 100, Object.extend({
625
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
626
restoreAfterFinish: true,
627
afterSetup: function(effect) {
628
effect.element.makeClipping().setStyle({height: '0px'}).show();
630
afterFinishInternal: function(effect) {
631
effect.element.undoClipping();
633
}, arguments[1] || {}));
636
Effect.SwitchOff = function(element) {
637
element = $(element);
638
var oldOpacity = element.getInlineOpacity();
639
return new Effect.Appear(element, Object.extend({
642
transition: Effect.Transitions.flicker,
643
afterFinishInternal: function(effect) {
644
new Effect.Scale(effect.element, 1, {
645
duration: 0.3, scaleFromCenter: true,
646
scaleX: false, scaleContent: false, restoreAfterFinish: true,
647
beforeSetup: function(effect) {
648
effect.element.makePositioned().makeClipping();
650
afterFinishInternal: function(effect) {
651
effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
655
}, arguments[1] || {}));
658
Effect.DropOut = function(element) {
659
element = $(element);
661
top: element.getStyle('top'),
662
left: element.getStyle('left'),
663
opacity: element.getInlineOpacity() };
664
return new Effect.Parallel(
665
[ new Effect.Move(element, {x: 0, y: 100, sync: true }),
666
new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
669
beforeSetup: function(effect) {
670
effect.effects[0].element.makePositioned();
672
afterFinishInternal: function(effect) {
673
effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
675
}, arguments[1] || {}));
678
Effect.Shake = function(element) {
679
element = $(element);
681
top: element.getStyle('top'),
682
left: element.getStyle('left') };
683
return new Effect.Move(element,
684
{ x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
685
new Effect.Move(effect.element,
686
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
687
new Effect.Move(effect.element,
688
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
689
new Effect.Move(effect.element,
690
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
691
new Effect.Move(effect.element,
692
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
693
new Effect.Move(effect.element,
694
{ x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
695
effect.element.undoPositioned().setStyle(oldStyle);
696
}}) }}) }}) }}) }}) }});
699
Effect.SlideDown = function(element) {
700
element = $(element).cleanWhitespace();
701
// SlideDown need to have the content of the element wrapped in a container element with fixed height!
702
var oldInnerBottom = element.down().getStyle('bottom');
703
var elementDimensions = element.getDimensions();
704
return new Effect.Scale(element, 100, Object.extend({
707
scaleFrom: window.opera ? 0 : 1,
708
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
709
restoreAfterFinish: true,
710
afterSetup: function(effect) {
711
effect.element.makePositioned();
712
effect.element.down().makePositioned();
713
if(window.opera) effect.element.setStyle({top: ''});
714
effect.element.makeClipping().setStyle({height: '0px'}).show();
716
afterUpdateInternal: function(effect) {
717
effect.element.down().setStyle({bottom:
718
(effect.dims[0] - effect.element.clientHeight) + 'px' });
720
afterFinishInternal: function(effect) {
721
effect.element.undoClipping().undoPositioned();
722
effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
723
}, arguments[1] || {})
727
Effect.SlideUp = function(element) {
728
element = $(element).cleanWhitespace();
729
var oldInnerBottom = element.down().getStyle('bottom');
730
return new Effect.Scale(element, window.opera ? 0 : 1,
731
Object.extend({ scaleContent: false,
735
restoreAfterFinish: true,
736
beforeStartInternal: function(effect) {
737
effect.element.makePositioned();
738
effect.element.down().makePositioned();
739
if(window.opera) effect.element.setStyle({top: ''});
740
effect.element.makeClipping().show();
742
afterUpdateInternal: function(effect) {
743
effect.element.down().setStyle({bottom:
744
(effect.dims[0] - effect.element.clientHeight) + 'px' });
746
afterFinishInternal: function(effect) {
747
effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
748
effect.element.down().undoPositioned();
750
}, arguments[1] || {})
754
// Bug in opera makes the TD containing this element expand for a instance after finish
755
Effect.Squish = function(element) {
756
return new Effect.Scale(element, window.opera ? 1 : 0, {
757
restoreAfterFinish: true,
758
beforeSetup: function(effect) {
759
effect.element.makeClipping();
761
afterFinishInternal: function(effect) {
762
effect.element.hide().undoClipping();
767
Effect.Grow = function(element) {
768
element = $(element);
769
var options = Object.extend({
771
moveTransition: Effect.Transitions.sinoidal,
772
scaleTransition: Effect.Transitions.sinoidal,
773
opacityTransition: Effect.Transitions.full
774
}, arguments[1] || {});
776
top: element.style.top,
777
left: element.style.left,
778
height: element.style.height,
779
width: element.style.width,
780
opacity: element.getInlineOpacity() };
782
var dims = element.getDimensions();
783
var initialMoveX, initialMoveY;
786
switch (options.direction) {
788
initialMoveX = initialMoveY = moveX = moveY = 0;
791
initialMoveX = dims.width;
792
initialMoveY = moveY = 0;
796
initialMoveX = moveX = 0;
797
initialMoveY = dims.height;
798
moveY = -dims.height;
801
initialMoveX = dims.width;
802
initialMoveY = dims.height;
804
moveY = -dims.height;
807
initialMoveX = dims.width / 2;
808
initialMoveY = dims.height / 2;
809
moveX = -dims.width / 2;
810
moveY = -dims.height / 2;
814
return new Effect.Move(element, {
818
beforeSetup: function(effect) {
819
effect.element.hide().makeClipping().makePositioned();
821
afterFinishInternal: function(effect) {
823
[ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
824
new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
825
new Effect.Scale(effect.element, 100, {
826
scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
827
sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
829
beforeSetup: function(effect) {
830
effect.effects[0].element.setStyle({height: '0px'}).show();
832
afterFinishInternal: function(effect) {
833
effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
841
Effect.Shrink = function(element) {
842
element = $(element);
843
var options = Object.extend({
845
moveTransition: Effect.Transitions.sinoidal,
846
scaleTransition: Effect.Transitions.sinoidal,
847
opacityTransition: Effect.Transitions.none
848
}, arguments[1] || {});
850
top: element.style.top,
851
left: element.style.left,
852
height: element.style.height,
853
width: element.style.width,
854
opacity: element.getInlineOpacity() };
856
var dims = element.getDimensions();
859
switch (options.direction) {
876
moveX = dims.width / 2;
877
moveY = dims.height / 2;
881
return new Effect.Parallel(
882
[ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
883
new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
884
new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
886
beforeStartInternal: function(effect) {
887
effect.effects[0].element.makePositioned().makeClipping();
889
afterFinishInternal: function(effect) {
890
effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
895
Effect.Pulsate = function(element) {
896
element = $(element);
897
var options = arguments[1] || {};
898
var oldOpacity = element.getInlineOpacity();
899
var transition = options.transition || Effect.Transitions.sinoidal;
900
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
901
reverser.bind(transition);
902
return new Effect.Opacity(element,
903
Object.extend(Object.extend({ duration: 2.0, from: 0,
904
afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
905
}, options), {transition: reverser}));
908
Effect.Fold = function(element) {
909
element = $(element);
911
top: element.style.top,
912
left: element.style.left,
913
width: element.style.width,
914
height: element.style.height };
915
element.makeClipping();
916
return new Effect.Scale(element, 5, Object.extend({
919
afterFinishInternal: function(effect) {
920
new Effect.Scale(element, 1, {
923
afterFinishInternal: function(effect) {
924
effect.element.hide().undoClipping().setStyle(oldStyle);
926
}}, arguments[1] || {}));
929
Effect.Morph = Class.create();
930
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
931
initialize: function(element) {
932
this.element = $(element);
933
if(!this.element) throw(Effect._elementDoesNotExistError);
934
var options = Object.extend({
936
}, arguments[1] || {});
937
if (typeof options.style == 'string') {
938
if(options.style.indexOf(':') == -1) {
939
var cssText = '', selector = '.' + options.style;
940
$A(document.styleSheets).reverse().each(function(styleSheet) {
941
if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
942
else if (styleSheet.rules) cssRules = styleSheet.rules;
943
$A(cssRules).reverse().each(function(rule) {
944
if (selector == rule.selectorText) {
945
cssText = rule.style.cssText;
949
if (cssText) throw $break;
951
this.style = cssText.parseStyle();
952
options.afterFinishInternal = function(effect){
953
effect.element.addClassName(effect.options.style);
954
effect.transforms.each(function(transform) {
955
if(transform.style != 'opacity')
956
effect.element.style[transform.style.camelize()] = '';
959
} else this.style = options.style.parseStyle();
960
} else this.style = $H(options.style)
964
function parseColor(color){
965
if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
966
color = color.parseColor();
967
return $R(0,2).map(function(i){
968
return parseInt( color.slice(i*2+1,i*2+3), 16 )
971
this.transforms = this.style.map(function(pair){
972
var property = pair[0].underscore().dasherize(), value = pair[1], unit = null;
974
if(value.parseColor('#zzzzzz') != '#zzzzzz') {
975
value = value.parseColor();
977
} else if(property == 'opacity') {
978
value = parseFloat(value);
979
if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
980
this.element.setStyle({zoom: 1});
981
} else if(Element.CSS_LENGTH.test(value))
982
var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
983
value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;
985
var originalValue = this.element.getStyle(property);
988
originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
989
targetValue: unit=='color' ? parseColor(value) : value,
992
}.bind(this)).reject(function(transform){
994
(transform.originalValue == transform.targetValue) ||
996
transform.unit != 'color' &&
997
(isNaN(transform.originalValue) || isNaN(transform.targetValue))
1002
update: function(position) {
1003
var style = $H(), value = null;
1004
this.transforms.each(function(transform){
1005
value = transform.unit=='color' ?
1006
$R(0,2).inject('#',function(m,v,i){
1007
return m+(Math.round(transform.originalValue[i]+
1008
(transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) :
1009
transform.originalValue + Math.round(
1010
((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
1011
style[transform.style] = value;
1013
this.element.setStyle(style);
1017
Effect.Transform = Class.create();
1018
Object.extend(Effect.Transform.prototype, {
1019
initialize: function(tracks){
1021
this.options = arguments[1] || {};
1022
this.addTracks(tracks);
1024
addTracks: function(tracks){
1025
tracks.each(function(track){
1026
var data = $H(track).values().first();
1027
this.tracks.push($H({
1028
ids: $H(track).keys().first(),
1029
effect: Effect.Morph,
1030
options: { style: data }
1036
return new Effect.Parallel(
1037
this.tracks.map(function(track){
1038
var elements = [$(track.ids) || $$(track.ids)].flatten();
1039
return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1046
Element.CSS_PROPERTIES = $w(
1047
'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
1048
'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1049
'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1050
'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1051
'fontSize fontWeight height left letterSpacing lineHeight ' +
1052
'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1053
'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1054
'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1055
'right textIndent top width wordSpacing zIndex');
1057
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1059
String.prototype.parseStyle = function(){
1060
var element = Element.extend(document.createElement('div'));
1061
element.innerHTML = '<div style="' + this + '"></div>';
1062
var style = element.down().style, styleRules = $H();
1064
Element.CSS_PROPERTIES.each(function(property){
1065
if(style[property]) styleRules[property] = style[property];
1067
if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
1068
styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
1073
Element.morph = function(element, style) {
1074
new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1078
['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
1079
'collectTextNodes','collectTextNodesIgnoreClass','morph'].each(
1080
function(f) { Element.Methods[f] = Element[f]; }
1083
Element.Methods.visualEffect = function(element, effect, options) {
1084
s = effect.gsub(/_/, '-').camelize();
1085
effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1086
new Effect[effect_class](element, options);
1090
Element.addMethods();
b'\\ No newline at end of file'