[ Index ]

PHP Cross Reference of MyBB

title

Body

[close]

/jscripts/ -> effects.js (source)

   1  // script.aculo.us effects.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
   2  
   3  // Copyright (c) 2005-2010 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) + .5;
  76      },
  77      reverse: function(pos) {
  78        return 1-pos;
  79      },
  80      flicker: function(pos) {
  81        var pos = ((-Math.cos(pos*Math.PI)/4) + .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) + .5;
  86      },
  87      pulse: function(pos, pulses) {
  88        return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5;
  89      },
  90      spring: function(pos) {
  91        return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
  92      },
  93      none: function(pos) {
  94        return 0;
  95      },
  96      full: function(pos) {
  97        return 1;
  98      }
  99    },
 100    DefaultOptions: {
 101      duration:   1.0,   // seconds
 102      fps:        100,   // 100= assume 66fps max.
 103      sync:       false, // true for combining
 104      from:       0.0,
 105      to:         1.0,
 106      delay:      0.0,
 107      queue:      'parallel'
 108    },
 109    tagifyText: function(element) {
 110      var tagifyStyle = 'position:relative';
 111      if (Prototype.Browser.IE) tagifyStyle += ';zoom:1';
 112  
 113      element = $(element);
 114      $A(element.childNodes).each( function(child) {
 115        if (child.nodeType==3) {
 116          child.nodeValue.toArray().each( function(character) {
 117            element.insertBefore(
 118              new Element('span', {style: tagifyStyle}).update(
 119                character == ' ' ? String.fromCharCode(160) : character),
 120                child);
 121          });
 122          Element.remove(child);
 123        }
 124      });
 125    },
 126    multiple: function(element, effect) {
 127      var elements;
 128      if (((typeof element == 'object') ||
 129          Object.isFunction(element)) &&
 130         (element.length))
 131        elements = element;
 132      else
 133        elements = $(element).childNodes;
 134  
 135      var options = Object.extend({
 136        speed: 0.1,
 137        delay: 0.0
 138      }, arguments[2] || { });
 139      var masterDelay = options.delay;
 140  
 141      $A(elements).each( function(element, index) {
 142        new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
 143      });
 144    },
 145    PAIRS: {
 146      'slide':  ['SlideDown','SlideUp'],
 147      'blind':  ['BlindDown','BlindUp'],
 148      'appear': ['Appear','Fade']
 149    },
 150    toggle: function(element, effect, options) {
 151      element = $(element);
 152      effect  = (effect || 'appear').toLowerCase();
 153      
 154      return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({
 155        queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
 156      }, options || {}));
 157    }
 158  };
 159  
 160  Effect.DefaultOptions.transition = Effect.Transitions.sinoidal;
 161  
 162  /* ------------- core effects ------------- */
 163  
 164  Effect.ScopedQueue = Class.create(Enumerable, {
 165    initialize: function() {
 166      this.effects  = [];
 167      this.interval = null;
 168    },
 169    _each: function(iterator) {
 170      this.effects._each(iterator);
 171    },
 172    add: function(effect) {
 173      var timestamp = new Date().getTime();
 174  
 175      var position = Object.isString(effect.options.queue) ?
 176        effect.options.queue : effect.options.queue.position;
 177  
 178      switch(position) {
 179        case 'front':
 180          // move unstarted effects after this effect
 181          this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
 182              e.startOn  += effect.finishOn;
 183              e.finishOn += effect.finishOn;
 184            });
 185          break;
 186        case 'with-last':
 187          timestamp = this.effects.pluck('startOn').max() || timestamp;
 188          break;
 189        case 'end':
 190          // start effect after last queued effect has finished
 191          timestamp = this.effects.pluck('finishOn').max() || timestamp;
 192          break;
 193      }
 194  
 195      effect.startOn  += timestamp;
 196      effect.finishOn += timestamp;
 197  
 198      if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
 199        this.effects.push(effect);
 200  
 201      if (!this.interval)
 202        this.interval = setInterval(this.loop.bind(this), 15);
 203    },
 204    remove: function(effect) {
 205      this.effects = this.effects.reject(function(e) { return e==effect });
 206      if (this.effects.length == 0) {
 207        clearInterval(this.interval);
 208        this.interval = null;
 209      }
 210    },
 211    loop: function() {
 212      var timePos = new Date().getTime();
 213      for(var i=0, len=this.effects.length;i<len;i++)
 214        this.effects[i] && this.effects[i].loop(timePos);
 215    }
 216  });
 217  
 218  Effect.Queues = {
 219    instances: $H(),
 220    get: function(queueName) {
 221      if (!Object.isString(queueName)) return queueName;
 222  
 223      return this.instances.get(queueName) ||
 224        this.instances.set(queueName, new Effect.ScopedQueue());
 225    }
 226  };
 227  Effect.Queue = Effect.Queues.get('global');
 228  
 229  Effect.Base = Class.create({
 230    position: null,
 231    start: function(options) {
 232      if (options && options.transition === false) options.transition = Effect.Transitions.linear;
 233      this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
 234      this.currentFrame = 0;
 235      this.state        = 'idle';
 236      this.startOn      = this.options.delay*1000;
 237      this.finishOn     = this.startOn+(this.options.duration*1000);
 238      this.fromToDelta  = this.options.to-this.options.from;
 239      this.totalTime    = this.finishOn-this.startOn;
 240      this.totalFrames  = this.options.fps*this.options.duration;
 241  
 242      this.render = (function() {
 243        function dispatch(effect, eventName) {
 244          if (effect.options[eventName + 'Internal'])
 245            effect.options[eventName + 'Internal'](effect);
 246          if (effect.options[eventName])
 247            effect.options[eventName](effect);
 248        }
 249  
 250        return function(pos) {
 251          if (this.state === "idle") {
 252            this.state = "running";
 253            dispatch(this, 'beforeSetup');
 254            if (this.setup) this.setup();
 255            dispatch(this, 'afterSetup');
 256          }
 257          if (this.state === "running") {
 258            pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from;
 259            this.position = pos;
 260            dispatch(this, 'beforeUpdate');
 261            if (this.update) this.update(pos);
 262            dispatch(this, 'afterUpdate');
 263          }
 264        };
 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  
 515    if (options.offset) elementOffsets[1] += options.offset;
 516  
 517    return new Effect.Tween(null,
 518      scrollOffsets.top,
 519      elementOffsets[1],
 520      options,
 521      function(p){ scrollTo(scrollOffsets.left, p.round()); }
 522    );
 523  };
 524  
 525  /* ------------- combination effects ------------- */
 526  
 527  Effect.Fade = function(element) {
 528    element = $(element);
 529    var oldOpacity = element.getInlineOpacity();
 530    var options = Object.extend({
 531      from: element.getOpacity() || 1.0,
 532      to:   0.0,
 533      afterFinishInternal: function(effect) {
 534        if (effect.options.to!=0) return;
 535        effect.element.hide().setStyle({opacity: oldOpacity});
 536      }
 537    }, arguments[1] || { });
 538    return new Effect.Opacity(element,options);
 539  };
 540  
 541  Effect.Appear = function(element) {
 542    element = $(element);
 543    var options = Object.extend({
 544    from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
 545    to:   1.0,
 546    // force Safari to render floated elements properly
 547    afterFinishInternal: function(effect) {
 548      effect.element.forceRerendering();
 549    },
 550    beforeSetup: function(effect) {
 551      effect.element.setOpacity(effect.options.from).show();
 552    }}, arguments[1] || { });
 553    return new Effect.Opacity(element,options);
 554  };
 555  
 556  Effect.Puff = function(element) {
 557    element = $(element);
 558    var oldStyle = {
 559      opacity: element.getInlineOpacity(),
 560      position: element.getStyle('position'),
 561      top:  element.style.top,
 562      left: element.style.left,
 563      width: element.style.width,
 564      height: element.style.height
 565    };
 566    return new Effect.Parallel(
 567     [ new Effect.Scale(element, 200,
 568        { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
 569       new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
 570       Object.extend({ duration: 1.0,
 571        beforeSetupInternal: function(effect) {
 572          Position.absolutize(effect.effects[0].element);
 573        },
 574        afterFinishInternal: function(effect) {
 575           effect.effects[0].element.hide().setStyle(oldStyle); }
 576       }, arguments[1] || { })
 577     );
 578  };
 579  
 580  Effect.BlindUp = function(element) {
 581    element = $(element);
 582    element.makeClipping();
 583    return new Effect.Scale(element, 0,
 584      Object.extend({ scaleContent: false,
 585        scaleX: false,
 586        restoreAfterFinish: true,
 587        afterFinishInternal: function(effect) {
 588          effect.element.hide().undoClipping();
 589        }
 590      }, arguments[1] || { })
 591    );
 592  };
 593  
 594  Effect.BlindDown = function(element) {
 595    element = $(element);
 596    var elementDimensions = element.getDimensions();
 597    return new Effect.Scale(element, 100, Object.extend({
 598      scaleContent: false,
 599      scaleX: false,
 600      scaleFrom: 0,
 601      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
 602      restoreAfterFinish: true,
 603      afterSetup: function(effect) {
 604        effect.element.makeClipping().setStyle({height: '0px'}).show();
 605      },
 606      afterFinishInternal: function(effect) {
 607        effect.element.undoClipping();
 608      }
 609    }, arguments[1] || { }));
 610  };
 611  
 612  Effect.SwitchOff = function(element) {
 613    element = $(element);
 614    var oldOpacity = element.getInlineOpacity();
 615    return new Effect.Appear(element, Object.extend({
 616      duration: 0.4,
 617      from: 0,
 618      transition: Effect.Transitions.flicker,
 619      afterFinishInternal: function(effect) {
 620        new Effect.Scale(effect.element, 1, {
 621          duration: 0.3, scaleFromCenter: true,
 622          scaleX: false, scaleContent: false, restoreAfterFinish: true,
 623          beforeSetup: function(effect) {
 624            effect.element.makePositioned().makeClipping();
 625          },
 626          afterFinishInternal: function(effect) {
 627            effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
 628          }
 629        });
 630      }
 631    }, arguments[1] || { }));
 632  };
 633  
 634  Effect.DropOut = function(element) {
 635    element = $(element);
 636    var oldStyle = {
 637      top: element.getStyle('top'),
 638      left: element.getStyle('left'),
 639      opacity: element.getInlineOpacity() };
 640    return new Effect.Parallel(
 641      [ new Effect.Move(element, {x: 0, y: 100, sync: true }),
 642        new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
 643      Object.extend(
 644        { duration: 0.5,
 645          beforeSetup: function(effect) {
 646            effect.effects[0].element.makePositioned();
 647          },
 648          afterFinishInternal: function(effect) {
 649            effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
 650          }
 651        }, arguments[1] || { }));
 652  };
 653  
 654  Effect.Shake = function(element) {
 655    element = $(element);
 656    var options = Object.extend({
 657      distance: 20,
 658      duration: 0.5
 659    }, arguments[1] || {});
 660    var distance = parseFloat(options.distance);
 661    var split = parseFloat(options.duration) / 10.0;
 662    var oldStyle = {
 663      top: element.getStyle('top'),
 664      left: element.getStyle('left') };
 665      return new Effect.Move(element,
 666        { x:  distance, y: 0, duration: split, afterFinishInternal: function(effect) {
 667      new Effect.Move(effect.element,
 668        { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
 669      new Effect.Move(effect.element,
 670        { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
 671      new Effect.Move(effect.element,
 672        { x: -distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
 673      new Effect.Move(effect.element,
 674        { x:  distance*2, y: 0, duration: split*2,  afterFinishInternal: function(effect) {
 675      new Effect.Move(effect.element,
 676        { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) {
 677          effect.element.undoPositioned().setStyle(oldStyle);
 678    }}); }}); }}); }}); }}); }});
 679  };
 680  
 681  Effect.SlideDown = function(element) {
 682    element = $(element).cleanWhitespace();
 683    // SlideDown need to have the content of the element wrapped in a container element with fixed height!
 684    var oldInnerBottom = element.down().getStyle('bottom');
 685    var elementDimensions = element.getDimensions();
 686    return new Effect.Scale(element, 100, Object.extend({
 687      scaleContent: false,
 688      scaleX: false,
 689      scaleFrom: window.opera ? 0 : 1,
 690      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
 691      restoreAfterFinish: true,
 692      afterSetup: function(effect) {
 693        effect.element.makePositioned();
 694        effect.element.down().makePositioned();
 695        if (window.opera) effect.element.setStyle({top: ''});
 696        effect.element.makeClipping().setStyle({height: '0px'}).show();
 697      },
 698      afterUpdateInternal: function(effect) {
 699        effect.element.down().setStyle({bottom:
 700          (effect.dims[0] - effect.element.clientHeight) + 'px' });
 701      },
 702      afterFinishInternal: function(effect) {
 703        effect.element.undoClipping().undoPositioned();
 704        effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
 705      }, arguments[1] || { })
 706    );
 707  };
 708  
 709  Effect.SlideUp = function(element) {
 710    element = $(element).cleanWhitespace();
 711    var oldInnerBottom = element.down().getStyle('bottom');
 712    var elementDimensions = element.getDimensions();
 713    return new Effect.Scale(element, window.opera ? 0 : 1,
 714     Object.extend({ scaleContent: false,
 715      scaleX: false,
 716      scaleMode: 'box',
 717      scaleFrom: 100,
 718      scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
 719      restoreAfterFinish: true,
 720      afterSetup: function(effect) {
 721        effect.element.makePositioned();
 722        effect.element.down().makePositioned();
 723        if (window.opera) effect.element.setStyle({top: ''});
 724        effect.element.makeClipping().show();
 725      },
 726      afterUpdateInternal: function(effect) {
 727        effect.element.down().setStyle({bottom:
 728          (effect.dims[0] - effect.element.clientHeight) + 'px' });
 729      },
 730      afterFinishInternal: function(effect) {
 731        effect.element.hide().undoClipping().undoPositioned();
 732        effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
 733      }
 734     }, arguments[1] || { })
 735    );
 736  };
 737  
 738  // Bug in opera makes the TD containing this element expand for a instance after finish
 739  Effect.Squish = function(element) {
 740    return new Effect.Scale(element, window.opera ? 1 : 0, {
 741      restoreAfterFinish: true,
 742      beforeSetup: function(effect) {
 743        effect.element.makeClipping();
 744      },
 745      afterFinishInternal: function(effect) {
 746        effect.element.hide().undoClipping();
 747      }
 748    });
 749  };
 750  
 751  Effect.Grow = function(element) {
 752    element = $(element);
 753    var options = Object.extend({
 754      direction: 'center',
 755      moveTransition: Effect.Transitions.sinoidal,
 756      scaleTransition: Effect.Transitions.sinoidal,
 757      opacityTransition: Effect.Transitions.full
 758    }, arguments[1] || { });
 759    var oldStyle = {
 760      top: element.style.top,
 761      left: element.style.left,
 762      height: element.style.height,
 763      width: element.style.width,
 764      opacity: element.getInlineOpacity() };
 765  
 766    var dims = element.getDimensions();
 767    var initialMoveX, initialMoveY;
 768    var moveX, moveY;
 769  
 770    switch (options.direction) {
 771      case 'top-left':
 772        initialMoveX = initialMoveY = moveX = moveY = 0;
 773        break;
 774      case 'top-right':
 775        initialMoveX = dims.width;
 776        initialMoveY = moveY = 0;
 777        moveX = -dims.width;
 778        break;
 779      case 'bottom-left':
 780        initialMoveX = moveX = 0;
 781        initialMoveY = dims.height;
 782        moveY = -dims.height;
 783        break;
 784      case 'bottom-right':
 785        initialMoveX = dims.width;
 786        initialMoveY = dims.height;
 787        moveX = -dims.width;
 788        moveY = -dims.height;
 789        break;
 790      case 'center':
 791        initialMoveX = dims.width / 2;
 792        initialMoveY = dims.height / 2;
 793        moveX = -dims.width / 2;
 794        moveY = -dims.height / 2;
 795        break;
 796    }
 797  
 798    return new Effect.Move(element, {
 799      x: initialMoveX,
 800      y: initialMoveY,
 801      duration: 0.01,
 802      beforeSetup: function(effect) {
 803        effect.element.hide().makeClipping().makePositioned();
 804      },
 805      afterFinishInternal: function(effect) {
 806        new Effect.Parallel(
 807          [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
 808            new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
 809            new Effect.Scale(effect.element, 100, {
 810              scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
 811              sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
 812          ], Object.extend({
 813               beforeSetup: function(effect) {
 814                 effect.effects[0].element.setStyle({height: '0px'}).show();
 815               },
 816               afterFinishInternal: function(effect) {
 817                 effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle);
 818               }
 819             }, options)
 820        );
 821      }
 822    });
 823  };
 824  
 825  Effect.Shrink = function(element) {
 826    element = $(element);
 827    var options = Object.extend({
 828      direction: 'center',
 829      moveTransition: Effect.Transitions.sinoidal,
 830      scaleTransition: Effect.Transitions.sinoidal,
 831      opacityTransition: Effect.Transitions.none
 832    }, arguments[1] || { });
 833    var oldStyle = {
 834      top: element.style.top,
 835      left: element.style.left,
 836      height: element.style.height,
 837      width: element.style.width,
 838      opacity: element.getInlineOpacity() };
 839  
 840    var dims = element.getDimensions();
 841    var moveX, moveY;
 842  
 843    switch (options.direction) {
 844      case 'top-left':
 845        moveX = moveY = 0;
 846        break;
 847      case 'top-right':
 848        moveX = dims.width;
 849        moveY = 0;
 850        break;
 851      case 'bottom-left':
 852        moveX = 0;
 853        moveY = dims.height;
 854        break;
 855      case 'bottom-right':
 856        moveX = dims.width;
 857        moveY = dims.height;
 858        break;
 859      case 'center':
 860        moveX = dims.width / 2;
 861        moveY = dims.height / 2;
 862        break;
 863    }
 864  
 865    return new Effect.Parallel(
 866      [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
 867        new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
 868        new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
 869      ], Object.extend({
 870           beforeStartInternal: function(effect) {
 871             effect.effects[0].element.makePositioned().makeClipping();
 872           },
 873           afterFinishInternal: function(effect) {
 874             effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
 875         }, options)
 876    );
 877  };
 878  
 879  Effect.Pulsate = function(element) {
 880    element = $(element);
 881    var options    = arguments[1] || { },
 882      oldOpacity = element.getInlineOpacity(),
 883      transition = options.transition || Effect.Transitions.linear,
 884      reverser   = function(pos){
 885        return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5);
 886      };
 887  
 888    return new Effect.Opacity(element,
 889      Object.extend(Object.extend({  duration: 2.0, from: 0,
 890        afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
 891      }, options), {transition: reverser}));
 892  };
 893  
 894  Effect.Fold = function(element) {
 895    element = $(element);
 896    var oldStyle = {
 897      top: element.style.top,
 898      left: element.style.left,
 899      width: element.style.width,
 900      height: element.style.height };
 901    element.makeClipping();
 902    return new Effect.Scale(element, 5, Object.extend({
 903      scaleContent: false,
 904      scaleX: false,
 905      afterFinishInternal: function(effect) {
 906      new Effect.Scale(element, 1, {
 907        scaleContent: false,
 908        scaleY: false,
 909        afterFinishInternal: function(effect) {
 910          effect.element.hide().undoClipping().setStyle(oldStyle);
 911        } });
 912    }}, arguments[1] || { }));
 913  };
 914  
 915  Effect.Morph = Class.create(Effect.Base, {
 916    initialize: function(element) {
 917      this.element = $(element);
 918      if (!this.element) throw(Effect._elementDoesNotExistError);
 919      var options = Object.extend({
 920        style: { }
 921      }, arguments[1] || { });
 922  
 923      if (!Object.isString(options.style)) this.style = $H(options.style);
 924      else {
 925        if (options.style.include(':'))
 926          this.style = options.style.parseStyle();
 927        else {
 928          this.element.addClassName(options.style);
 929          this.style = $H(this.element.getStyles());
 930          this.element.removeClassName(options.style);
 931          var css = this.element.getStyles();
 932          this.style = this.style.reject(function(style) {
 933            return style.value == css[style.key];
 934          });
 935          options.afterFinishInternal = function(effect) {
 936            effect.element.addClassName(effect.options.style);
 937            effect.transforms.each(function(transform) {
 938              effect.element.style[transform.style] = '';
 939            });
 940          };
 941        }
 942      }
 943      this.start(options);
 944    },
 945  
 946    setup: function(){
 947      function parseColor(color){
 948        if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
 949        color = color.parseColor();
 950        return $R(0,2).map(function(i){
 951          return parseInt( color.slice(i*2+1,i*2+3), 16 );
 952        });
 953      }
 954      this.transforms = this.style.map(function(pair){
 955        var property = pair[0], value = pair[1], unit = null;
 956  
 957        if (value.parseColor('#zzzzzz') != '#zzzzzz') {
 958          value = value.parseColor();
 959          unit  = 'color';
 960        } else if (property == 'opacity') {
 961          value = parseFloat(value);
 962          if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout))
 963            this.element.setStyle({zoom: 1});
 964        } else if (Element.CSS_LENGTH.test(value)) {
 965            var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
 966            value = parseFloat(components[1]);
 967            unit = (components.length == 3) ? components[2] : null;
 968        }
 969  
 970        var originalValue = this.element.getStyle(property);
 971        return {
 972          style: property.camelize(),
 973          originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0),
 974          targetValue: unit=='color' ? parseColor(value) : value,
 975          unit: unit
 976        };
 977      }.bind(this)).reject(function(transform){
 978        return (
 979          (transform.originalValue == transform.targetValue) ||
 980          (
 981            transform.unit != 'color' &&
 982            (isNaN(transform.originalValue) || isNaN(transform.targetValue))
 983          )
 984        );
 985      });
 986    },
 987    update: function(position) {
 988      var style = { }, transform, i = this.transforms.length;
 989      while(i--)
 990        style[(transform = this.transforms[i]).style] =
 991          transform.unit=='color' ? '#'+
 992            (Math.round(transform.originalValue[0]+
 993              (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() +
 994            (Math.round(transform.originalValue[1]+
 995              (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() +
 996            (Math.round(transform.originalValue[2]+
 997              (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() :
 998          (transform.originalValue +
 999            (transform.targetValue - transform.originalValue) * position).toFixed(3) +
1000              (transform.unit === null ? '' : transform.unit);
1001      this.element.setStyle(style, true);
1002    }
1003  });
1004  
1005  Effect.Transform = Class.create({
1006    initialize: function(tracks){
1007      this.tracks  = [];
1008      this.options = arguments[1] || { };
1009      this.addTracks(tracks);
1010    },
1011    addTracks: function(tracks){
1012      tracks.each(function(track){
1013        track = $H(track);
1014        var data = track.values().first();
1015        this.tracks.push($H({
1016          ids:     track.keys().first(),
1017          effect:  Effect.Morph,
1018          options: { style: data }
1019        }));
1020      }.bind(this));
1021      return this;
1022    },
1023    play: function(){
1024      return new Effect.Parallel(
1025        this.tracks.map(function(track){
1026          var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options');
1027          var elements = [$(ids) || $$(ids)].flatten();
1028          return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) });
1029        }).flatten(),
1030        this.options
1031      );
1032    }
1033  });
1034  
1035  Element.CSS_PROPERTIES = $w(
1036    'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' +
1037    'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1038    'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1039    'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1040    'fontSize fontWeight height left letterSpacing lineHeight ' +
1041    'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1042    'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1043    'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1044    'right textIndent top width wordSpacing zIndex');
1045  
1046  Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1047  
1048  String.__parseStyleElement = document.createElement('div');
1049  String.prototype.parseStyle = function(){
1050    var style, styleRules = $H();
1051    if (Prototype.Browser.WebKit)
1052      style = new Element('div',{style:this}).style;
1053    else {
1054      String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>';
1055      style = String.__parseStyleElement.childNodes[0].style;
1056    }
1057  
1058    Element.CSS_PROPERTIES.each(function(property){
1059      if (style[property]) styleRules.set(property, style[property]);
1060    });
1061  
1062    if (Prototype.Browser.IE && this.include('opacity'))
1063      styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]);
1064  
1065    return styleRules;
1066  };
1067  
1068  if (document.defaultView && document.defaultView.getComputedStyle) {
1069    Element.getStyles = function(element) {
1070      var css = document.defaultView.getComputedStyle($(element), null);
1071      return Element.CSS_PROPERTIES.inject({ }, function(styles, property) {
1072        styles[property] = css[property];
1073        return styles;
1074      });
1075    };
1076  } else {
1077    Element.getStyles = function(element) {
1078      element = $(element);
1079      var css = element.currentStyle, styles;
1080      styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) {
1081        results[property] = css[property];
1082        return results;
1083      });
1084      if (!styles.opacity) styles.opacity = element.getOpacity();
1085      return styles;
1086    };
1087  }
1088  
1089  Effect.Methods = {
1090    morph: function(element, style) {
1091      element = $(element);
1092      new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { }));
1093      return element;
1094    },
1095    visualEffect: function(element, effect, options) {
1096      element = $(element);
1097      var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1);
1098      new Effect[klass](element, options);
1099      return element;
1100    },
1101    highlight: function(element, options) {
1102      element = $(element);
1103      new Effect.Highlight(element, options);
1104      return element;
1105    }
1106  };
1107  
1108  $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+
1109    'pulsate shake puff squish switchOff dropOut').each(
1110    function(effect) {
1111      Effect.Methods[effect] = function(element, options){
1112        element = $(element);
1113        Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options);
1114        return element;
1115      };
1116    }
1117  );
1118  
1119  $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each(
1120    function(f) { Effect.Methods[f] = Element[f]; }
1121  );
1122  
1123  Element.addMethods(Effect.Methods);


Generated: Tue Oct 8 19:19:50 2013 Cross-referenced by PHPXref 0.7.1