[ Index ]

PHP Cross Reference of Wordpress 2.9.1

title

Body

[close]

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

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


Generated: Fri Jan 8 00:19:48 2010 Cross-referenced by PHPXref 0.7