PHP Cross Reference of WordPress Subversion HEAD

[ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]

title

Body

[close]

/wp-includes/js/scriptaculous/ -> effects.js (source)

   1  // script.aculo.us effects.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007
   2  
   3  // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
   4  // Contributors:
   5  //  Justin Palmer (http://encytemedia.com/)
   6  //  Mark Pilgrim (http://diveintomark.org/)
   7  //  Martin Bialasinki
   8  // 
   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/ 
  11  
  12  // converts rgb() and #xxx to #xxxxxx format,  
  13  // returns self (or first argument) if not convertable  
  14  String.prototype.parseColor = function() {  
  15    var color = '#';
  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);  
  19    } else {  
  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();  
  23      }  
  24    }  
  25    return(color.length==7 ? color : (arguments[0] || this));  
  26  }
  27  
  28  /*--------------------------------------------------------------------------*/
  29  
  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('');
  35  }
  36  
  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('');
  43  }
  44  
  45  Element.setContentZoom = function(element, percent) {
  46    element = $(element);  
  47    element.setStyle({fontSize: (percent/100) + 'em'});   
  48    if(Prototype.Browser.WebKit) window.scrollBy(0,0);
  49    return element;
  50  }
  51  
  52  Element.getInlineOpacity = function(element){
  53    return $(element).style.opacity || '';
  54  }
  55  
  56  Element.forceRerendering = function(element) {
  57    try {
  58      element = $(element);
  59      var n = document.createTextNode(' ');
  60      element.appendChild(n);
  61      element.removeChild(n);
  62    } catch(e) { }
  63  };
  64  
  65  /*--------------------------------------------------------------------------*/
  66  
  67  Array.prototype.call = function() {
  68    var args = arguments;
  69    this.each(function(f){ f.apply(this, args) });
  70  }
  71  
  72  /*--------------------------------------------------------------------------*/
  73  
  74  var Effect = {
  75    _elementDoesNotExistError: {
  76      name: 'ElementDoesNotExistError',
  77      message: 'The specified DOM element does not exist, but is required for this effect to operate'
  78    },
  79    tagifyText: function(element) {
  80      if(typeof Builder == 'undefined')
  81        throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
  82        
  83      var tagifyStyle = 'position:relative';
  84      if(Prototype.Browser.IE) tagifyStyle += ';zoom:1';
  85      
  86      element = $(element);
  87      $A(element.childNodes).each( function(child) {
  88        if(child.nodeType==3) {
  89          child.nodeValue.toArray().each( function(character) {
  90            element.insertBefore(
  91              Builder.node('span',{style: tagifyStyle},
  92                character == ' ' ? String.fromCharCode(160) : character), 
  93                child);
  94          });
  95          Element.remove(child);
  96        }
  97      });
  98    },
  99    multiple: function(element, effect) {
 100      var elements;
 101      if(((typeof element == 'object') || 
 102          (typeof element == 'function')) && 
 103         (element.length))
 104        elements = element;
 105      else
 106        elements = $(element).childNodes;
 107        
 108      var options = Object.extend({
 109        speed: 0.1,
 110        delay: 0.0
 111      }, arguments[2] || {});
 112      var masterDelay = options.delay;
 113  
 114      $A(elements).each( function(element, index) {
 115        new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
 116      });
 117    },
 118    PAIRS: {
 119      'slide':  ['SlideDown','SlideUp'],
 120      'blind':  ['BlindDown','BlindUp'],
 121      'appear': ['Appear','Fade']
 122    },
 123    toggle: function(element, effect) {
 124      element = $(element);
 125      effect = (effect || 'appear').toLowerCase();
 126      var options = Object.extend({
 127        queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
 128      }, arguments[2] || {});
 129      Effect[element.visible() ? 
 130        Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
 131    }
 132  };
 133  
 134  var Effect2 = Effect; // deprecated
 135  
 136  /* ------------- transitions ------------- */
 137  
 138  Effect.Transitions = {
 139    linear: Prototype.K,
 140    sinoidal: function(pos) {
 141      return (-Math.cos(pos*Math.PI)/2) + 0.5;
 142    },
 143    reverse: function(pos) {
 144      return 1-pos;
 145    },
 146    flicker: function(pos) {
 147      var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
 148      return (pos > 1 ? 1 : pos);
 149    },
 150    wobble: function(pos) {
 151      return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
 152    },
 153    pulse: function(pos, pulses) { 
 154      pulses = pulses || 5; 
 155      return (
 156        Math.round((pos % (1/pulses)) * pulses) == 0 ? 
 157              ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
 158          1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
 159        );
 160    },
 161    none: function(pos) {
 162      return 0;
 163    },
 164    full: function(pos) {
 165      return 1;
 166    }
 167  };
 168  
 169  /* ------------- core effects ------------- */
 170  
 171  Effect.ScopedQueue = Class.create();
 172  Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
 173    initialize: function() {
 174      this.effects  = [];
 175      this.interval = null;    
 176    },
 177    _each: function(iterator) {
 178      this.effects._each(iterator);
 179    },
 180    add: function(effect) {
 181      var timestamp = new Date().getTime();
 182      
 183      var position = (typeof effect.options.queue == 'string') ? 
 184        effect.options.queue : effect.options.queue.position;
 185      
 186      switch(position) {
 187        case 'front':
 188          // move unstarted effects after this effect  
 189          this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
 190              e.startOn  += effect.finishOn;
 191              e.finishOn += effect.finishOn;
 192            });
 193          break;
 194        case 'with-last':
 195          timestamp = this.effects.pluck('startOn').max() || timestamp;
 196          break;
 197        case 'end':
 198          // start effect after last queued effect has finished
 199          timestamp = this.effects.pluck('finishOn').max() || timestamp;
 200          break;
 201      }
 202      
 203      effect.startOn  += timestamp;
 204      effect.finishOn += timestamp;
 205  
 206      if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
 207        this.effects.push(effect);
 208      
 209      if(!this.interval)
 210        this.interval = setInterval(this.loop.bind(this), 15);
 211    },
 212    remove: function(effect) {
 213      this.effects = this.effects.reject(function(e) { return e==effect });
 214      if(this.effects.length == 0) {
 215        clearInterval(this.interval);
 216        this.interval = null;
 217      }
 218    },
 219    loop: function() {
 220      var timePos = new Date().getTime();
 221      for(var i=0, len=this.effects.length;i<len;i++) 
 222        this.effects[i] && this.effects[i].loop(timePos);
 223    }
 224  });
 225  
 226  Effect.Queues = {
 227    instances: $H(),
 228    get: function(queueName) {
 229      if(typeof queueName != 'string') return queueName;
 230      
 231      if(!this.instances[queueName])
 232        this.instances[queueName] = new Effect.ScopedQueue();
 233        
 234      return this.instances[queueName];
 235    }
 236  }
 237  Effect.Queue = Effect.Queues.get('global');
 238  
 239  Effect.DefaultOptions = {
 240    transition: Effect.Transitions.sinoidal,
 241    duration:   1.0,   // seconds
 242    fps:        100,   // 100= assume 66fps max.
 243    sync:       false, // true for combining
 244    from:       0.0,
 245    to:         1.0,
 246    delay:      0.0,
 247    queue:      'parallel'
 248  }
 249  
 250  Effect.Base = function() {};
 251  Effect.Base.prototype = {
 252    position: null,
 253    start: function(options) {
 254      function codeForEvent(options,eventName){
 255        return (
 256          (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
 257          (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
 258        );
 259      }
 260      if(options.transition === false) options.transition = Effect.Transitions.linear;
 261      this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
 262      this.currentFrame = 0;
 263      this.state        = 'idle';
 264      this.startOn      = this.options.delay*1000;
 265      this.finishOn     = this.startOn+(this.options.duration*1000);
 266      this.fromToDelta  = this.options.to-this.options.from;
 267      this.totalTime    = this.finishOn-this.startOn;
 268      this.totalFrames  = this.options.fps*this.options.duration;
 269      
 270      eval('this.render = function(pos){ '+
 271        'if(this.state=="idle"){this.state="running";'+
 272        codeForEvent(options,'beforeSetup')+
 273        (this.setup ? 'this.setup();':'')+ 
 274        codeForEvent(options,'afterSetup')+
 275        '};if(this.state=="running"){'+
 276        'pos=this.options.transition(pos)*'+this.fromToDelta+'+'+this.options.from+';'+
 277        'this.position=pos;'+
 278        codeForEvent(options,'beforeUpdate')+
 279        (this.update ? 'this.update(pos);':'')+
 280        codeForEvent(options,'afterUpdate')+
 281        '}}');
 282      
 283      this.event('beforeStart');
 284      if(!this.options.sync)
 285        Effect.Queues.get(typeof this.options.queue == 'string' ? 
 286          'global' : this.options.queue.scope).add(this);
 287    },
 288    loop: function(timePos) {
 289      if(timePos >= this.startOn) {
 290        if(timePos >= this.finishOn) {
 291          this.render(1.0);
 292          this.cancel();
 293          this.event('beforeFinish');
 294          if(this.finish) this.finish(); 
 295          this.event('afterFinish');
 296          return;  
 297        }
 298        var pos   = (timePos - this.startOn) / this.totalTime,
 299            frame = Math.round(pos * this.totalFrames);
 300        if(frame > this.currentFrame) {
 301          this.render(pos);
 302          this.currentFrame = frame;
 303        }
 304      }
 305    },
 306    cancel: function() {
 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';
 311    },
 312    event: function(eventName) {
 313      if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
 314      if(this.options[eventName]) this.options[eventName](this);
 315    },
 316    inspect: function() {
 317      var data = $H();
 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() + '>';
 321    }
 322  }
 323  
 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]);
 329    },
 330    update: function(position) {
 331      this.effects.invoke('render', position);
 332    },
 333    finish: function(position) {
 334      this.effects.each( function(effect) {
 335        effect.render(1.0);
 336        effect.cancel();
 337        effect.event('beforeFinish');
 338        if(effect.finish) effect.finish(position);
 339        effect.event('afterFinish');
 340      });
 341    }
 342  });
 343  
 344  Effect.Event = Class.create();
 345  Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
 346    initialize: function() {
 347      var options = Object.extend({
 348        duration: 0
 349      }, arguments[0] || {});
 350      this.start(options);
 351    },
 352    update: Prototype.emptyFunction
 353  });
 354  
 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(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
 362        this.element.setStyle({zoom: 1});
 363      var options = Object.extend({
 364        from: this.element.getOpacity() || 0.0,
 365        to:   1.0
 366      }, arguments[1] || {});
 367      this.start(options);
 368    },
 369    update: function(position) {
 370      this.element.setOpacity(position);
 371    }
 372  });
 373  
 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({
 380        x:    0,
 381        y:    0,
 382        mode: 'relative'
 383      }, arguments[1] || {});
 384      this.start(options);
 385    },
 386    setup: function() {
 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;
 398      }
 399    },
 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'
 404      });
 405    }
 406  });
 407  
 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] || {}));
 412  };
 413  
 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({
 420        scaleX: true,
 421        scaleY: true,
 422        scaleContent: true,
 423        scaleFromCenter: false,
 424        scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
 425        scaleFrom: 100.0,
 426        scaleTo:   percent
 427      }, arguments[2] || {});
 428      this.start(options);
 429    },
 430    setup: function() {
 431      this.restoreAfterFinish = this.options.restoreAfterFinish || false;
 432      this.elementPositioning = this.element.getStyle('position');
 433      
 434      this.originalStyle = {};
 435      ['top','left','width','height','fontSize'].each( function(k) {
 436        this.originalStyle[k] = this.element.style[k];
 437      }.bind(this));
 438        
 439      this.originalTop  = this.element.offsetTop;
 440      this.originalLeft = this.element.offsetLeft;
 441      
 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;
 447        }
 448      }.bind(this));
 449      
 450      this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
 451      
 452      this.dims = null;
 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];
 457      if(!this.dims)
 458        this.dims = [this.options.scaleMode.originalHeight,
 459                     this.options.scaleMode.originalWidth];
 460    },
 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);
 466    },
 467    finish: function(position) {
 468      if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
 469    },
 470    setDimensions: function(height, width) {
 471      var d = {};
 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';
 480        } else {
 481          if(this.options.scaleY) d.top = -topd + 'px';
 482          if(this.options.scaleX) d.left = -leftd + 'px';
 483        }
 484      }
 485      this.element.setStyle(d);
 486    }
 487  });
 488  
 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] || {});
 495      this.start(options);
 496    },
 497    setup: function() {
 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
 501      this.oldStyle = {};
 502      if (!this.options.keepBackgroundImage) {
 503        this.oldStyle.backgroundImage = this.element.getStyle('background-image');
 504        this.element.setStyle({backgroundImage: 'none'});
 505      }
 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));
 513    },
 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)) });
 517    },
 518    finish: function() {
 519      this.element.setStyle(Object.extend(this.oldStyle, {
 520        backgroundColor: this.options.restorecolor
 521      }));
 522    }
 523  });
 524  
 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] || {});
 530    },
 531    setup: function() {
 532      Position.prepare();
 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;
 542    },
 543    update: function(position) {
 544      Position.prepare();
 545      window.scrollTo(Position.deltaX, 
 546        this.scrollStart + (position*this.delta));
 547    }
 548  });
 549  
 550  /* ------------- combination effects ------------- */
 551  
 552  Effect.Fade = function(element) {
 553    element = $(element);
 554    var oldOpacity = element.getInlineOpacity();
 555    var options = Object.extend({
 556    from: element.getOpacity() || 1.0,
 557    to:   0.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);
 563  }
 564  
 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),
 569    to:   1.0,
 570    // force Safari to render floated elements properly
 571    afterFinishInternal: function(effect) {
 572      effect.element.forceRerendering();
 573    },
 574    beforeSetup: function(effect) {
 575      effect.element.setOpacity(effect.options.from).show(); 
 576    }}, arguments[1] || {});
 577    return new Effect.Opacity(element,options);
 578  }
 579  
 580  Effect.Puff = function(element) {
 581    element = $(element);
 582    var oldStyle = { 
 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
 589    };
 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)
 597        },
 598        afterFinishInternal: function(effect) {
 599           effect.effects[0].element.hide().setStyle(oldStyle); }
 600       }, arguments[1] || {})
 601     );
 602  }
 603  
 604  Effect.BlindUp = function(element) {
 605    element = $(element);
 606    element.makeClipping();
 607    return new Effect.Scale(element, 0,
 608      Object.extend({ scaleContent: false, 
 609        scaleX: false, 
 610        restoreAfterFinish: true,
 611        afterFinishInternal: function(effect) {
 612          effect.element.hide().undoClipping();
 613        } 
 614      }, arguments[1] || {})
 615    );
 616  }
 617  
 618  Effect.BlindDown = function(element) {
 619    element = $(element);
 620    var elementDimensions = element.getDimensions();
 621    return new Effect.Scale(element, 100, Object.extend({ 
 622      scaleContent: false, 
 623      scaleX: false,
 624      scaleFrom: 0,
 625      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
 626      restoreAfterFinish: true,
 627      afterSetup: function(effect) {
 628        effect.element.makeClipping().setStyle({height: '0px'}).show(); 
 629      },  
 630      afterFinishInternal: function(effect) {
 631        effect.element.undoClipping();
 632      }
 633    }, arguments[1] || {}));
 634  }
 635  
 636  Effect.SwitchOff = function(element) {
 637    element = $(element);
 638    var oldOpacity = element.getInlineOpacity();
 639    return new Effect.Appear(element, Object.extend({
 640      duration: 0.4,
 641      from: 0,
 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();
 649          },
 650          afterFinishInternal: function(effect) {
 651            effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
 652          }
 653        })
 654      }
 655    }, arguments[1] || {}));
 656  }
 657  
 658  Effect.DropOut = function(element) {
 659    element = $(element);
 660    var oldStyle = {
 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 }) ],
 667      Object.extend(
 668        { duration: 0.5,
 669          beforeSetup: function(effect) {
 670            effect.effects[0].element.makePositioned(); 
 671          },
 672          afterFinishInternal: function(effect) {
 673            effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
 674          } 
 675        }, arguments[1] || {}));
 676  }
 677  
 678  Effect.Shake = function(element) {
 679    element = $(element);
 680    var oldStyle = {
 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    }}) }}) }}) }}) }}) }});
 697  }
 698  
 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({ 
 705      scaleContent: false, 
 706      scaleX: false, 
 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(); 
 715      },
 716      afterUpdateInternal: function(effect) {
 717        effect.element.down().setStyle({bottom:
 718          (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
 719      },
 720      afterFinishInternal: function(effect) {
 721        effect.element.undoClipping().undoPositioned();
 722        effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
 723      }, arguments[1] || {})
 724    );
 725  }
 726  
 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, 
 732      scaleX: false, 
 733      scaleMode: 'box',
 734      scaleFrom: 100,
 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();
 741      },  
 742      afterUpdateInternal: function(effect) {
 743        effect.element.down().setStyle({bottom:
 744          (effect.dims[0] - effect.element.clientHeight) + 'px' });
 745      },
 746      afterFinishInternal: function(effect) {
 747        effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
 748        effect.element.down().undoPositioned();
 749      }
 750     }, arguments[1] || {})
 751    );
 752  }
 753  
 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(); 
 760      },  
 761      afterFinishInternal: function(effect) {
 762        effect.element.hide().undoClipping(); 
 763      }
 764    });
 765  }
 766  
 767  Effect.Grow = function(element) {
 768    element = $(element);
 769    var options = Object.extend({
 770      direction: 'center',
 771      moveTransition: Effect.Transitions.sinoidal,
 772      scaleTransition: Effect.Transitions.sinoidal,
 773      opacityTransition: Effect.Transitions.full
 774    }, arguments[1] || {});
 775    var oldStyle = {
 776      top: element.style.top,
 777      left: element.style.left,
 778      height: element.style.height,
 779      width: element.style.width,
 780      opacity: element.getInlineOpacity() };
 781  
 782    var dims = element.getDimensions();    
 783    var initialMoveX, initialMoveY;
 784    var moveX, moveY;
 785    
 786    switch (options.direction) {
 787      case 'top-left':
 788        initialMoveX = initialMoveY = moveX = moveY = 0; 
 789        break;
 790      case 'top-right':
 791        initialMoveX = dims.width;
 792        initialMoveY = moveY = 0;
 793        moveX = -dims.width;
 794        break;
 795      case 'bottom-left':
 796        initialMoveX = moveX = 0;
 797        initialMoveY = dims.height;
 798        moveY = -dims.height;
 799        break;
 800      case 'bottom-right':
 801        initialMoveX = dims.width;
 802        initialMoveY = dims.height;
 803        moveX = -dims.width;
 804        moveY = -dims.height;
 805        break;
 806      case 'center':
 807        initialMoveX = dims.width / 2;
 808        initialMoveY = dims.height / 2;
 809        moveX = -dims.width / 2;
 810        moveY = -dims.height / 2;
 811        break;
 812    }
 813    
 814    return new Effect.Move(element, {
 815      x: initialMoveX,
 816      y: initialMoveY,
 817      duration: 0.01, 
 818      beforeSetup: function(effect) {
 819        effect.element.hide().makeClipping().makePositioned();
 820      },
 821      afterFinishInternal: function(effect) {
 822        new Effect.Parallel(
 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})
 828          ], Object.extend({
 829               beforeSetup: function(effect) {
 830                 effect.effects[0].element.setStyle({height: '0px'}).show(); 
 831               },
 832               afterFinishInternal: function(effect) {
 833                 effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
 834               }
 835             }, options)
 836        )
 837      }
 838    });
 839  }
 840  
 841  Effect.Shrink = function(element) {
 842    element = $(element);
 843    var options = Object.extend({
 844      direction: 'center',
 845      moveTransition: Effect.Transitions.sinoidal,
 846      scaleTransition: Effect.Transitions.sinoidal,
 847      opacityTransition: Effect.Transitions.none
 848    }, arguments[1] || {});
 849    var oldStyle = {
 850      top: element.style.top,
 851      left: element.style.left,
 852      height: element.style.height,
 853      width: element.style.width,
 854      opacity: element.getInlineOpacity() };
 855  
 856    var dims = element.getDimensions();
 857    var moveX, moveY;
 858    
 859    switch (options.direction) {
 860      case 'top-left':
 861        moveX = moveY = 0;
 862        break;
 863      case 'top-right':
 864        moveX = dims.width;
 865        moveY = 0;
 866        break;
 867      case 'bottom-left':
 868        moveX = 0;
 869        moveY = dims.height;
 870        break;
 871      case 'bottom-right':
 872        moveX = dims.width;
 873        moveY = dims.height;
 874        break;
 875      case 'center':  
 876        moveX = dims.width / 2;
 877        moveY = dims.height / 2;
 878        break;
 879    }
 880    
 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 })
 885      ], Object.extend({            
 886           beforeStartInternal: function(effect) {
 887             effect.effects[0].element.makePositioned().makeClipping(); 
 888           },
 889           afterFinishInternal: function(effect) {
 890             effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
 891         }, options)
 892    );
 893  }
 894  
 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}));
 906  }
 907  
 908  Effect.Fold = function(element) {
 909    element = $(element);
 910    var oldStyle = {
 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({   
 917      scaleContent: false,
 918      scaleX: false,
 919      afterFinishInternal: function(effect) {
 920      new Effect.Scale(element, 1, { 
 921        scaleContent: false, 
 922        scaleY: false,
 923        afterFinishInternal: function(effect) {
 924          effect.element.hide().undoClipping().setStyle(oldStyle);
 925        } });
 926    }}, arguments[1] || {}));
 927  };
 928  
 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({
 935        style: {}
 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;
 946                throw $break;
 947              }
 948            });
 949            if (cssText) throw $break;
 950          });
 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] = '';
 957            });
 958          }
 959        } else this.style = options.style.parseStyle();
 960      } else this.style = $H(options.style)
 961      this.start(options);
 962    },
 963    setup: function(){
 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 ) 
 969        });
 970      }
 971      this.transforms = this.style.map(function(pair){
 972        var property = pair[0], value = pair[1], unit = null;
 973  
 974        if(value.parseColor('#zzzzzz') != '#zzzzzz') {
 975          value = value.parseColor();
 976          unit  = 'color';
 977        } else if(property == 'opacity') {
 978          value = parseFloat(value);
 979          if(Prototype.Browser.IE && (!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]);
 984            unit = (components.length == 3) ? components[2] : null;
 985        }
 986  
 987        var originalValue = this.element.getStyle(property);
 988        return { 
 989          style: property.camelize(), 
 990          originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
 991          targetValue: unit=='color' ? parseColor(value) : value,
 992          unit: unit
 993        };
 994      }.bind(this)).reject(function(transform){
 995        return (
 996          (transform.originalValue == transform.targetValue) ||
 997          (
 998            transform.unit != 'color' &&
 999            (isNaN(transform.originalValue) || isNaN(transform.targetValue))
1000          )
1001        )
1002      });
1003    },
1004    update: function(position) {
1005      var style = {}, transform, i = this.transforms.length;
1006      while(i--)
1007        style[(transform = this.transforms[i]).style] = 
1008          transform.unit=='color' ? '#'+
1009            (Math.round(transform.originalValue[0]+
1010              (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
1011            (Math.round(transform.originalValue[1]+
1012              (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
1013            (Math.round(transform.originalValue[2]+
1014              (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
1015          transform.originalValue + Math.round(
1016            ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
1017      this.element.setStyle(style, true);
1018    }
1019  });
1020  
1021  Effect.Transform = Class.create();
1022  Object.extend(Effect.Transform.prototype, {
1023    initialize: function(tracks){
1024      this.tracks  = [];
1025      this.options = arguments[1] || {};
1026      this.addTracks(tracks);
1027    },
1028    addTracks: function(tracks){
1029      tracks.each(function(track){
1030        var data = $H(track).values().first();
1031        this.tracks.push($H({
1032          ids:     $H(track).keys().first(),
1033          effect:  Effect.Morph,
1034          options: { style: data }
1035        }));
1036      }.bind(this));
1037      return this;
1038    },
1039    play: function(){
1040      return new Effect.Parallel(
1041        this.tracks.map(function(track){
1042          var elements = [$(track.ids) || $$(track.ids)].flatten();
1043          return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1044        }).flatten(),
1045        this.options
1046      );
1047    }
1048  });
1049  
1050  Element.CSS_PROPERTIES = $w(
1051    'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
1052    'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1053    'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1054    'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1055    'fontSize fontWeight height left letterSpacing lineHeight ' +
1056    'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1057    'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1058    'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1059    'right textIndent top width wordSpacing zIndex');
1060    
1061  Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1062  
1063  String.prototype.parseStyle = function(){
1064    var element = document.createElement('div');
1065    element.innerHTML = '<div style="' + this + '"></div>';
1066    var style = element.childNodes[0].style, styleRules = $H();
1067    
1068    Element.CSS_PROPERTIES.each(function(property){
1069      if(style[property]) styleRules[property] = style[property]; 
1070    });
1071    if(Prototype.Browser.IE && this.indexOf('opacity') > -1) {
1072      styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
1073    }
1074    return styleRules;
1075  };
1076  
1077  Element.morph = function(element, style) {
1078    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1079    return element;
1080  };
1081  
1082  ['getInlineOpacity','forceRerendering','setContentZoom',
1083   'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
1084    function(f) { Element.Methods[f] = Element[f]; }
1085  );
1086  
1087  Element.Methods.visualEffect = function(element, effect, options) {
1088    s = effect.dasherize().camelize();
1089    effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1090    new Effect[effect_class](element, options);
1091    return $(element);
1092  };
1093  
1094  Element.addMethods();


Generated Thu Dec 6 06:47:08 2007 for RedAlt XRefs Cross-referenced by PHPXref 0.6 and RedAlt