[ Index ]
 

Code source de Typo3 4.1.3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/typo3/contrib/scriptaculous/ -> effects.js (source)

   1  // script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007
   2  
   3  // Copyright (c) 2005, 2006 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(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
  49    return element;
  50  }
  51  
  52  Element.getOpacity = function(element){
  53    return $(element).getStyle('opacity');
  54  }
  55  
  56  Element.setOpacity = function(element, value){
  57    return $(element).setStyle({opacity:value});
  58  }
  59  
  60  Element.getInlineOpacity = function(element){
  61    return $(element).style.opacity || '';
  62  }
  63  
  64  Element.forceRerendering = function(element) {
  65    try {
  66      element = $(element);
  67      var n = document.createTextNode(' ');
  68      element.appendChild(n);
  69      element.removeChild(n);
  70    } catch(e) { }
  71  };
  72  
  73  /*--------------------------------------------------------------------------*/
  74  
  75  Array.prototype.call = function() {
  76    var args = arguments;
  77    this.each(function(f){ f.apply(this, args) });
  78  }
  79  
  80  /*--------------------------------------------------------------------------*/
  81  
  82  var Effect = {
  83    _elementDoesNotExistError: {
  84      name: 'ElementDoesNotExistError',
  85      message: 'The specified DOM element does not exist, but is required for this effect to operate'
  86    },
  87    tagifyText: function(element) {
  88      if(typeof Builder == 'undefined')
  89        throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
  90        
  91      var tagifyStyle = 'position:relative';
  92      if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
  93      
  94      element = $(element);
  95      $A(element.childNodes).each( function(child) {
  96        if(child.nodeType==3) {
  97          child.nodeValue.toArray().each( function(character) {
  98            element.insertBefore(
  99              Builder.node('span',{style: tagifyStyle},
 100                character == ' ' ? String.fromCharCode(160) : character), 
 101                child);
 102          });
 103          Element.remove(child);
 104        }
 105      });
 106    },
 107    multiple: function(element, effect) {
 108      var elements;
 109      if(((typeof element == 'object') || 
 110          (typeof element == 'function')) && 
 111         (element.length))
 112        elements = element;
 113      else
 114        elements = $(element).childNodes;
 115        
 116      var options = Object.extend({
 117        speed: 0.1,
 118        delay: 0.0
 119      }, arguments[2] || {});
 120      var masterDelay = options.delay;
 121  
 122      $A(elements).each( function(element, index) {
 123        new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
 124      });
 125    },
 126    PAIRS: {
 127      'slide':  ['SlideDown','SlideUp'],
 128      'blind':  ['BlindDown','BlindUp'],
 129      'appear': ['Appear','Fade']
 130    },
 131    toggle: function(element, effect) {
 132      element = $(element);
 133      effect = (effect || 'appear').toLowerCase();
 134      var options = Object.extend({
 135        queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
 136      }, arguments[2] || {});
 137      Effect[element.visible() ? 
 138        Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
 139    }
 140  };
 141  
 142  var Effect2 = Effect; // deprecated
 143  
 144  /* ------------- transitions ------------- */
 145  
 146  Effect.Transitions = {
 147    linear: Prototype.K,
 148    sinoidal: function(pos) {
 149      return (-Math.cos(pos*Math.PI)/2) + 0.5;
 150    },
 151    reverse: function(pos) {
 152      return 1-pos;
 153    },
 154    flicker: function(pos) {
 155      return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
 156    },
 157    wobble: function(pos) {
 158      return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
 159    },
 160    pulse: function(pos, pulses) { 
 161      pulses = pulses || 5; 
 162      return (
 163        Math.round((pos % (1/pulses)) * pulses) == 0 ? 
 164              ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
 165          1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
 166        );
 167    },
 168    none: function(pos) {
 169      return 0;
 170    },
 171    full: function(pos) {
 172      return 1;
 173    }
 174  };
 175  
 176  /* ------------- core effects ------------- */
 177  
 178  Effect.ScopedQueue = Class.create();
 179  Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
 180    initialize: function() {
 181      this.effects  = [];
 182      this.interval = null;
 183    },
 184    _each: function(iterator) {
 185      this.effects._each(iterator);
 186    },
 187    add: function(effect) {
 188      var timestamp = new Date().getTime();
 189      
 190      var position = (typeof effect.options.queue == 'string') ? 
 191        effect.options.queue : effect.options.queue.position;
 192      
 193      switch(position) {
 194        case 'front':
 195          // move unstarted effects after this effect  
 196          this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
 197              e.startOn  += effect.finishOn;
 198              e.finishOn += effect.finishOn;
 199            });
 200          break;
 201        case 'with-last':
 202          timestamp = this.effects.pluck('startOn').max() || timestamp;
 203          break;
 204        case 'end':
 205          // start effect after last queued effect has finished
 206          timestamp = this.effects.pluck('finishOn').max() || timestamp;
 207          break;
 208      }
 209      
 210      effect.startOn  += timestamp;
 211      effect.finishOn += timestamp;
 212  
 213      if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
 214        this.effects.push(effect);
 215      
 216      if(!this.interval) 
 217        this.interval = setInterval(this.loop.bind(this), 15);
 218    },
 219    remove: function(effect) {
 220      this.effects = this.effects.reject(function(e) { return e==effect });
 221      if(this.effects.length == 0) {
 222        clearInterval(this.interval);
 223        this.interval = null;
 224      }
 225    },
 226    loop: function() {
 227      var timePos = new Date().getTime();
 228      for(var i=0, len=this.effects.length;i<len;i++) 
 229        if(this.effects[i]) this.effects[i].loop(timePos);
 230    }
 231  });
 232  
 233  Effect.Queues = {
 234    instances: $H(),
 235    get: function(queueName) {
 236      if(typeof queueName != 'string') return queueName;
 237      
 238      if(!this.instances[queueName])
 239        this.instances[queueName] = new Effect.ScopedQueue();
 240        
 241      return this.instances[queueName];
 242    }
 243  }
 244  Effect.Queue = Effect.Queues.get('global');
 245  
 246  Effect.DefaultOptions = {
 247    transition: Effect.Transitions.sinoidal,
 248    duration:   1.0,   // seconds
 249    fps:        60.0,  // max. 60fps due to Effect.Queue implementation
 250    sync:       false, // true for combining
 251    from:       0.0,
 252    to:         1.0,
 253    delay:      0.0,
 254    queue:      'parallel'
 255  }
 256  
 257  Effect.Base = function() {};
 258  Effect.Base.prototype = {
 259    position: null,
 260    start: function(options) {
 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.event('beforeStart');
 267      if(!this.options.sync)
 268        Effect.Queues.get(typeof this.options.queue == 'string' ? 
 269          'global' : this.options.queue.scope).add(this);
 270    },
 271    loop: function(timePos) {
 272      if(timePos >= this.startOn) {
 273        if(timePos >= this.finishOn) {
 274          this.render(1.0);
 275          this.cancel();
 276          this.event('beforeFinish');
 277          if(this.finish) this.finish(); 
 278          this.event('afterFinish');
 279          return;  
 280        }
 281        var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
 282        var frame = Math.round(pos * this.options.fps * this.options.duration);
 283        if(frame > this.currentFrame) {
 284          this.render(pos);
 285          this.currentFrame = frame;
 286        }
 287      }
 288    },
 289    render: function(pos) {
 290      if(this.state == 'idle') {
 291        this.state = 'running';
 292        this.event('beforeSetup');
 293        if(this.setup) this.setup();
 294        this.event('afterSetup');
 295      }
 296      if(this.state == 'running') {
 297        if(this.options.transition) pos = this.options.transition(pos);
 298        pos *= (this.options.to-this.options.from);
 299        pos += this.options.from;
 300        this.position = pos;
 301        this.event('beforeUpdate');
 302        if(this.update) this.update(pos);
 303        this.event('afterUpdate');
 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(/MSIE/.test(navigator.userAgent) && !window.opera && (!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.camelize()] = '';
 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].underscore().dasherize(), 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(/MSIE/.test(navigator.userAgent) && !window.opera && (!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]), unit = (components.length == 3) ? components[2] : null;
 984  
 985        var originalValue = this.element.getStyle(property);
 986        return $H({ 
 987          style: property, 
 988          originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
 989          targetValue: unit=='color' ? parseColor(value) : value,
 990          unit: unit
 991        });
 992      }.bind(this)).reject(function(transform){
 993        return (
 994          (transform.originalValue == transform.targetValue) ||
 995          (
 996            transform.unit != 'color' &&
 997            (isNaN(transform.originalValue) || isNaN(transform.targetValue))
 998          )
 999        )
1000      });
1001    },
1002    update: function(position) {
1003      var style = $H(), value = null;
1004      this.transforms.each(function(transform){
1005        value = transform.unit=='color' ?
1006          $R(0,2).inject('#',function(m,v,i){
1007            return m+(Math.round(transform.originalValue[i]+
1008              (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : 
1009          transform.originalValue + Math.round(
1010            ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
1011        style[transform.style] = value;
1012      });
1013      this.element.setStyle(style);
1014    }
1015  });
1016  
1017  Effect.Transform = Class.create();
1018  Object.extend(Effect.Transform.prototype, {
1019    initialize: function(tracks){
1020      this.tracks  = [];
1021      this.options = arguments[1] || {};
1022      this.addTracks(tracks);
1023    },
1024    addTracks: function(tracks){
1025      tracks.each(function(track){
1026        var data = $H(track).values().first();
1027        this.tracks.push($H({
1028          ids:     $H(track).keys().first(),
1029          effect:  Effect.Morph,
1030          options: { style: data }
1031        }));
1032      }.bind(this));
1033      return this;
1034    },
1035    play: function(){
1036      return new Effect.Parallel(
1037        this.tracks.map(function(track){
1038          var elements = [$(track.ids) || $$(track.ids)].flatten();
1039          return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
1040        }).flatten(),
1041        this.options
1042      );
1043    }
1044  });
1045  
1046  Element.CSS_PROPERTIES = $w(
1047    'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
1048    'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
1049    'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
1050    'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
1051    'fontSize fontWeight height left letterSpacing lineHeight ' +
1052    'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
1053    'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
1054    'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
1055    'right textIndent top width wordSpacing zIndex');
1056    
1057  Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
1058  
1059  String.prototype.parseStyle = function(){
1060    var element = Element.extend(document.createElement('div'));
1061    element.innerHTML = '<div style="' + this + '"></div>';
1062    var style = element.down().style, styleRules = $H();
1063    
1064    Element.CSS_PROPERTIES.each(function(property){
1065      if(style[property]) styleRules[property] = style[property]; 
1066    });
1067    if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
1068      styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
1069    }
1070    return styleRules;
1071  };
1072  
1073  Element.morph = function(element, style) {
1074    new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
1075    return element;
1076  };
1077  
1078  ['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
1079   'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
1080    function(f) { Element.Methods[f] = Element[f]; }
1081  );
1082  
1083  Element.Methods.visualEffect = function(element, effect, options) {
1084    s = effect.gsub(/_/, '-').camelize();
1085    effect_class = s.charAt(0).toUpperCase() + s.substring(1);
1086    new Effect[effect_class](element, options);
1087    return $(element);
1088  };
1089  
1090  Element.addMethods();


Généré le : Sun Nov 25 17:13:16 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics