1// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) 2// Contributors: 3// Justin Palmer (http://encytemedia.com/) 4// Mark Pilgrim (http://diveintomark.org/) 5// Martin Bialasinki 6// 7// See scriptaculous.js for full license. 8 9// converts rgb() and #xxx to #xxxxxx format, 10// returns self (or first argument) if not convertable 11String.prototype.parseColor = function() { 12 var color = '#'; 13 if(this.slice(0,4) == 'rgb(') { 14 var cols = this.slice(4,this.length-1).split(','); 15 var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); 16 } else { 17 if(this.slice(0,1) == '#') { 18 if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); 19 if(this.length==7) color = this.toLowerCase(); 20 } 21 } 22 return(color.length==7 ? color : (arguments[0] || this)); 23} 24 25/*--------------------------------------------------------------------------*/ 26 27Element.collectTextNodes = function(element) { 28 return $A($(element).childNodes).collect( function(node) { 29 return (node.nodeType==3 ? node.nodeValue : 30 (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); 31 }).flatten().join(''); 32} 33 34Element.collectTextNodesIgnoreClass = function(element, className) { 35 return $A($(element).childNodes).collect( function(node) { 36 return (node.nodeType==3 ? node.nodeValue : 37 ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 38 Element.collectTextNodesIgnoreClass(node, className) : '')); 39 }).flatten().join(''); 40} 41 42Element.setContentZoom = function(element, percent) { 43 element = $(element); 44 Element.setStyle(element, {fontSize: (percent/100) + 'em'}); 45 if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); 46} 47 48Element.getOpacity = function(element){ 49 var opacity; 50 if (opacity = Element.getStyle(element, 'opacity')) 51 return parseFloat(opacity); 52 if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/)) 53 if(opacity[1]) return parseFloat(opacity[1]) / 100; 54 return 1.0; 55} 56 57Element.setOpacity = function(element, value){ 58 element= $(element); 59 if (value == 1){ 60 Element.setStyle(element, { opacity: 61 (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 62 0.999999 : null }); 63 if(/MSIE/.test(navigator.userAgent)) 64 Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); 65 } else { 66 if(value < 0.00001) value = 0; 67 Element.setStyle(element, {opacity: value}); 68 if(/MSIE/.test(navigator.userAgent)) 69 Element.setStyle(element, 70 { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + 71 'alpha(opacity='+value*100+')' }); 72 } 73} 74 75Element.getInlineOpacity = function(element){ 76 return $(element).style.opacity || ''; 77} 78 79Element.childrenWithClassName = function(element, className, findFirst) { 80 return [$A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { 81 return c.className ? Element.hasClassName(c, className) : false; 82 })].flatten(); 83} 84 85Element.forceRerendering = function(element) { 86 try { 87 element = $(element); 88 var n = document.createTextNode(' '); 89 element.appendChild(n); 90 element.removeChild(n); 91 } catch(e) { } 92}; 93 94['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', 95 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each( 96 function(f) { Element.Methods[f] = Element[f]; } 97); 98 99/*--------------------------------------------------------------------------*/ 100 101Array.prototype.call = function() { 102 var args = arguments; 103 this.each(function(f){ f.apply(this, args) }); 104} 105 106/*--------------------------------------------------------------------------*/ 107 108var Effect = { 109 tagifyText: function(element) { 110 var tagifyStyle = 'position:relative'; 111 if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1'; 112 element = $(element); 113 $A(element.childNodes).each( function(child) { 114 if(child.nodeType==3) {
115 child.nodeValue.toArray().each( function(character) { 116 element.insertBefore( 117 Builder.node('span',{style: tagifyStyle}, 118 character == ' ' ? String.fromCharCode(160) : character), 119 child); 120 }); 121 Element.remove(child); 122 } 123 }); 124 }, 125 multiple: function(element, effect) { 126 var elements; 127 if(((typeof element == 'object') || 128 (typeof element == 'function')) && 129 (element.length)) 130 elements = element; 131 else 132 elements = $(element).childNodes; 133 134 var options = Object.extend({ 135 speed: 0.1, 136 delay: 0.0 137 }, arguments[2] || {}); 138 var masterDelay = options.delay; 139 140 $A(elements).each( function(element, index) { 141 new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); 142 }); 143 }, 144 PAIRS: { 145 'slide': ['SlideDown','SlideUp'], 146 'blind': ['BlindDown','BlindUp'], 147 'appear': ['Appear','Fade'] 148 }, 149 toggle: function(element, effect) { 150 element = $(element); 151 effect = (effect || 'appear').toLowerCase(); 152 var options = Object.extend({ 153 queue: { position:'end', scope:(element.id || 'global'), limit: 1 } 154 }, arguments[2] || {}); 155 Effect[element.visible() ? 156 Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); 157 } 158}; 159 160var Effect2 = Effect; // deprecated 161 162/* ------------- transitions ------------- */ 163 164Effect.Transitions = {} 165 166Effect.Transitions.linear = function(pos) { 167 return pos; 168} 169Effect.Transitions.sinoidal = function(pos) { 170 return (-Math.cos(pos*Math.PI)/2) + 0.5; 171} 172Effect.Transitions.reverse = function(pos) { 173 return 1-pos; 174} 175Effect.Transitions.flicker = function(pos) { 176 return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; 177} 178Effect.Transitions.wobble = function(pos) { 179 return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; 180} 181Effect.Transitions.pulse = function(pos) { 182 return (Math.floor(pos*10) % 2 == 0 ? 183 (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); 184} 185Effect.Transitions.none = function(pos) { 186 return 0; 187} 188Effect.Transitions.full = function(pos) { 189 return 1; 190} 191 192/* ------------- core effects ------------- */ 193 194Effect.ScopedQueue = Class.create(); 195Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { 196 initialize: function() { 197 this.effects = []; 198 this.interval = null; 199 }, 200 _each: function(iterator) { 201 this.effects._each(iterator); 202 }, 203 add: function(effect) { 204 var timestamp = new Date().getTime(); 205 206 var position = (typeof effect.options.queue == 'string') ? 207 effect.options.queue : effect.options.queue.position; 208 209 switch(position) { 210 case 'front': 211 // move unstarted effects after this effect 212 this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { 213 e.startOn += effect.finishOn; 214 e.finishOn += effect.finishOn; 215 }); 216 break; 217 case 'end': 218 // start effect after last queued effect has finished 219 timestamp = this.effects.pluck('finishOn').max() || timestamp; 220 break; 221 } 222 223 effect.startOn += timestamp; 224 effect.finishOn += timestamp; 225 226 if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) 227 this.effects.push(effect); 228 229 if(!this.interval) 230 this.interval = setInterval(this.loop.bind(this), 40); 231 }, 232 remove: function(effect) { 233 this.effects = this.effects.reject(function(e) { return e==effect }); 234 if(this.effects.length == 0) { 235 clearInterval(this.interval); 236 this.interval = null; 237 } 238 }, 239 loop: function() { 240 var timePos = new Date().getTime(); 241 this.effects.invoke('loop', timePos); 242 } 243}); 244 245Effect.Queues = { 246 instances: $H(), 247 get: function(queueName) { 248 if(typeof queueName != 'string') return queueName; 249 250 if(!this.instances[queueName]) 251 this.instances[queueName] = new Effect.ScopedQueue(); 252 253 return this.instances[queueName]; 254 } 255} 256Effect.Queue = Effect.Queues.get('global'); 257 258Effect.DefaultOptions = { 259 transition: Effect.Transitions.sinoidal, 260 duration: 1.0, // seconds 261 fps: 25.0, // max. 25fps due to Effect.Queue implementation 262 sync: false, // true for combining 263 from: 0.0, 264 to: 1.0, 265 delay: 0.0, 266 queue: 'parallel' 267} 268 269Effect.Base = function() {}; 270Effect.Base.prototype = { 271 position: null, 272 start: function(options) { 273 this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); 274 this.currentFrame = 0; 275 this.state = 'idle'; 276 this.startOn = this.options.delay*1000; 277 this.finishOn = this.startOn + (this.options.duration*1000); 278 this.event('beforeStart'); 279 if(!this.options.sync)
280 Effect.Queues.get(typeof this.options.queue == 'string' ? 281 'global' : this.options.queue.scope).add(this); 282 }, 283 loop: function(timePos) { 284 if(timePos >= this.startOn) { 285 if(timePos >= this.finishOn) { 286 this.render(1.0); 287 this.cancel(); 288 this.event('beforeFinish'); 289 if(this.finish) this.finish(); 290 this.event('afterFinish'); 291 return; 292 } 293 var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); 294 var frame = Math.round(pos * this.options.fps * this.options.duration); 295 if(frame > this.currentFrame) { 296 this.render(pos); 297 this.currentFrame = frame; 298 } 299 } 300 }, 301 render: function(pos) { 302 if(this.state == 'idle') { 303 this.state = 'running'; 304 this.event('beforeSetup'); 305 if(this.setup) this.setup(); 306 this.event('afterSetup'); 307 } 308 if(this.state == 'running') { 309 if(this.options.transition) pos = this.options.transition(pos); 310 pos *= (this.options.to-this.options.from); 311 pos += this.options.from; 312 this.position = pos; 313 this.event('beforeUpdate'); 314 if(this.update) this.update(pos); 315 this.event('afterUpdate'); 316 } 317 }, 318 cancel: function() { 319 if(!this.options.sync) 320 Effect.Queues.get(typeof this.options.queue == 'string' ? 321 'global' : this.options.queue.scope).remove(this); 322 this.state = 'finished'; 323 }, 324 event: function(eventName) { 325 if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); 326 if(this.options[eventName]) this.options[eventName](this); 327 }, 328 inspect: function() { 329 return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>'; 330 } 331} 332 333Effect.Parallel = Class.create(); 334Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { 335 initialize: function(effects) { 336 this.effects = effects || []; 337 this.start(arguments[1]); 338 }, 339 update: function(position) { 340 this.effects.invoke('render', position); 341 }, 342 finish: function(position) { 343 this.effects.each( function(effect) { 344 effect.render(1.0); 345 effect.cancel(); 346 effect.event('beforeFinish'); 347 if(effect.finish) effect.finish(position); 348 effect.event('afterFinish'); 349 }); 350 } 351}); 352 353Effect.Opacity = Class.create(); 354Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { 355 initialize: function(element) { 356 this.element = $(element); 357 // make this work on IE on elements without 'layout' 358 if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout)) 359 this.element.setStyle({zoom: 1}); 360 var options = Object.extend({ 361 from: this.element.getOpacity() || 0.0, 362 to: 1.0 363 }, arguments[1] || {}); 364 this.start(options); 365 }, 366 update: function(position) { 367 this.element.setOpacity(position); 368 } 369}); 370 371Effect.Move = Class.create(); 372Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { 373 initialize: function(element) { 374 this.element = $(element); 375 var options = Object.extend({ 376 x: 0, 377 y: 0, 378 mode: 'relative' 379 }, arguments[1] || {}); 380 this.start(options); 381 }, 382 setup: function() { 383 // Bug in Opera: Opera returns the "real" position of a static element or 384 // relative element that does not have top/left explicitly set. 385 // ==> Always set top and left for position relative elements in your stylesheets 386 // (to 0 if you do not need them) 387 this.element.makePositioned(); 388 this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); 389 this.originalTop = parseFloat(this.element.getStyle('top') || '0'); 390 if(this.options.mode == 'absolute') { 391 // absolute movement, so we need to calc deltaX and deltaY 392 this.options.x = this.options.x - this.originalLeft; 393 this.options.y = this.options.y - this.originalTop; 394 } 395 }, 396 update: function(position) { 397 this.element.setStyle({ 398 left: this.options.x * position + this.originalLeft + 'px', 399 top: this.options.y * position + this.originalTop + 'px' 400 }); 401 } 402}); 403 404// for backwards compatibility 405Effect.MoveBy = function(element, toTop, toLeft) { 406 return new Effect.Move(element, 407 Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); 408}; 409 410Effect.Scale = Class.create(); 411Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { 412 initialize: function(element, percent) { 413 this.element = $(element) 414 var options = Object.extend({ 415 scaleX: true, 416 scaleY: true, 417 scaleContent: true, 418 scaleFromCenter: false, 419 scaleMode: 'box', // 'box' or 'contents' or {} with provided values 420 scaleFrom: 100.0, 421 scaleTo: percent 422 }, arguments[2] || {}); 423 this.start(options); 424 }, 425 setup: function() { 426 this.restoreAfterFinish = this.options.restoreAfterFinish || false; 427 this.elementPositioning = this.element.getStyle('position'); 428 429 this.originalStyle = {}; 430 ['top','left','width','height','fontSize'].each( function(k) { 431 this.originalStyle[k] = this.element.style[k]; 432 }.bind(this)); 433 434 this.originalTop = this.element.offsetTop; 435 this.originalLeft = this.element.offsetLeft; 436 437 var fontSize = this.element.getStyle('font-size') || '100%'; 438 ['em','px','%'].each( function(fontSizeType) { 439 if(fontSize.indexOf(fontSizeType)>0) { 440 this.fontSize = parseFloat(fontSize); 441 this.fontSizeType = fontSizeType; 442 } 443 }.bind(this)); 444 445 this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; 446 447 this.dims = null; 448 if(this.options.scaleMode=='box') 449 this.dims = [this.element.offsetHeight, this.element.offsetWidth]; 450 if(/^content/.test(this.options.scaleMode)) 451 this.dims = [this.element.scrollHeight, this.element.scrollWidth]; 452 if(!this.dims) 453 this.dims = [this.options.scaleMode.originalHeight, 454 this.options.scaleMode.originalWidth]; 455 }, 456 update: function(position) { 457 var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); 458 if(this.options.scaleContent && this.fontSize) 459 this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); 460 this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); 461 }, 462 finish: function(position) { 463 if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); 464 }, 465 setDimensions: function(height, width) { 466 var d = {}; 467 if(this.options.scaleX) d.width = width + 'px'; 468 if(this.options.scaleY) d.height = height + 'px'; 469 if(this.options.scaleFromCenter) { 470 var topd = (height - this.dims[0])/2; 471 var leftd = (width - this.dims[1])/2; 472 if(this.elementPositioning == 'absolute') { 473 if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; 474 if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; 475 } else { 476 if(this.options.scaleY) d.top = -topd + 'px'; 477 if(this.options.scaleX) d.left = -leftd + 'px'; 478 } 479 } 480 this.element.setStyle(d); 481 } 482}); 483 484Effect.Highlight = Class.create(); 485Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { 486 initialize: function(element) { 487 this.element = $(element); 488 var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); 489 this.start(options); 490 }, 491 setup: function() { 492 // Prevent executing on elements not in the layout flow 493 if(this.element.getStyle('display')=='none') { this.cancel(); return; } 494 // Disable background image during the effect
495 this.oldStyle = { 496 backgroundImage: this.element.getStyle('background-image') }; 497 this.element.setStyle({backgroundImage: 'none'}); 498 if(!this.options.endcolor) 499 this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); 500 if(!this.options.restorecolor) 501 this.options.restorecolor = this.element.getStyle('background-color'); 502 // init color calculations 503 this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); 504 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)); 505 }, 506 update: function(position) { 507 this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ 508 return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); 509 }, 510 finish: function() { 511 this.element.setStyle(Object.extend(this.oldStyle, { 512 backgroundColor: this.options.restorecolor 513 })); 514 } 515}); 516 517Effect.ScrollTo = Class.create(); 518Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { 519 initialize: function(element) { 520 this.element = $(element); 521 this.start(arguments[1] || {}); 522 }, 523 setup: function() { 524 Position.prepare(); 525 var offsets = Position.cumulativeOffset(this.element); 526 if(this.options.offset) offsets[1] += this.options.offset; 527 var max = window.innerHeight ? 528 window.height - window.innerHeight : 529 document.body.scrollHeight - 530 (document.documentElement.clientHeight ? 531 document.documentElement.clientHeight : document.body.clientHeight); 532 this.scrollStart = Position.deltaY; 533 this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; 534 }, 535 update: function(position) { 536 Position.prepare(); 537 window.scrollTo(Position.deltaX, 538 this.scrollStart + (position*this.delta)); 539 } 540}); 541 542/* ------------- combination effects ------------- */ 543 544Effect.Fade = function(element) { 545 element = $(element); 546 var oldOpacity = element.getInlineOpacity(); 547 var options = Object.extend({ 548 from: element.getOpacity() || 1.0, 549 to: 0.0, 550 afterFinishInternal: function(effect) { 551 if(effect.options.to!=0) return; 552 effect.element.hide(); 553 effect.element.setStyle({opacity: oldOpacity}); 554 }}, arguments[1] || {}); 555 return new Effect.Opacity(element,options); 556} 557 558Effect.Appear = function(element) { 559 element = $(element); 560 var options = Object.extend({ 561 from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), 562 to: 1.0, 563 // force Safari to render floated elements properly 564 afterFinishInternal: function(effect) { 565 effect.element.forceRerendering(); 566 }, 567 beforeSetup: function(effect) { 568 effect.element.setOpacity(effect.options.from); 569 effect.element.show(); 570 }}, arguments[1] || {}); 571 return new Effect.Opacity(element,options); 572} 573 574Effect.Puff = function(element) { 575 element = $(element); 576 var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') }; 577 return new Effect.Parallel( 578 [ new Effect.Scale(element, 200, 579 { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 580 new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 581 Object.extend({ duration: 1.0, 582 beforeSetupInternal: function(effect) { 583 effect.effects[0].element.setStyle({position: 'absolute'}); }, 584 afterFinishInternal: function(effect) { 585 effect.effects[0].element.hide(); 586 effect.effects[0].element.setStyle(oldStyle); } 587 }, arguments[1] || {}) 588 ); 589} 590 591Effect.BlindUp = function(element) { 592 element = $(element); 593 element.makeClipping(); 594 return new Effect.Scale(element, 0, 595 Object.extend({ scaleContent: false, 596 scaleX: false, 597 restoreAfterFinish: true, 598 afterFinishInternal: function(effect) { 599 effect.element.hide(); 600 effect.element.undoClipping(); 601 } 602 }, arguments[1] || {}) 603 ); 604} 605 606Effect.BlindDown = function(element) { 607 element = $(element); 608 var elementDimensions = element.getDimensions(); 609 return new Effect.Scale(element, 100, 610 Object.extend({ scaleContent: false, 611 scaleX: false, 612 scaleFrom: 0, 613 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, 614 restoreAfterFinish: true, 615 afterSetup: function(effect) { 616 effect.element.makeClipping(); 617 effect.element.setStyle({height: '0px'}); 618 effect.element.show(); 619 }, 620 afterFinishInternal: function(effect) { 621 effect.element.undoClipping(); 622 } 623 }, arguments[1] || {}) 624 ); 625} 626 627Effect.SwitchOff = function(element) { 628 element = $(element); 629 var oldOpacity = element.getInlineOpacity(); 630 return new Effect.Appear(element, { 631 duration: 0.4, 632 from: 0, 633 transition: Effect.Transitions.flicker, 634 afterFinishInternal: function(effect) { 635 new Effect.Scale(effect.element, 1, { 636 duration: 0.3, scaleFromCenter: true, 637 scaleX: false, scaleContent: false, restoreAfterFinish: true, 638 beforeSetup: function(effect) { 639 effect.element.makePositioned(); 640 effect.element.makeClipping(); 641 }, 642 afterFinishInternal: function(effect) { 643 effect.element.hide(); 644 effect.element.undoClipping(); 645 effect.element.undoPositioned(); 646 effect.element.setStyle({opacity: oldOpacity}); 647 } 648 }) 649 } 650 }); 651} 652 653Effect.DropOut = function(element) { 654 element = $(element); 655 var oldStyle = { 656 top: element.getStyle('top'), 657 left: element.getStyle('left'), 658 opacity: element.getInlineOpacity() }; 659 return new Effect.Parallel( 660 [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 661 new Effect.Opacity(element, { sync: true, to: 0.0 }) ], 662 Object.extend( 663 { duration: 0.5, 664 beforeSetup: function(effect) { 665 effect.effects[0].element.makePositioned(); 666 }, 667 afterFinishInternal: function(effect) { 668 effect.effects[0].element.hide(); 669 effect.effects[0].element.undoPositioned(); 670 effect.effects[0].element.setStyle(oldStyle); 671 } 672 }, arguments[1] || {})); 673} 674 675Effect.Shake = function(element) { 676 element = $(element); 677 var oldStyle = { 678 top: element.getStyle('top'), 679 left: element.getStyle('left') }; 680 return new Effect.Move(element, 681 { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { 682 new Effect.Move(effect.element, 683 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { 684 new Effect.Move(effect.element, 685 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { 686 new Effect.Move(effect.element, 687 { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { 688 new Effect.Move(effect.element, 689 { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { 690 new Effect.Move(effect.element, 691 { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { 692 effect.element.undoPositioned(); 693 effect.element.setStyle(oldStyle); 694 }}) }}) }}) }}) }}) }}); 695} 696 697Effect.SlideDown = function(element) { 698 element = $(element); 699 element.cleanWhitespace(); 700 // SlideDown need to have the content of the element wrapped in a container element with fixed height! 701 var oldInnerBottom = $(element.firstChild).getStyle('bottom'); 702 var elementDimensions = element.getDimensions(); 703 return new Effect.Scale(element, 100, Object.extend({ 704 scaleContent: false, 705 scaleX: false, 706 scaleFrom: 0, 707 scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, 708 restoreAfterFinish: true, 709 afterSetup: function(effect) { 710 effect.element.makePositioned(); 711 effect.element.firstChild.makePositioned(); 712 if(window.opera) effect.element.setStyle({top: ''}); 713 effect.element.makeClipping(); 714 effect.element.setStyle({height: '0px'}); 715 effect.element.show(); }, 716 afterUpdateInternal: function(effect) { 717 effect.element.firstChild.setStyle({bottom: 718 (effect.dims[0] - effect.element.clientHeight) + 'px' }); 719 }, 720 afterFinishInternal: function(effect) { 721 effect.element.undoClipping(); 722 // IE will crash if child is undoPositioned first 723 if(/MSIE/.test(navigator.userAgent)){ 724 effect.element.undoPositioned(); 725 effect.element.firstChild.undoPositioned(); 726 }else{ 727 effect.element.firstChild.undoPositioned(); 728 effect.element.undoPositioned(); 729 } 730 effect.element.firstChild.setStyle({bottom: oldInnerBottom}); } 731 }, arguments[1] || {}) 732 ); 733} 734 735Effect.SlideUp = function(element) { 736 element = $(element); 737 element.cleanWhitespace(); 738 var oldInnerBottom = $(element.firstChild).getStyle('bottom'); 739 return new Effect.Scale(element, 0, 740 Object.extend({ scaleContent: false, 741 scaleX: false, 742 scaleMode: 'box', 743 scaleFrom: 100, 744 restoreAfterFinish: true, 745 beforeStartInternal: function(effect) { 746 effect.element.makePositioned(); 747 effect.element.firstChild.makePositioned(); 748 if(window.opera) effect.element.setStyle({top: ''}); 749 effect.element.makeClipping(); 750 effect.element.show(); }, 751 afterUpdateInternal: function(effect) { 752 effect.element.firstChild.setStyle({bottom: 753 (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, 754 afterFinishInternal: function(effect) { 755 effect.element.hide(); 756 effect.element.undoClipping(); 757 effect.element.firstChild.undoPositioned(); 758 effect.element.undoPositioned(); 759 effect.element.setStyle({bottom: oldInnerBottom}); } 760 }, arguments[1] || {}) 761 ); 762} 763 764// Bug in opera makes the TD containing this element expand for a instance after finish 765Effect.Squish = function(element) { 766 return new Effect.Scale(element, window.opera ? 1 : 0, 767 { restoreAfterFinish: true, 768 beforeSetup: function(effect) { 769 effect.element.makeClipping(effect.element); }, 770 afterFinishInternal: function(effect) { 771 effect.element.hide(effect.element); 772 effect.element.undoClipping(effect.element); } 773 }); 774} 775 776Effect.Grow = function(element) { 777 element = $(element); 778 var options = Object.extend({ 779 direction: 'center', 780 moveTransition: Effect.Transitions.sinoidal, 781 scaleTransition: Effect.Transitions.sinoidal, 782 opacityTransition: Effect.Transitions.full 783 }, arguments[1] || {}); 784 var oldStyle = { 785 top: element.style.top, 786 left: element.style.left, 787 height: element.style.height, 788 width: element.style.width, 789 opacity: element.getInlineOpacity() }; 790 791 var dims = element.getDimensions(); 792 var initialMoveX, initialMoveY; 793 var moveX, moveY; 794 795 switch (options.direction) { 796 case 'top-left': 797 initialMoveX = initialMoveY = moveX = moveY = 0; 798 break; 799 case 'top-right': 800 initialMoveX = dims.width; 801 initialMoveY = moveY = 0; 802 moveX = -dims.width; 803 break; 804 case 'bottom-left': 805 initialMoveX = moveX = 0; 806 initialMoveY = dims.height; 807 moveY = -dims.height; 808 break; 809 case 'bottom-right': 810 initialMoveX = dims.width; 811 initialMoveY = dims.height; 812 moveX = -dims.width; 813 moveY = -dims.height; 814 break; 815 case 'center': 816 initialMoveX = dims.width / 2; 817 initialMoveY = dims.height / 2; 818 moveX = -dims.width / 2; 819 moveY = -dims.height / 2; 820 break; 821 } 822 823 return new Effect.Move(element, { 824 x: initialMoveX, 825 y: initialMoveY, 826 duration: 0.01, 827 beforeSetup: function(effect) { 828 effect.element.hide(); 829 effect.element.makeClipping(); 830 effect.element.makePositioned(); 831 }, 832 afterFinishInternal: function(effect) { 833 new Effect.Parallel( 834 [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), 835 new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), 836 new Effect.Scale(effect.element, 100, { 837 scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 838 sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) 839 ], Object.extend({ 840 beforeSetup: function(effect) { 841 effect.effects[0].element.setStyle({height: '0px'}); 842 effect.effects[0].element.show(); 843 }, 844 afterFinishInternal: function(effect) { 845 effect.effects[0].element.undoClipping(); 846 effect.effects[0].element.undoPositioned(); 847 effect.effects[0].element.setStyle(oldStyle); 848 } 849 }, options) 850 ) 851 } 852 }); 853} 854 855Effect.Shrink = function(element) { 856 element = $(element); 857 var options = Object.extend({ 858 direction: 'center', 859 moveTransition: Effect.Transitions.sinoidal, 860 scaleTransition: Effect.Transitions.sinoidal, 861 opacityTransition: Effect.Transitions.none 862 }, arguments[1] || {}); 863 var oldStyle = { 864 top: element.style.top, 865 left: element.style.left, 866 height: element.style.height, 867 width: element.style.width, 868 opacity: element.getInlineOpacity() }; 869 870 var dims = element.getDimensions(); 871 var moveX, moveY; 872 873 switch (options.direction) { 874 case 'top-left': 875 moveX = moveY = 0; 876 break; 877 case 'top-right': 878 moveX = dims.width; 879 moveY = 0; 880 break; 881 case 'bottom-left': 882 moveX = 0; 883 moveY = dims.height; 884 break; 885 case 'bottom-right': 886 moveX = dims.width; 887 moveY = dims.height; 888 break; 889 case 'center': 890 moveX = dims.width / 2; 891 moveY = dims.height / 2; 892 break; 893 } 894 895 return new Effect.Parallel( 896 [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), 897 new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), 898 new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) 899 ], Object.extend({ 900 beforeStartInternal: function(effect) { 901 effect.effects[0].element.makePositioned(); 902 effect.effects[0].element.makeClipping(); }, 903 afterFinishInternal: function(effect) { 904 effect.effects[0].element.hide(); 905 effect.effects[0].element.undoClipping(); 906 effect.effects[0].element.undoPositioned(); 907 effect.effects[0].element.setStyle(oldStyle); } 908 }, options) 909 ); 910} 911 912Effect.Pulsate = function(element) { 913 element = $(element); 914 var options = arguments[1] || {}; 915 var oldOpacity = element.getInlineOpacity();
916 var transition = options.transition || Effect.Transitions.sinoidal; 917 var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; 918 reverser.bind(transition); 919 return new Effect.Opacity(element, 920 Object.extend(Object.extend({ duration: 3.0, from: 0, 921 afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } 922 }, options), {transition: reverser})); 923} 924 925Effect.Fold = function(element) { 926 element = $(element); 927 var oldStyle = { 928 top: element.style.top, 929 left: element.style.left, 930 width: element.style.width, 931 height: element.style.height }; 932 Element.makeClipping(element); 933 return new Effect.Scale(element, 5, Object.extend({ 934 scaleContent: false, 935 scaleX: false, 936 afterFinishInternal: function(effect) { 937 new Effect.Scale(element, 1, { 938 scaleContent: false, 939 scaleY: false, 940 afterFinishInternal: function(effect) { 941 effect.element.hide(); 942 effect.element.undoClipping(); 943 effect.element.setStyle(oldStyle); 944 } }); 945 }}, arguments[1] || {})); 946} 947 948Element.Methods.visualEffect = function(element, effect, options) { 949 s = effect.gsub(/_/, '-').camelize(); 950 effect_class = s.charAt(0).toUpperCase() + s.substring(1); 951 new Effect[effect_class](element, options); 952 return $(element); 953};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.