annotate public/javascripts/effects.js @ 8:0c83d98252d9 yuya

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