[ Index ]

PHP Cross Reference of phpwcms V1.4.3 _r380 (23.11.09)

title

Body

[close]

/template/inc_js/mootools/ -> mootools-uncompressed.js (source)

   1  //MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006 Valerio Proietti, <http://mad4milk.net>, MIT Style License.
   2  
   3  var MooTools = {
   4      version: '1.11'
   5  };
   6  
   7  function $defined(obj){
   8      return (obj != undefined);
   9  };
  10  
  11  function $type(obj){
  12      if (!$defined(obj)) return false;
  13      if (obj.htmlElement) return 'element';
  14      var type = typeof obj;
  15      if (type == 'object' && obj.nodeName){
  16          switch(obj.nodeType){
  17              case 1: return 'element';
  18              case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
  19          }
  20      }
  21      if (type == 'object' || type == 'function'){
  22          switch(obj.constructor){
  23              case Array: return 'array';
  24              case RegExp: return 'regexp';
  25              case Class: return 'class';
  26          }
  27          if (typeof obj.length == 'number'){
  28              if (obj.item) return 'collection';
  29              if (obj.callee) return 'arguments';
  30          }
  31      }
  32      return type;
  33  };
  34  
  35  function $merge(){
  36      var mix = {};
  37      for (var i = 0; i < arguments.length; i++){
  38          for (var property in arguments[i]){
  39              var ap = arguments[i][property];
  40              var mp = mix[property];
  41              if (mp && $type(ap) == 'object' && $type(mp) == 'object') mix[property] = $merge(mp, ap);
  42              else mix[property] = ap;
  43          }
  44      }
  45      return mix;
  46  };
  47  
  48  var $extend = function(){
  49      var args = arguments;
  50      if (!args[1]) args = [this, args[0]];
  51      for (var property in args[1]) args[0][property] = args[1][property];
  52      return args[0];
  53  };
  54  
  55  var $native = function(){
  56      for (var i = 0, l = arguments.length; i < l; i++){
  57          arguments[i].extend = function(props){
  58              for (var prop in props){
  59                  if (!this.prototype[prop]) this.prototype[prop] = props[prop];
  60                  if (!this[prop]) this[prop] = $native.generic(prop);
  61              }
  62          };
  63      }
  64  };
  65  
  66  $native.generic = function(prop){
  67      return function(bind){
  68          return this.prototype[prop].apply(bind, Array.prototype.slice.call(arguments, 1));
  69      };
  70  };
  71  
  72  $native(Function, Array, String, Number);
  73  
  74  function $chk(obj){
  75      return !!(obj || obj === 0);
  76  };
  77  
  78  function $pick(obj, picked){
  79      return $defined(obj) ? obj : picked;
  80  };
  81  
  82  function $random(min, max){
  83      return Math.floor(Math.random() * (max - min + 1) + min);
  84  };
  85  
  86  function $time(){
  87      return new Date().getTime();
  88  };
  89  
  90  function $clear(timer){
  91      clearTimeout(timer);
  92      clearInterval(timer);
  93      return null;
  94  };
  95  
  96  var Abstract = function(obj){
  97      obj = obj || {};
  98      obj.extend = $extend;
  99      return obj;
 100  };
 101  
 102  var Window = new Abstract(window);
 103  var Document = new Abstract(document);
 104  document.head = document.getElementsByTagName('head')[0];
 105  
 106  window.xpath = !!(document.evaluate);
 107  if (window.ActiveXObject) window.ie = window[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
 108  else if (document.childNodes && !document.all && !navigator.taintEnabled) window.webkit = window[window.xpath ? 'webkit420' : 'webkit419'] = true;
 109  else if (document.getBoxObjectFor != null) window.gecko = true;
 110  
 111  window.khtml = window.webkit;
 112  
 113  Object.extend = $extend;
 114  
 115  if (typeof HTMLElement == 'undefined'){
 116      var HTMLElement = function(){};
 117      if (window.webkit) document.createElement("iframe");
 118      HTMLElement.prototype = (window.webkit) ? window["[[DOMElement.prototype]]"] : {};
 119  }
 120  HTMLElement.prototype.htmlElement = function(){};
 121  
 122  if (window.ie6) try {document.execCommand("BackgroundImageCache", false, true);} catch(e){};
 123  
 124  var Class = function(properties){
 125      var klass = function(){
 126          return (arguments[0] !== null && this.initialize && $type(this.initialize) == 'function') ? this.initialize.apply(this, arguments) : this;
 127      };
 128      $extend(klass, this);
 129      klass.prototype = properties;
 130      klass.constructor = Class;
 131      return klass;
 132  };
 133  
 134  Class.empty = function(){};
 135  
 136  Class.prototype = {
 137  
 138      extend: function(properties){
 139          var proto = new this(null);
 140          for (var property in properties){
 141              var pp = proto[property];
 142              proto[property] = Class.Merge(pp, properties[property]);
 143          }
 144          return new Class(proto);
 145      },
 146  
 147      implement: function(){
 148          for (var i = 0, l = arguments.length; i < l; i++) $extend(this.prototype, arguments[i]);
 149      }
 150  
 151  };
 152  
 153  Class.Merge = function(previous, current){
 154      if (previous && previous != current){
 155          var type = $type(current);
 156          if (type != $type(previous)) return current;
 157          switch(type){
 158              case 'function':
 159                  var merged = function(){
 160                      this.parent = arguments.callee.parent;
 161                      return current.apply(this, arguments);
 162                  };
 163                  merged.parent = previous;
 164                  return merged;
 165              case 'object': return $merge(previous, current);
 166          }
 167      }
 168      return current;
 169  };
 170  
 171  var Chain = new Class({
 172  
 173      chain: function(fn){
 174          this.chains = this.chains || [];
 175          this.chains.push(fn);
 176          return this;
 177      },
 178  
 179      callChain: function(){
 180          if (this.chains && this.chains.length) this.chains.shift().delay(10, this);
 181      },
 182  
 183      clearChain: function(){
 184          this.chains = [];
 185      }
 186  
 187  });
 188  
 189  var Events = new Class({
 190  
 191      addEvent: function(type, fn){
 192          if (fn != Class.empty){
 193              this.$events = this.$events || {};
 194              this.$events[type] = this.$events[type] || [];
 195              this.$events[type].include(fn);
 196          }
 197          return this;
 198      },
 199  
 200      fireEvent: function(type, args, delay){
 201          if (this.$events && this.$events[type]){
 202              this.$events[type].each(function(fn){
 203                  fn.create({'bind': this, 'delay': delay, 'arguments': args})();
 204              }, this);
 205          }
 206          return this;
 207      },
 208  
 209      removeEvent: function(type, fn){
 210          if (this.$events && this.$events[type]) this.$events[type].remove(fn);
 211          return this;
 212      }
 213  
 214  });
 215  
 216  var Options = new Class({
 217  
 218      setOptions: function(){
 219          this.options = $merge.apply(null, [this.options].extend(arguments));
 220          if (this.addEvent){
 221              for (var option in this.options){
 222                  if ($type(this.options[option] == 'function') && (/^on[A-Z]/).test(option)) this.addEvent(option, this.options[option]);
 223              }
 224          }
 225          return this;
 226      }
 227  
 228  });
 229  
 230  Array.extend({
 231  
 232      forEach: function(fn, bind){
 233          for (var i = 0, j = this.length; i < j; i++) fn.call(bind, this[i], i, this);
 234      },
 235  
 236      filter: function(fn, bind){
 237          var results = [];
 238          for (var i = 0, j = this.length; i < j; i++){
 239              if (fn.call(bind, this[i], i, this)) results.push(this[i]);
 240          }
 241          return results;
 242      },
 243  
 244      map: function(fn, bind){
 245          var results = [];
 246          for (var i = 0, j = this.length; i < j; i++) results[i] = fn.call(bind, this[i], i, this);
 247          return results;
 248      },
 249  
 250      every: function(fn, bind){
 251          for (var i = 0, j = this.length; i < j; i++){
 252              if (!fn.call(bind, this[i], i, this)) return false;
 253          }
 254          return true;
 255      },
 256  
 257      some: function(fn, bind){
 258          for (var i = 0, j = this.length; i < j; i++){
 259              if (fn.call(bind, this[i], i, this)) return true;
 260          }
 261          return false;
 262      },
 263  
 264      indexOf: function(item, from){
 265          var len = this.length;
 266          for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
 267              if (this[i] === item) return i;
 268          }
 269          return -1;
 270      },
 271  
 272      copy: function(start, length){
 273          start = start || 0;
 274          if (start < 0) start = this.length + start;
 275          length = length || (this.length - start);
 276          var newArray = [];
 277          for (var i = 0; i < length; i++) newArray[i] = this[start++];
 278          return newArray;
 279      },
 280  
 281      remove: function(item){
 282          var i = 0;
 283          var len = this.length;
 284          while (i < len){
 285              if (this[i] === item){
 286                  this.splice(i, 1);
 287                  len--;
 288              } else {
 289                  i++;
 290              }
 291          }
 292          return this;
 293      },
 294  
 295      contains: function(item, from){
 296          return this.indexOf(item, from) != -1;
 297      },
 298  
 299      associate: function(keys){
 300          var obj = {}, length = Math.min(this.length, keys.length);
 301          for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
 302          return obj;
 303      },
 304  
 305      extend: function(array){
 306          for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
 307          return this;
 308      },
 309  
 310      merge: function(array){
 311          for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
 312          return this;
 313      },
 314  
 315      include: function(item){
 316          if (!this.contains(item)) this.push(item);
 317          return this;
 318      },
 319  
 320      getRandom: function(){
 321          return this[$random(0, this.length - 1)] || null;
 322      },
 323  
 324      getLast: function(){
 325          return this[this.length - 1] || null;
 326      }
 327  
 328  });
 329  
 330  Array.prototype.each = Array.prototype.forEach;
 331  Array.each = Array.forEach;
 332  
 333  function $A(array){
 334      return Array.copy(array);
 335  };
 336  
 337  function $each(iterable, fn, bind){
 338      if (iterable && typeof iterable.length == 'number' && $type(iterable) != 'object'){
 339          Array.forEach(iterable, fn, bind);
 340      } else {
 341           for (var name in iterable) fn.call(bind || iterable, iterable[name], name);
 342      }
 343  };
 344  
 345  Array.prototype.test = Array.prototype.contains;
 346  
 347  String.extend({
 348  
 349      test: function(regex, params){
 350          return (($type(regex) == 'string') ? new RegExp(regex, params) : regex).test(this);
 351      },
 352  
 353      toInt: function(){
 354          return parseInt(this, 10);
 355      },
 356  
 357      toFloat: function(){
 358          return parseFloat(this);
 359      },
 360  
 361      camelCase: function(){
 362          return this.replace(/-\D/g, function(match){
 363              return match.charAt(1).toUpperCase();
 364          });
 365      },
 366  
 367      hyphenate: function(){
 368          return this.replace(/\w[A-Z]/g, function(match){
 369              return (match.charAt(0) + '-' + match.charAt(1).toLowerCase());
 370          });
 371      },
 372  
 373      capitalize: function(){
 374          return this.replace(/\b[a-z]/g, function(match){
 375              return match.toUpperCase();
 376          });
 377      },
 378  
 379      trim: function(){
 380          return this.replace(/^\s+|\s+$/g, '');
 381      },
 382  
 383      clean: function(){
 384          return this.replace(/\s{2,}/g, ' ').trim();
 385      },
 386  
 387      rgbToHex: function(array){
 388          var rgb = this.match(/\d{1,3}/g);
 389          return (rgb) ? rgb.rgbToHex(array) : false;
 390      },
 391  
 392      hexToRgb: function(array){
 393          var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
 394          return (hex) ? hex.slice(1).hexToRgb(array) : false;
 395      },
 396  
 397      contains: function(string, s){
 398          return (s) ? (s + this + s).indexOf(s + string + s) > -1 : this.indexOf(string) > -1;
 399      },
 400  
 401      escapeRegExp: function(){
 402          return this.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
 403      }
 404  
 405  });
 406  
 407  Array.extend({
 408  
 409      rgbToHex: function(array){
 410          if (this.length < 3) return false;
 411          if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
 412          var hex = [];
 413          for (var i = 0; i < 3; i++){
 414              var bit = (this[i] - 0).toString(16);
 415              hex.push((bit.length == 1) ? '0' + bit : bit);
 416          }
 417          return array ? hex : '#' + hex.join('');
 418      },
 419  
 420      hexToRgb: function(array){
 421          if (this.length != 3) return false;
 422          var rgb = [];
 423          for (var i = 0; i < 3; i++){
 424              rgb.push(parseInt((this[i].length == 1) ? this[i] + this[i] : this[i], 16));
 425          }
 426          return array ? rgb : 'rgb(' + rgb.join(',') + ')';
 427      }
 428  
 429  });
 430  
 431  Function.extend({
 432  
 433      create: function(options){
 434          var fn = this;
 435          options = $merge({
 436              'bind': fn,
 437              'event': false,
 438              'arguments': null,
 439              'delay': false,
 440              'periodical': false,
 441              'attempt': false
 442          }, options);
 443          if ($chk(options.arguments) && $type(options.arguments) != 'array') options.arguments = [options.arguments];
 444          return function(event){
 445              var args;
 446              if (options.event){
 447                  event = event || window.event;
 448                  args = [(options.event === true) ? event : new options.event(event)];
 449                  if (options.arguments) args.extend(options.arguments);
 450              }
 451              else args = options.arguments || arguments;
 452              var returns = function(){
 453                  return fn.apply($pick(options.bind, fn), args);
 454              };
 455              if (options.delay) return setTimeout(returns, options.delay);
 456              if (options.periodical) return setInterval(returns, options.periodical);
 457              if (options.attempt) try {return returns();} catch(err){return false;};
 458              return returns();
 459          };
 460      },
 461  
 462      pass: function(args, bind){
 463          return this.create({'arguments': args, 'bind': bind});
 464      },
 465  
 466      attempt: function(args, bind){
 467          return this.create({'arguments': args, 'bind': bind, 'attempt': true})();
 468      },
 469  
 470      bind: function(bind, args){
 471          return this.create({'bind': bind, 'arguments': args});
 472      },
 473  
 474      bindAsEventListener: function(bind, args){
 475          return this.create({'bind': bind, 'event': true, 'arguments': args});
 476      },
 477  
 478      delay: function(delay, bind, args){
 479          return this.create({'delay': delay, 'bind': bind, 'arguments': args})();
 480      },
 481  
 482      periodical: function(interval, bind, args){
 483          return this.create({'periodical': interval, 'bind': bind, 'arguments': args})();
 484      }
 485  
 486  });
 487  
 488  Number.extend({
 489  
 490      toInt: function(){
 491          return parseInt(this);
 492      },
 493  
 494      toFloat: function(){
 495          return parseFloat(this);
 496      },
 497  
 498      limit: function(min, max){
 499          return Math.min(max, Math.max(min, this));
 500      },
 501  
 502      round: function(precision){
 503          precision = Math.pow(10, precision || 0);
 504          return Math.round(this * precision) / precision;
 505      },
 506  
 507      times: function(fn){
 508          for (var i = 0; i < this; i++) fn(i);
 509      }
 510  
 511  });
 512  
 513  var Element = new Class({
 514  
 515      initialize: function(el, props){
 516          if ($type(el) == 'string'){
 517              if (window.ie && props && (props.name || props.type)){
 518                  var name = (props.name) ? ' name="' + props.name + '"' : '';
 519                  var type = (props.type) ? ' type="' + props.type + '"' : '';
 520                  delete props.name;
 521                  delete props.type;
 522                  el = '<' + el + name + type + '>';
 523              }
 524              el = document.createElement(el);
 525          }
 526          el = $(el);
 527          return (!props || !el) ? el : el.set(props);
 528      }
 529  
 530  });
 531  
 532  var Elements = new Class({
 533  
 534      initialize: function(elements){
 535          return (elements) ? $extend(elements, this) : this;
 536      }
 537  
 538  });
 539  
 540  Elements.extend = function(props){
 541      for (var prop in props){
 542          this.prototype[prop] = props[prop];
 543          this[prop] = $native.generic(prop);
 544      }
 545  };
 546  
 547  function $(el){
 548      if (!el) return null;
 549      if (el.htmlElement) return Garbage.collect(el);
 550      if ([window, document].contains(el)) return el;
 551      var type = $type(el);
 552      if (type == 'string'){
 553          el = document.getElementById(el);
 554          type = (el) ? 'element' : false;
 555      }
 556      if (type != 'element') return null;
 557      if (el.htmlElement) return Garbage.collect(el);
 558      if (['object', 'embed'].contains(el.tagName.toLowerCase())) return el;
 559      $extend(el, Element.prototype);
 560      el.htmlElement = function(){};
 561      return Garbage.collect(el);
 562  };
 563  
 564  document.getElementsBySelector = document.getElementsByTagName;
 565  
 566  function $$(){
 567      var elements = [];
 568      for (var i = 0, j = arguments.length; i < j; i++){
 569          var selector = arguments[i];
 570          switch($type(selector)){
 571              case 'element': elements.push(selector);
 572              case 'boolean': break;
 573              case false: break;
 574              case 'string': selector = document.getElementsBySelector(selector, true);
 575              default: elements.extend(selector);
 576          }
 577      }
 578      return $$.unique(elements);
 579  };
 580  
 581  $$.unique = function(array){
 582      var elements = [];
 583      for (var i = 0, l = array.length; i < l; i++){
 584          if (array[i].$included) continue;
 585          var element = $(array[i]);
 586          if (element && !element.$included){
 587              element.$included = true;
 588              elements.push(element);
 589          }
 590      }
 591      for (var n = 0, d = elements.length; n < d; n++) elements[n].$included = null;
 592      return new Elements(elements);
 593  };
 594  
 595  Elements.Multi = function(property){
 596      return function(){
 597          var args = arguments;
 598          var items = [];
 599          var elements = true;
 600          for (var i = 0, j = this.length, returns; i < j; i++){
 601              returns = this[i][property].apply(this[i], args);
 602              if ($type(returns) != 'element') elements = false;
 603              items.push(returns);
 604          };
 605          return (elements) ? $$.unique(items) : items;
 606      };
 607  };
 608  
 609  Element.extend = function(properties){
 610      for (var property in properties){
 611          HTMLElement.prototype[property] = properties[property];
 612          Element.prototype[property] = properties[property];
 613          Element[property] = $native.generic(property);
 614          var elementsProperty = (Array.prototype[property]) ? property + 'Elements' : property;
 615          Elements.prototype[elementsProperty] = Elements.Multi(property);
 616      }
 617  };
 618  
 619  Element.extend({
 620  
 621      set: function(props){
 622          for (var prop in props){
 623              var val = props[prop];
 624              switch(prop){
 625                  case 'styles': this.setStyles(val); break;
 626                  case 'events': if (this.addEvents) this.addEvents(val); break;
 627                  case 'properties': this.setProperties(val); break;
 628                  default: this.setProperty(prop, val);
 629              }
 630          }
 631          return this;
 632      },
 633  
 634      inject: function(el, where){
 635          el = $(el);
 636          switch(where){
 637              case 'before': el.parentNode.insertBefore(this, el); break;
 638              case 'after':
 639                  var next = el.getNext();
 640                  if (!next) el.parentNode.appendChild(this);
 641                  else el.parentNode.insertBefore(this, next);
 642                  break;
 643              case 'top':
 644                  var first = el.firstChild;
 645                  if (first){
 646                      el.insertBefore(this, first);
 647                      break;
 648                  }
 649              default: el.appendChild(this);
 650          }
 651          return this;
 652      },
 653  
 654      injectBefore: function(el){
 655          return this.inject(el, 'before');
 656      },
 657  
 658      injectAfter: function(el){
 659          return this.inject(el, 'after');
 660      },
 661  
 662      injectInside: function(el){
 663          return this.inject(el, 'bottom');
 664      },
 665  
 666      injectTop: function(el){
 667          return this.inject(el, 'top');
 668      },
 669  
 670      adopt: function(){
 671          var elements = [];
 672          $each(arguments, function(argument){
 673              elements = elements.concat(argument);
 674          });
 675          $$(elements).inject(this);
 676          return this;
 677      },
 678  
 679      remove: function(){
 680          return this.parentNode.removeChild(this);
 681      },
 682  
 683      clone: function(contents){
 684          var el = $(this.cloneNode(contents !== false));
 685          if (!el.$events) return el;
 686          el.$events = {};
 687          for (var type in this.$events) el.$events[type] = {
 688              'keys': $A(this.$events[type].keys),
 689              'values': $A(this.$events[type].values)
 690          };
 691          return el.removeEvents();
 692      },
 693  
 694      replaceWith: function(el){
 695          el = $(el);
 696          this.parentNode.replaceChild(el, this);
 697          return el;
 698      },
 699  
 700      appendText: function(text){
 701          this.appendChild(document.createTextNode(text));
 702          return this;
 703      },
 704  
 705      hasClass: function(className){
 706          return this.className.contains(className, ' ');
 707      },
 708  
 709      addClass: function(className){
 710          if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
 711          return this;
 712      },
 713  
 714      removeClass: function(className){
 715          this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1').clean();
 716          return this;
 717      },
 718  
 719      toggleClass: function(className){
 720          return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
 721      },
 722  
 723      setStyle: function(property, value){
 724          switch(property){
 725              case 'opacity': return this.setOpacity(parseFloat(value));
 726              case 'float': property = (window.ie) ? 'styleFloat' : 'cssFloat';
 727          }
 728          property = property.camelCase();
 729          switch($type(value)){
 730              case 'number': if (!['zIndex', 'zoom'].contains(property)) value += 'px'; break;
 731              case 'array': value = 'rgb(' + value.join(',') + ')';
 732          }
 733          this.style[property] = value;
 734          return this;
 735      },
 736  
 737      setStyles: function(source){
 738          switch($type(source)){
 739              case 'object': Element.setMany(this, 'setStyle', source); break;
 740              case 'string': this.style.cssText = source;
 741          }
 742          return this;
 743      },
 744  
 745      setOpacity: function(opacity){
 746          if (opacity == 0){
 747              if (this.style.visibility != "hidden") this.style.visibility = "hidden";
 748          } else {
 749              if (this.style.visibility != "visible") this.style.visibility = "visible";
 750          }
 751          if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
 752          if (window.ie) this.style.filter = (opacity == 1) ? '' : "alpha(opacity=" + opacity * 100 + ")";
 753          this.style.opacity = this.$tmp.opacity = opacity;
 754          return this;
 755      },
 756  
 757      getStyle: function(property){
 758          property = property.camelCase();
 759          var result = this.style[property];
 760          if (!$chk(result)){
 761              if (property == 'opacity') return this.$tmp.opacity;
 762              result = [];
 763              for (var style in Element.Styles){
 764                  if (property == style){
 765                      Element.Styles[style].each(function(s){
 766                          var style = this.getStyle(s);
 767                          result.push(parseInt(style) ? style : '0px');
 768                      }, this);
 769                      if (property == 'border'){
 770                          var every = result.every(function(bit){
 771                              return (bit == result[0]);
 772                          });
 773                          return (every) ? result[0] : false;
 774                      }
 775                      return result.join(' ');
 776                  }
 777              }
 778              if (property.contains('border')){
 779                  if (Element.Styles.border.contains(property)){
 780                      return ['Width', 'Style', 'Color'].map(function(p){
 781                          return this.getStyle(property + p);
 782                      }, this).join(' ');
 783                  } else if (Element.borderShort.contains(property)){
 784                      return ['Top', 'Right', 'Bottom', 'Left'].map(function(p){
 785                          return this.getStyle('border' + p + property.replace('border', ''));
 786                      }, this).join(' ');
 787                  }
 788              }
 789              if (document.defaultView) result = document.defaultView.getComputedStyle(this, null).getPropertyValue(property.hyphenate());
 790              else if (this.currentStyle) result = this.currentStyle[property];
 791          }
 792          if (window.ie) result = Element.fixStyle(property, result, this);
 793          if (result && property.test(/color/i) && result.contains('rgb')){
 794              return result.split('rgb').splice(1,4).map(function(color){
 795                  return color.rgbToHex();
 796              }).join(' ');
 797          }
 798          return result;
 799      },
 800  
 801      getStyles: function(){
 802          return Element.getMany(this, 'getStyle', arguments);
 803      },
 804  
 805      walk: function(brother, start){
 806          brother += 'Sibling';
 807          var el = (start) ? this[start] : this[brother];
 808          while (el && $type(el) != 'element') el = el[brother];
 809          return $(el);
 810      },
 811  
 812      getPrevious: function(){
 813          return this.walk('previous');
 814      },
 815  
 816      getNext: function(){
 817          return this.walk('next');
 818      },
 819  
 820      getFirst: function(){
 821          return this.walk('next', 'firstChild');
 822      },
 823  
 824      getLast: function(){
 825          return this.walk('previous', 'lastChild');
 826      },
 827  
 828      getParent: function(){
 829          return $(this.parentNode);
 830      },
 831  
 832      getChildren: function(){
 833          return $$(this.childNodes);
 834      },
 835  
 836      hasChild: function(el){
 837          return !!$A(this.getElementsByTagName('*')).contains(el);
 838      },
 839  
 840      getProperty: function(property){
 841          var index = Element.Properties[property];
 842          if (index) return this[index];
 843          var flag = Element.PropertiesIFlag[property] || 0;
 844          if (!window.ie || flag) return this.getAttribute(property, flag);
 845          var node = this.attributes[property];
 846          return (node) ? node.nodeValue : null;
 847      },
 848  
 849      removeProperty: function(property){
 850          var index = Element.Properties[property];
 851          if (index) this[index] = '';
 852          else this.removeAttribute(property);
 853          return this;
 854      },
 855  
 856      getProperties: function(){
 857          return Element.getMany(this, 'getProperty', arguments);
 858      },
 859  
 860      setProperty: function(property, value){
 861          var index = Element.Properties[property];
 862          if (index) this[index] = value;
 863          else this.setAttribute(property, value);
 864          return this;
 865      },
 866  
 867      setProperties: function(source){
 868          return Element.setMany(this, 'setProperty', source);
 869      },
 870  
 871      setHTML: function(){
 872          this.innerHTML = $A(arguments).join('');
 873          return this;
 874      },
 875  
 876      setText: function(text){
 877          var tag = this.getTag();
 878          if (['style', 'script'].contains(tag)){
 879              if (window.ie){
 880                  if (tag == 'style') this.styleSheet.cssText = text;
 881                  else if (tag ==  'script') this.setProperty('text', text);
 882                  return this;
 883              } else {
 884                  this.removeChild(this.firstChild);
 885                  return this.appendText(text);
 886              }
 887          }
 888          this[$defined(this.innerText) ? 'innerText' : 'textContent'] = text;
 889          return this;
 890      },
 891  
 892      getText: function(){
 893          var tag = this.getTag();
 894          if (['style', 'script'].contains(tag)){
 895              if (window.ie){
 896                  if (tag == 'style') return this.styleSheet.cssText;
 897                  else if (tag ==  'script') return this.getProperty('text');
 898              } else {
 899                  return this.innerHTML;
 900              }
 901          }
 902          return ($pick(this.innerText, this.textContent));
 903      },
 904  
 905      getTag: function(){
 906          return this.tagName.toLowerCase();
 907      },
 908  
 909      empty: function(){
 910          Garbage.trash(this.getElementsByTagName('*'));
 911          return this.setHTML('');
 912      }
 913  
 914  });
 915  
 916  Element.fixStyle = function(property, result, element){
 917      if ($chk(parseInt(result))) return result;
 918      if (['height', 'width'].contains(property)){
 919          var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'];
 920          var size = 0;
 921          values.each(function(value){
 922              size += element.getStyle('border-' + value + '-width').toInt() + element.getStyle('padding-' + value).toInt();
 923          });
 924          return element['offset' + property.capitalize()] - size + 'px';
 925      } else if (property.test(/border(.+)Width|margin|padding/)){
 926          return '0px';
 927      }
 928      return result;
 929  };
 930  
 931  Element.Styles = {'border': [], 'padding': [], 'margin': []};
 932  ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
 933      for (var style in Element.Styles) Element.Styles[style].push(style + direction);
 934  });
 935  
 936  Element.borderShort = ['borderWidth', 'borderStyle', 'borderColor'];
 937  
 938  Element.getMany = function(el, method, keys){
 939      var result = {};
 940      $each(keys, function(key){
 941          result[key] = el[method](key);
 942      });
 943      return result;
 944  };
 945  
 946  Element.setMany = function(el, method, pairs){
 947      for (var key in pairs) el[method](key, pairs[key]);
 948      return el;
 949  };
 950  
 951  Element.Properties = new Abstract({
 952      'class': 'className', 'for': 'htmlFor', 'colspan': 'colSpan', 'rowspan': 'rowSpan',
 953      'accesskey': 'accessKey', 'tabindex': 'tabIndex', 'maxlength': 'maxLength',
 954      'readonly': 'readOnly', 'frameborder': 'frameBorder', 'value': 'value',
 955      'disabled': 'disabled', 'checked': 'checked', 'multiple': 'multiple', 'selected': 'selected'
 956  });
 957  Element.PropertiesIFlag = {
 958      'href': 2, 'src': 2
 959  };
 960  
 961  Element.Methods = {
 962      Listeners: {
 963          addListener: function(type, fn){
 964              if (this.addEventListener) this.addEventListener(type, fn, false);
 965              else this.attachEvent('on' + type, fn);
 966              return this;
 967          },
 968  
 969          removeListener: function(type, fn){
 970              if (this.removeEventListener) this.removeEventListener(type, fn, false);
 971              else this.detachEvent('on' + type, fn);
 972              return this;
 973          }
 974      }
 975  };
 976  
 977  window.extend(Element.Methods.Listeners);
 978  document.extend(Element.Methods.Listeners);
 979  Element.extend(Element.Methods.Listeners);
 980  
 981  var Garbage = {
 982  
 983      elements: [],
 984  
 985      collect: function(el){
 986          if (!el.$tmp){
 987              Garbage.elements.push(el);
 988              el.$tmp = {'opacity': 1};
 989          }
 990          return el;
 991      },
 992  
 993      trash: function(elements){
 994          for (var i = 0, j = elements.length, el; i < j; i++){
 995              if (!(el = elements[i]) || !el.$tmp) continue;
 996              if (el.$events) el.fireEvent('trash').removeEvents();
 997              for (var p in el.$tmp) el.$tmp[p] = null;
 998              for (var d in Element.prototype) el[d] = null;
 999              Garbage.elements[Garbage.elements.indexOf(el)] = null;
1000              el.htmlElement = el.$tmp = el = null;
1001          }
1002          Garbage.elements.remove(null);
1003      },
1004  
1005      empty: function(){
1006          Garbage.collect(window);
1007          Garbage.collect(document);
1008          Garbage.trash(Garbage.elements);
1009      }
1010  
1011  };
1012  
1013  window.addListener('beforeunload', function(){
1014      window.addListener('unload', Garbage.empty);
1015      if (window.ie) window.addListener('unload', CollectGarbage);
1016  });
1017  
1018  var Event = new Class({
1019  
1020      initialize: function(event){
1021          if (event && event.$extended) return event;
1022          this.$extended = true;
1023          event = event || window.event;
1024          this.event = event;
1025          this.type = event.type;
1026          this.target = event.target || event.srcElement;
1027          if (this.target.nodeType == 3) this.target = this.target.parentNode;
1028          this.shift = event.shiftKey;
1029          this.control = event.ctrlKey;
1030          this.alt = event.altKey;
1031          this.meta = event.metaKey;
1032          if (['DOMMouseScroll', 'mousewheel'].contains(this.type)){
1033              this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
1034          } else if (this.type.contains('key')){
1035              this.code = event.which || event.keyCode;
1036              for (var name in Event.keys){
1037                  if (Event.keys[name] == this.code){
1038                      this.key = name;
1039                      break;
1040                  }
1041              }
1042              if (this.type == 'keydown'){
1043                  var fKey = this.code - 111;
1044                  if (fKey > 0 && fKey < 13) this.key = 'f' + fKey;
1045              }
1046              this.key = this.key || String.fromCharCode(this.code).toLowerCase();
1047          } else if (this.type.test(/(click|mouse|menu)/)){
1048              this.page = {
1049                  'x': event.pageX || event.clientX + document.documentElement.scrollLeft,
1050                  'y': event.pageY || event.clientY + document.documentElement.scrollTop
1051              };
1052              this.client = {
1053                  'x': event.pageX ? event.pageX - window.pageXOffset : event.clientX,
1054                  'y': event.pageY ? event.pageY - window.pageYOffset : event.clientY
1055              };
1056              this.rightClick = (event.which == 3) || (event.button == 2);
1057              switch(this.type){
1058                  case 'mouseover': this.relatedTarget = event.relatedTarget || event.fromElement; break;
1059                  case 'mouseout': this.relatedTarget = event.relatedTarget || event.toElement;
1060              }
1061              this.fixRelatedTarget();
1062          }
1063          return this;
1064      },
1065  
1066      stop: function(){
1067          return this.stopPropagation().preventDefault();
1068      },
1069  
1070      stopPropagation: function(){
1071          if (this.event.stopPropagation) this.event.stopPropagation();
1072          else this.event.cancelBubble = true;
1073          return this;
1074      },
1075  
1076      preventDefault: function(){
1077          if (this.event.preventDefault) this.event.preventDefault();
1078          else this.event.returnValue = false;
1079          return this;
1080      }
1081  
1082  });
1083  
1084  Event.fix = {
1085  
1086      relatedTarget: function(){
1087          if (this.relatedTarget && this.relatedTarget.nodeType == 3) this.relatedTarget = this.relatedTarget.parentNode;
1088      },
1089  
1090      relatedTargetGecko: function(){
1091          try {Event.fix.relatedTarget.call(this);} catch(e){this.relatedTarget = this.target;}
1092      }
1093  
1094  };
1095  
1096  Event.prototype.fixRelatedTarget = (window.gecko) ? Event.fix.relatedTargetGecko : Event.fix.relatedTarget;
1097  
1098  Event.keys = new Abstract({
1099      'enter': 13,
1100      'up': 38,
1101      'down': 40,
1102      'left': 37,
1103      'right': 39,
1104      'esc': 27,
1105      'space': 32,
1106      'backspace': 8,
1107      'tab': 9,
1108      'delete': 46
1109  });
1110  
1111  Element.Methods.Events = {
1112  
1113      addEvent: function(type, fn){
1114          this.$events = this.$events || {};
1115          this.$events[type] = this.$events[type] || {'keys': [], 'values': []};
1116          if (this.$events[type].keys.contains(fn)) return this;
1117          this.$events[type].keys.push(fn);
1118          var realType = type;
1119          var custom = Element.Events[type];
1120          if (custom){
1121              if (custom.add) custom.add.call(this, fn);
1122              if (custom.map) fn = custom.map;
1123              if (custom.type) realType = custom.type;
1124          }
1125          if (!this.addEventListener) fn = fn.create({'bind': this, 'event': true});
1126          this.$events[type].values.push(fn);
1127          return (Element.NativeEvents.contains(realType)) ? this.addListener(realType, fn) : this;
1128      },
1129  
1130      removeEvent: function(type, fn){
1131          if (!this.$events || !this.$events[type]) return this;
1132          var pos = this.$events[type].keys.indexOf(fn);
1133          if (pos == -1) return this;
1134          var key = this.$events[type].keys.splice(pos,1)[0];
1135          var value = this.$events[type].values.splice(pos,1)[0];
1136          var custom = Element.Events[type];
1137          if (custom){
1138              if (custom.remove) custom.remove.call(this, fn);
1139              if (custom.type) type = custom.type;
1140          }
1141          return (Element.NativeEvents.contains(type)) ? this.removeListener(type, value) : this;
1142      },
1143  
1144      addEvents: function(source){
1145          return Element.setMany(this, 'addEvent', source);
1146      },
1147  
1148      removeEvents: function(type){
1149          if (!this.$events) return this;
1150          if (!type){
1151              for (var evType in this.$events) this.removeEvents(evType);
1152              this.$events = null;
1153          } else if (this.$events[type]){
1154              this.$events[type].keys.each(function(fn){
1155                  this.removeEvent(type, fn);
1156              }, this);
1157              this.$events[type] = null;
1158          }
1159          return this;
1160      },
1161  
1162      fireEvent: function(type, args, delay){
1163          if (this.$events && this.$events[type]){
1164              this.$events[type].keys.each(function(fn){
1165                  fn.create({'bind': this, 'delay': delay, 'arguments': args})();
1166              }, this);
1167          }
1168          return this;
1169      },
1170  
1171      cloneEvents: function(from, type){
1172          if (!from.$events) return this;
1173          if (!type){
1174              for (var evType in from.$events) this.cloneEvents(from, evType);
1175          } else if (from.$events[type]){
1176              from.$events[type].keys.each(function(fn){
1177                  this.addEvent(type, fn);
1178              }, this);
1179          }
1180          return this;
1181      }
1182  
1183  };
1184  
1185  window.extend(Element.Methods.Events);
1186  document.extend(Element.Methods.Events);
1187  Element.extend(Element.Methods.Events);
1188  
1189  Element.Events = new Abstract({
1190  
1191      'mouseenter': {
1192          type: 'mouseover',
1193          map: function(event){
1194              event = new Event(event);
1195              if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseenter', event);
1196          }
1197      },
1198  
1199      'mouseleave': {
1200          type: 'mouseout',
1201          map: function(event){
1202              event = new Event(event);
1203              if (event.relatedTarget != this && !this.hasChild(event.relatedTarget)) this.fireEvent('mouseleave', event);
1204          }
1205      },
1206  
1207      'mousewheel': {
1208          type: (window.gecko) ? 'DOMMouseScroll' : 'mousewheel'
1209      }
1210  
1211  });
1212  
1213  Element.NativeEvents = [
1214      'click', 'dblclick', 'mouseup', 'mousedown',
1215      'mousewheel', 'DOMMouseScroll',
1216      'mouseover', 'mouseout', 'mousemove',
1217      'keydown', 'keypress', 'keyup',
1218      'load', 'unload', 'beforeunload', 'resize', 'move',
1219      'focus', 'blur', 'change', 'submit', 'reset', 'select',
1220      'error', 'abort', 'contextmenu', 'scroll'
1221  ];
1222  
1223  Function.extend({
1224  
1225      bindWithEvent: function(bind, args){
1226          return this.create({'bind': bind, 'arguments': args, 'event': Event});
1227      }
1228  
1229  });
1230  
1231  Elements.extend({
1232  
1233      filterByTag: function(tag){
1234          return new Elements(this.filter(function(el){
1235              return (Element.getTag(el) == tag);
1236          }));
1237      },
1238  
1239      filterByClass: function(className, nocash){
1240          var elements = this.filter(function(el){
1241              return (el.className && el.className.contains(className, ' '));
1242          });
1243          return (nocash) ? elements : new Elements(elements);
1244      },
1245  
1246      filterById: function(id, nocash){
1247          var elements = this.filter(function(el){
1248              return (el.id == id);
1249          });
1250          return (nocash) ? elements : new Elements(elements);
1251      },
1252  
1253      filterByAttribute: function(name, operator, value, nocash){
1254          var elements = this.filter(function(el){
1255              var current = Element.getProperty(el, name);
1256              if (!current) return false;
1257              if (!operator) return true;
1258              switch(operator){
1259                  case '=': return (current == value);
1260                  case '*=': return (current.contains(value));
1261                  case '^=': return (current.substr(0, value.length) == value);
1262                  case '$=': return (current.substr(current.length - value.length) == value);
1263                  case '!=': return (current != value);
1264                  case '~=': return current.contains(value, ' ');
1265              }
1266              return false;
1267          });
1268          return (nocash) ? elements : new Elements(elements);
1269      }
1270  
1271  });
1272  
1273  function $E(selector, filter){
1274      return ($(filter) || document).getElement(selector);
1275  };
1276  
1277  function $ES(selector, filter){
1278      return ($(filter) || document).getElementsBySelector(selector);
1279  };
1280  
1281  $$.shared = {
1282  
1283      'regexp': /^(\w*|\*)(?:#([\w-]+)|\.([\w-]+))?(?:\[(\w+)(?:([!*^$]?=)["']?([^"'\]]*)["']?)?])?$/,
1284  
1285      'xpath': {
1286  
1287          getParam: function(items, context, param, i){
1288              var temp = [context.namespaceURI ? 'xhtml:' : '', param[1]];
1289              if (param[2]) temp.push('[@id="', param[2], '"]');
1290              if (param[3]) temp.push('[contains(concat(" ", @class, " "), " ', param[3], ' ")]');
1291              if (param[4]){
1292                  if (param[5] && param[6]){
1293                      switch(param[5]){
1294                          case '*=': temp.push('[contains(@', param[4], ', "', param[6], '")]'); break;
1295                          case '^=': temp.push('[starts-with(@', param[4], ', "', param[6], '")]'); break;
1296                          case '$=': temp.push('[substring(@', param[4], ', string-length(@', param[4], ') - ', param[6].length, ' + 1) = "', param[6], '"]'); break;
1297                          case '=': temp.push('[@', param[4], '="', param[6], '"]'); break;
1298                          case '!=': temp.push('[@', param[4], '!="', param[6], '"]');
1299                      }
1300                  } else {
1301                      temp.push('[@', param[4], ']');
1302                  }
1303              }
1304              items.push(temp.join(''));
1305              return items;
1306          },
1307  
1308          getItems: function(items, context, nocash){
1309              var elements = [];
1310              var xpath = document.evaluate('.//' + items.join('//'), context, $$.shared.resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
1311              for (var i = 0, j = xpath.snapshotLength; i < j; i++) elements.push(xpath.snapshotItem(i));
1312              return (nocash) ? elements : new Elements(elements.map($));
1313          }
1314  
1315      },
1316  
1317      'normal': {
1318  
1319          getParam: function(items, context, param, i){
1320              if (i == 0){
1321                  if (param[2]){
1322                      var el = context.getElementById(param[2]);
1323                      if (!el || ((param[1] != '*') && (Element.getTag(el) != param[1]))) return false;
1324                      items = [el];
1325                  } else {
1326                      items = $A(context.getElementsByTagName(param[1]));
1327                  }
1328              } else {
1329                  items = $$.shared.getElementsByTagName(items, param[1]);
1330                  if (param[2]) items = Elements.filterById(items, param[2], true);
1331              }
1332              if (param[3]) items = Elements.filterByClass(items, param[3], true);
1333              if (param[4]) items = Elements.filterByAttribute(items, param[4], param[5], param[6], true);
1334              return items;
1335          },
1336  
1337          getItems: function(items, context, nocash){
1338              return (nocash) ? items : $$.unique(items);
1339          }
1340  
1341      },
1342  
1343      resolver: function(prefix){
1344          return (prefix == 'xhtml') ? 'http://www.w3.org/1999/xhtml' : false;
1345      },
1346  
1347      getElementsByTagName: function(context, tagName){
1348          var found = [];
1349          for (var i = 0, j = context.length; i < j; i++) found.extend(context[i].getElementsByTagName(tagName));
1350          return found;
1351      }
1352  
1353  };
1354  
1355  $$.shared.method = (window.xpath) ? 'xpath' : 'normal';
1356  
1357  Element.Methods.Dom = {
1358  
1359      getElements: function(selector, nocash){
1360          var items = [];
1361          selector = selector.trim().split(' ');
1362          for (var i = 0, j = selector.length; i < j; i++){
1363              var sel = selector[i];
1364              var param = sel.match($$.shared.regexp);
1365              if (!param) break;
1366              param[1] = param[1] || '*';
1367              var temp = $$.shared[$$.shared.method].getParam(items, this, param, i);
1368              if (!temp) break;
1369              items = temp;
1370          }
1371          return $$.shared[$$.shared.method].getItems(items, this, nocash);
1372      },
1373  
1374      getElement: function(selector){
1375          return $(this.getElements(selector, true)[0] || false);
1376      },
1377  
1378      getElementsBySelector: function(selector, nocash){
1379          var elements = [];
1380          selector = selector.split(',');
1381          for (var i = 0, j = selector.length; i < j; i++) elements = elements.concat(this.getElements(selector[i], true));
1382          return (nocash) ? elements : $$.unique(elements);
1383      }
1384  
1385  };
1386  
1387  Element.extend({
1388  
1389      getElementById: function(id){
1390          var el = document.getElementById(id);
1391          if (!el) return false;
1392          for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
1393              if (!parent) return false;
1394          }
1395          return el;
1396      }/*compatibility*/,
1397  
1398      getElementsByClassName: function(className){ 
1399          return this.getElements('.' + className); 
1400      }
1401  
1402  });
1403  
1404  document.extend(Element.Methods.Dom);
1405  Element.extend(Element.Methods.Dom);
1406  
1407  Element.extend({
1408  
1409      getValue: function(){
1410          switch(this.getTag()){
1411              case 'select':
1412                  var values = [];
1413                  $each(this.options, function(option){
1414                      if (option.selected) values.push($pick(option.value, option.text));
1415                  });
1416                  return (this.multiple) ? values : values[0];
1417              case 'input': if (!(this.checked && ['checkbox', 'radio'].contains(this.type)) && !['hidden', 'text', 'password'].contains(this.type)) break;
1418              case 'textarea': return this.value;
1419          }
1420          return false;
1421      },
1422  
1423      getFormElements: function(){
1424          return $$(this.getElementsByTagName('input'), this.getElementsByTagName('select'), this.getElementsByTagName('textarea'));
1425      },
1426  
1427      toQueryString: function(){
1428          var queryString = [];
1429          this.getFormElements().each(function(el){
1430              var name = el.name;
1431              var value = el.getValue();
1432              if (value === false || !name || el.disabled) return;
1433              var qs = function(val){
1434                  queryString.push(name + '=' + encodeURIComponent(val));
1435              };
1436              if ($type(value) == 'array') value.each(qs);
1437              else qs(value);
1438          });
1439          return queryString.join('&');
1440      }
1441  
1442  });
1443  
1444  Element.extend({
1445  
1446      scrollTo: function(x, y){
1447          this.scrollLeft = x;
1448          this.scrollTop = y;
1449      },
1450  
1451      getSize: function(){
1452          return {
1453              'scroll': {'x': this.scrollLeft, 'y': this.scrollTop},
1454              'size': {'x': this.offsetWidth, 'y': this.offsetHeight},
1455              'scrollSize': {'x': this.scrollWidth, 'y': this.scrollHeight}
1456          };
1457      },
1458  
1459      getPosition: function(overflown){
1460          overflown = overflown || [];
1461          var el = this, left = 0, top = 0;
1462          do {
1463              left += el.offsetLeft || 0;
1464              top += el.offsetTop || 0;
1465              el = el.offsetParent;
1466          } while (el);
1467          overflown.each(function(element){
1468              left -= element.scrollLeft || 0;
1469              top -= element.scrollTop || 0;
1470          });
1471          return {'x': left, 'y': top};
1472      },
1473  
1474      getTop: function(overflown){
1475          return this.getPosition(overflown).y;
1476      },
1477  
1478      getLeft: function(overflown){
1479          return this.getPosition(overflown).x;
1480      },
1481  
1482      getCoordinates: function(overflown){
1483          var position = this.getPosition(overflown);
1484          var obj = {
1485              'width': this.offsetWidth,
1486              'height': this.offsetHeight,
1487              'left': position.x,
1488              'top': position.y
1489          };
1490          obj.right = obj.left + obj.width;
1491          obj.bottom = obj.top + obj.height;
1492          return obj;
1493      }
1494  
1495  });
1496  
1497  Element.Events.domready = {
1498  
1499      add: function(fn){
1500          if (window.loaded){
1501              fn.call(this);
1502              return;
1503          }
1504          var domReady = function(){
1505              if (window.loaded) return;
1506              window.loaded = true;
1507              window.timer = $clear(window.timer);
1508              this.fireEvent('domready');
1509          }.bind(this);
1510          if (document.readyState && window.webkit){
1511              window.timer = function(){
1512                  if (['loaded','complete'].contains(document.readyState)) domReady();
1513              }.periodical(50);
1514          } else if (document.readyState && window.ie){
1515              if (!$('ie_ready')){
1516                  var src = (window.location.protocol == 'https:') ? '://0' : 'javascript:void(0)';
1517                  document.write('<script id="ie_ready" defer src="' + src + '"><\/script>');
1518                  $('ie_ready').onreadystatechange = function(){
1519                      if (this.readyState == 'complete') domReady();
1520                  };
1521              }
1522          } else {
1523              window.addListener("load", domReady);
1524              document.addListener("DOMContentLoaded", domReady);
1525          }
1526      }
1527  
1528  };
1529  
1530  window.onDomReady = function(fn){ 
1531      return this.addEvent('domready', fn); 
1532  };
1533  
1534  window.extend({
1535  
1536      getWidth: function(){
1537          if (this.webkit419) return this.innerWidth;
1538          if (this.opera) return document.body.clientWidth;
1539          return document.documentElement.clientWidth;
1540      },
1541  
1542      getHeight: function(){
1543          if (this.webkit419) return this.innerHeight;
1544          if (this.opera) return document.body.clientHeight;
1545          return document.documentElement.clientHeight;
1546      },
1547  
1548      getScrollWidth: function(){
1549          if (this.ie) return Math.max(document.documentElement.offsetWidth, document.documentElement.scrollWidth);
1550          if (this.webkit) return document.body.scrollWidth;
1551          return document.documentElement.scrollWidth;
1552      },
1553  
1554      getScrollHeight: function(){
1555          if (this.ie) return Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight);
1556          if (this.webkit) return document.body.scrollHeight;
1557          return document.documentElement.scrollHeight;
1558      },
1559  
1560      getScrollLeft: function(){
1561          return this.pageXOffset || document.documentElement.scrollLeft;
1562      },
1563  
1564      getScrollTop: function(){
1565          return this.pageYOffset || document.documentElement.scrollTop;
1566      },
1567  
1568      getSize: function(){
1569          return {
1570              'size': {'x': this.getWidth(), 'y': this.getHeight()},
1571              'scrollSize': {'x': this.getScrollWidth(), 'y': this.getScrollHeight()},
1572              'scroll': {'x': this.getScrollLeft(), 'y': this.getScrollTop()}
1573          };
1574      },
1575      getPosition: function(){return {'x': 0, 'y': 0};}
1576  
1577  });
1578  
1579  var Fx = {};
1580  
1581  Fx.Base = new Class({
1582  
1583      options: {
1584          onStart: Class.empty,
1585          onComplete: Class.empty,
1586          onCancel: Class.empty,
1587          transition: function(p){
1588              return -(Math.cos(Math.PI * p) - 1) / 2;
1589          },
1590          duration: 500,
1591          unit: 'px',
1592          wait: true,
1593          fps: 50
1594      },
1595  
1596      initialize: function(options){
1597          this.element = this.element || null;
1598          this.setOptions(options);
1599          if (this.options.initialize) this.options.initialize.call(this);
1600      },
1601  
1602      step: function(){
1603          var time = $time();
1604          if (time < this.time + this.options.duration){
1605              this.delta = this.options.transition((time - this.time) / this.options.duration);
1606              this.setNow();
1607              this.increase();
1608          } else {
1609              this.stop(true);
1610              this.set(this.to);
1611              this.fireEvent('onComplete', this.element, 10);
1612              this.callChain();
1613          }
1614      },
1615  
1616      set: function(to){
1617          this.now = to;
1618          this.increase();
1619          return this;
1620      },
1621  
1622      setNow: function(){
1623          this.now = this.compute(this.from, this.to);
1624      },
1625  
1626      compute: function(from, to){
1627          return (to - from) * this.delta + from;
1628      },
1629  
1630      start: function(from, to){
1631          if (!this.options.wait) this.stop();
1632          else if (this.timer) return this;
1633          this.from = from;
1634          this.to = to;
1635          this.change = this.to - this.from;
1636          this.time = $time();
1637          this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
1638          this.fireEvent('onStart', this.element);
1639          return this;
1640      },
1641  
1642      stop: function(end){
1643          if (!this.timer) return this;
1644          this.timer = $clear(this.timer);
1645          if (!end) this.fireEvent('onCancel', this.element);
1646          return this;
1647      }/*compatibility*/,
1648  
1649      custom: function(from, to){
1650          return this.start(from, to);
1651      },
1652  
1653      clearTimer: function(end){
1654          return this.stop(end);
1655      }
1656  
1657  });
1658  
1659  Fx.Base.implement(new Chain, new Events, new Options);
1660  
1661  Fx.CSS = {
1662  
1663      select: function(property, to){
1664          if (property.test(/color/i)) return this.Color;
1665          var type = $type(to);
1666          if ((type == 'array') || (type == 'string' && to.contains(' '))) return this.Multi;
1667          return this.Single;
1668      },
1669  
1670      parse: function(el, property, fromTo){
1671          if (!fromTo.push) fromTo = [fromTo];
1672          var from = fromTo[0], to = fromTo[1];
1673          if (!$chk(to)){
1674              to = from;
1675              from = el.getStyle(property);
1676          }
1677          var css = this.select(property, to);
1678          return {'from': css.parse(from), 'to': css.parse(to), 'css': css};
1679      }
1680  
1681  };
1682  
1683  Fx.CSS.Single = {
1684  
1685      parse: function(value){
1686          return parseFloat(value);
1687      },
1688  
1689      getNow: function(from, to, fx){
1690          return fx.compute(from, to);
1691      },
1692  
1693      getValue: function(value, unit, property){
1694          if (unit == 'px' && property != 'opacity') value = Math.round(value);
1695          return value + unit;
1696      }
1697  
1698  };
1699  
1700  Fx.CSS.Multi = {
1701  
1702      parse: function(value){
1703          return value.push ? value : value.split(' ').map(function(v){
1704              return parseFloat(v);
1705          });
1706      },
1707  
1708      getNow: function(from, to, fx){
1709          var now = [];
1710          for (var i = 0; i < from.length; i++) now[i] = fx.compute(from[i], to[i]);
1711          return now;
1712      },
1713  
1714      getValue: function(value, unit, property){
1715          if (unit == 'px' && property != 'opacity') value = value.map(Math.round);
1716          return value.join(unit + ' ') + unit;
1717      }
1718  
1719  };
1720  
1721  Fx.CSS.Color = {
1722  
1723      parse: function(value){
1724          return value.push ? value : value.hexToRgb(true);
1725      },
1726  
1727      getNow: function(from, to, fx){
1728          var now = [];
1729          for (var i = 0; i < from.length; i++) now[i] = Math.round(fx.compute(from[i], to[i]));
1730          return now;
1731      },
1732  
1733      getValue: function(value){
1734          return 'rgb(' + value.join(',') + ')';
1735      }
1736  
1737  };
1738  
1739  Fx.Style = Fx.Base.extend({
1740  
1741      initialize: function(el, property, options){
1742          this.element = $(el);
1743          this.property = property;
1744          this.parent(options);
1745      },
1746  
1747      hide: function(){
1748          return this.set(0);
1749      },
1750  
1751      setNow: function(){
1752          this.now = this.css.getNow(this.from, this.to, this);
1753      },
1754  
1755      set: function(to){
1756          this.css = Fx.CSS.select(this.property, to);
1757          return this.parent(this.css.parse(to));
1758      },
1759  
1760      start: function(from, to){
1761          if (this.timer && this.options.wait) return this;
1762          var parsed = Fx.CSS.parse(this.element, this.property, [from, to]);
1763          this.css = parsed.css;
1764          return this.parent(parsed.from, parsed.to);
1765      },
1766  
1767      increase: function(){
1768          this.element.setStyle(this.property, this.css.getValue(this.now, this.options.unit, this.property));
1769      }
1770  
1771  });
1772  
1773  Element.extend({
1774  
1775      effect: function(property, options){
1776          return new Fx.Style(this, property, options);
1777      }
1778  
1779  });
1780  
1781  Fx.Styles = Fx.Base.extend({
1782  
1783      initialize: function(el, options){
1784          this.element = $(el);
1785          this.parent(options);
1786      },
1787  
1788      setNow: function(){
1789          for (var p in this.from) this.now[p] = this.css[p].getNow(this.from[p], this.to[p], this);
1790      },
1791  
1792      set: function(to){
1793          var parsed = {};
1794          this.css = {};
1795          for (var p in to){
1796              this.css[p] = Fx.CSS.select(p, to[p]);
1797              parsed[p] = this.css[p].parse(to[p]);
1798          }
1799          return this.parent(parsed);
1800      },
1801  
1802      start: function(obj){
1803          if (this.timer && this.options.wait) return this;
1804          this.now = {};
1805          this.css = {};
1806          var from = {}, to = {};
1807          for (var p in obj){
1808              var parsed = Fx.CSS.parse(this.element, p, obj[p]);
1809              from[p] = parsed.from;
1810              to[p] = parsed.to;
1811              this.css[p] = parsed.css;
1812          }
1813          return this.parent(from, to);
1814      },
1815  
1816      increase: function(){
1817          for (var p in this.now) this.element.setStyle(p, this.css[p].getValue(this.now[p], this.options.unit, p));
1818      }
1819  
1820  });
1821  
1822  Element.extend({
1823  
1824      effects: function(options){
1825          return new Fx.Styles(this, options);
1826      }
1827  
1828  });
1829  
1830  Fx.Elements = Fx.Base.extend({
1831  
1832      initialize: function(elements, options){
1833          this.elements = $$(elements);
1834          this.parent(options);
1835      },
1836  
1837      setNow: function(){
1838          for (var i in this.from){
1839              var iFrom = this.from[i], iTo = this.to[i], iCss = this.css[i], iNow = this.now[i] = {};
1840              for (var p in iFrom) iNow[p] = iCss[p].getNow(iFrom[p], iTo[p], this);
1841          }
1842      },
1843  
1844      set: function(to){
1845          var parsed = {};
1846          this.css = {};
1847          for (var i in to){
1848              var iTo = to[i], iCss = this.css[i] = {}, iParsed = parsed[i] = {};
1849              for (var p in iTo){
1850                  iCss[p] = Fx.CSS.select(p, iTo[p]);
1851                  iParsed[p] = iCss[p].parse(iTo[p]);
1852              }
1853          }
1854          return this.parent(parsed);
1855      },
1856  
1857      start: function(obj){
1858          if (this.timer && this.options.wait) return this;
1859          this.now = {};
1860          this.css = {};
1861          var from = {}, to = {};
1862          for (var i in obj){
1863              var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}, iCss = this.css[i] = {};
1864              for (var p in iProps){
1865                  var parsed = Fx.CSS.parse(this.elements[i], p, iProps[p]);
1866                  iFrom[p] = parsed.from;
1867                  iTo[p] = parsed.to;
1868                  iCss[p] = parsed.css;
1869              }
1870          }
1871          return this.parent(from, to);
1872      },
1873  
1874      increase: function(){
1875          for (var i in this.now){
1876              var iNow = this.now[i], iCss = this.css[i];
1877              for (var p in iNow) this.elements[i].setStyle(p, iCss[p].getValue(iNow[p], this.options.unit, p));
1878          }
1879      }
1880  
1881  });
1882  
1883  Fx.Scroll = Fx.Base.extend({
1884  
1885      options: {
1886          overflown: [],
1887          offset: {'x': 0, 'y': 0},
1888          wheelStops: true
1889      },
1890  
1891      initialize: function(element, options){
1892          this.now = [];
1893          this.element = $(element);
1894          this.bound = {'stop': this.stop.bind(this, false)};
1895          this.parent(options);
1896          if (this.options.wheelStops){
1897              this.addEvent('onStart', function(){
1898                  document.addEvent('mousewheel', this.bound.stop);
1899              }.bind(this));
1900              this.addEvent('onComplete', function(){
1901                  document.removeEvent('mousewheel', this.bound.stop);
1902              }.bind(this));
1903          }
1904      },
1905  
1906      setNow: function(){
1907          for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
1908      },
1909  
1910      scrollTo: function(x, y){
1911          if (this.timer && this.options.wait) return this;
1912          var el = this.element.getSize();
1913          var values = {'x': x, 'y': y};
1914          for (var z in el.size){
1915              var max = el.scrollSize[z] - el.size[z];
1916              if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
1917              else values[z] = el.scroll[z];
1918              values[z] += this.options.offset[z];
1919          }
1920          return this.start([el.scroll.x, el.scroll.y], [values.x, values.y]);
1921      },
1922  
1923      toTop: function(){
1924          return this.scrollTo(false, 0);
1925      },
1926  
1927      toBottom: function(){
1928          return this.scrollTo(false, 'full');
1929      },
1930  
1931      toLeft: function(){
1932          return this.scrollTo(0, false);
1933      },
1934  
1935      toRight: function(){
1936          return this.scrollTo('full', false);
1937      },
1938  
1939      toElement: function(el){
1940          var parent = this.element.getPosition(this.options.overflown);
1941          var target = $(el).getPosition(this.options.overflown);
1942          return this.scrollTo(target.x - parent.x, target.y - parent.y);
1943      },
1944  
1945      increase: function(){
1946          this.element.scrollTo(this.now[0], this.now[1]);
1947      }
1948  
1949  });
1950  
1951  Fx.Slide = Fx.Base.extend({
1952  
1953      options: {
1954          mode: 'vertical'
1955      },
1956  
1957      initialize: function(el, options){
1958          this.element = $(el);
1959          this.wrapper = new Element('div', {'styles': $extend(this.element.getStyles('margin'), {'overflow': 'hidden'})}).injectAfter(this.element).adopt(this.element);
1960          this.element.setStyle('margin', 0);
1961          this.setOptions(options);
1962          this.now = [];
1963          this.parent(this.options);
1964          this.open = true;
1965          this.addEvent('onComplete', function(){
1966              this.open = (this.now[0] === 0);
1967          });
1968          if (window.webkit419) this.addEvent('onComplete', function(){
1969              if (this.open) this.element.remove().inject(this.wrapper);
1970          });
1971      },
1972  
1973      setNow: function(){
1974          for (var i = 0; i < 2; i++) this.now[i] = this.compute(this.from[i], this.to[i]);
1975      },
1976  
1977      vertical: function(){
1978          this.margin = 'margin-top';
1979          this.layout = 'height';
1980          this.offset = this.element.offsetHeight;
1981      },
1982  
1983      horizontal: function(){
1984          this.margin = 'margin-left';
1985          this.layout = 'width';
1986          this.offset = this.element.offsetWidth;
1987      },
1988  
1989      slideIn: function(mode){
1990          this[mode || this.options.mode]();
1991          return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [0, this.offset]);
1992      },
1993  
1994      slideOut: function(mode){
1995          this[mode || this.options.mode]();
1996          return this.start([this.element.getStyle(this.margin).toInt(), this.wrapper.getStyle(this.layout).toInt()], [-this.offset, 0]);
1997      },
1998  
1999      hide: function(mode){
2000          this[mode || this.options.mode]();
2001          this.open = false;
2002          return this.set([-this.offset, 0]);
2003      },
2004  
2005      show: function(mode){
2006          this[mode || this.options.mode]();
2007          this.open = true;
2008          return this.set([0, this.offset]);
2009      },
2010  
2011      toggle: function(mode){
2012          if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) return this.slideIn(mode);
2013          return this.slideOut(mode);
2014      },
2015  
2016      increase: function(){
2017          this.element.setStyle(this.margin, this.now[0] + this.options.unit);
2018          this.wrapper.setStyle(this.layout, this.now[1] + this.options.unit);
2019      }
2020  
2021  });
2022  
2023  Fx.Transition = function(transition, params){
2024      params = params || [];
2025      if ($type(params) != 'array') params = [params];
2026      return $extend(transition, {
2027          easeIn: function(pos){
2028              return transition(pos, params);
2029          },
2030          easeOut: function(pos){
2031              return 1 - transition(1 - pos, params);
2032          },
2033          easeInOut: function(pos){
2034              return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
2035          }
2036      });
2037  };
2038  
2039  Fx.Transitions = new Abstract({
2040  
2041      linear: function(p){
2042          return p;
2043      }
2044  
2045  });
2046  
2047  Fx.Transitions.extend = function(transitions){
2048      for (var transition in transitions){
2049          Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
2050          Fx.Transitions.compat(transition);
2051      }
2052  };
2053  
2054  Fx.Transitions.compat = function(transition){
2055      ['In', 'Out', 'InOut'].each(function(easeType){
2056          Fx.Transitions[transition.toLowerCase() + easeType] = Fx.Transitions[transition]['ease' + easeType];
2057      });
2058  };
2059  
2060  Fx.Transitions.extend({
2061  
2062      Pow: function(p, x){
2063          return Math.pow(p, x[0] || 6);
2064      },
2065  
2066      Expo: function(p){
2067          return Math.pow(2, 8 * (p - 1));
2068      },
2069  
2070      Circ: function(p){
2071          return 1 - Math.sin(Math.acos(p));
2072      },
2073  
2074      Sine: function(p){
2075          return 1 - Math.sin((1 - p) * Math.PI / 2);
2076      },
2077  
2078      Back: function(p, x){
2079          x = x[0] || 1.618;
2080          return Math.pow(p, 2) * ((x + 1) * p - x);
2081      },
2082  
2083      Bounce: function(p){
2084          var value;
2085          for (var a = 0, b = 1; 1; a += b, b /= 2){
2086              if (p >= (7 - 4 * a) / 11){
2087                  value = - Math.pow((11 - 6 * a - 11 * p) / 4, 2) + b * b;
2088                  break;
2089              }
2090          }
2091          return value;
2092      },
2093  
2094      Elastic: function(p, x){
2095          return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
2096      }
2097  
2098  });
2099  
2100  ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
2101      Fx.Transitions[transition] = new Fx.Transition(function(p){
2102          return Math.pow(p, [i + 2]);
2103      });
2104      Fx.Transitions.compat(transition);
2105  });
2106  
2107  var Drag = {};
2108  
2109  Drag.Base = new Class({
2110  
2111      options: {
2112          handle: false,
2113          unit: 'px',
2114          onStart: Class.empty,
2115          onBeforeStart: Class.empty,
2116          onComplete: Class.empty,
2117          onSnap: Class.empty,
2118          onDrag: Class.empty,
2119          limit: false,
2120          modifiers: {x: 'left', y: 'top'},
2121          grid: false,
2122          snap: 6
2123      },
2124  
2125      initialize: function(el, options){
2126          this.setOptions(options);
2127          this.element = $(el);
2128          this.handle = $(this.options.handle) || this.element;
2129          this.mouse = {'now': {}, 'pos': {}};
2130          this.value = {'start': {}, 'now': {}};
2131          this.bound = {
2132              'start': this.start.bindWithEvent(this),
2133              'check': this.check.bindWithEvent(this),
2134              'drag': this.drag.bindWithEvent(this),
2135              'stop': this.stop.bind(this)
2136          };
2137          this.attach();
2138          if (this.options.initialize) this.options.initialize.call(this);
2139      },
2140  
2141      attach: function(){
2142          this.handle.addEvent('mousedown', this.bound.start);
2143          return this;
2144      },
2145  
2146      detach: function(){
2147          this.handle.removeEvent('mousedown', this.bound.start);
2148          return this;
2149      },
2150  
2151      start: function(event){
2152          this.fireEvent('onBeforeStart', this.element);
2153          this.mouse.start = event.page;
2154          var limit = this.options.limit;
2155          this.limit = {'x': [], 'y': []};
2156          for (var z in this.options.modifiers){
2157              if (!this.options.modifiers[z]) continue;
2158              this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
2159              this.mouse.pos[z] = event.page[z] - this.value.now[z];
2160              if (limit && limit[z]){
2161                  for (var i = 0; i < 2; i++){
2162                      if ($chk(limit[z][i])) this.limit[z][i] = ($type(limit[z][i]) == 'function') ? limit[z][i]() : limit[z][i];
2163                  }
2164              }
2165          }
2166          if ($type(this.options.grid) == 'number') this.options.grid = {'x': this.options.grid, 'y': this.options.grid};
2167          document.addListener('mousemove', this.bound.check);
2168          document.addListener('mouseup', this.bound.stop);
2169          this.fireEvent('onStart', this.element);
2170          event.stop();
2171      },
2172  
2173      check: function(event){
2174          var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
2175          if (distance > this.options.snap){
2176              document.removeListener('mousemove', this.bound.check);
2177              document.addListener('mousemove', this.bound.drag);
2178              this.drag(event);
2179              this.fireEvent('onSnap', this.element);
2180          }
2181          event.stop();
2182      },
2183  
2184      drag: function(event){
2185          this.out = false;
2186          this.mouse.now = event.page;
2187          for (var z in this.options.modifiers){
2188              if (!this.options.modifiers[z]) continue;
2189              this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
2190              if (this.limit[z]){
2191                  if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
2192                      this.value.now[z] = this.limit[z][1];
2193                      this.out = true;
2194                  } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
2195                      this.value.now[z] = this.limit[z][0];
2196                      this.out = true;
2197                  }
2198              }
2199              if (this.options.grid[z]) this.value.now[z] -= (this.value.now[z] % this.options.grid[z]);
2200              this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
2201          }
2202          this.fireEvent('onDrag', this.element);
2203          event.stop();
2204      },
2205  
2206      stop: function(){
2207          document.removeListener('mousemove', this.bound.check);
2208          document.removeListener('mousemove', this.bound.drag);
2209          document.removeListener('mouseup', this.bound.stop);
2210          this.fireEvent('onComplete', this.element);
2211      }
2212  
2213  });
2214  
2215  Drag.Base.implement(new Events, new Options);
2216  
2217  Element.extend({
2218  
2219      makeResizable: function(options){
2220          return new Drag.Base(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
2221      }
2222  
2223  });
2224  
2225  Drag.Move = Drag.Base.extend({
2226  
2227      options: {
2228          droppables: [],
2229          container: false,
2230          overflown: []
2231      },
2232  
2233      initialize: function(el, options){
2234          this.setOptions(options);
2235          this.element = $(el);
2236          this.droppables = $$(this.options.droppables);
2237          this.container = $(this.options.container);
2238          this.position = {'element': this.element.getStyle('position'), 'container': false};
2239          if (this.container) this.position.container = this.container.getStyle('position');
2240          if (!['relative', 'absolute', 'fixed'].contains(this.position.element)) this.position.element = 'absolute';
2241          var top = this.element.getStyle('top').toInt();
2242          var left = this.element.getStyle('left').toInt();
2243          if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
2244              top = $chk(top) ? top : this.element.getTop(this.options.overflown);
2245              left = $chk(left) ? left : this.element.getLeft(this.options.overflown);
2246          } else {
2247              top = $chk(top) ? top : 0;
2248              left = $chk(left) ? left : 0;
2249          }
2250          this.element.setStyles({'top': top, 'left': left, 'position': this.position.element});
2251          this.parent(this.element);
2252      },
2253  
2254      start: function(event){
2255          this.overed = null;
2256          if (this.container){
2257              var cont = this.container.getCoordinates();
2258              var el = this.element.getCoordinates();
2259              if (this.position.element == 'absolute' && !['relative', 'absolute', 'fixed'].contains(this.position.container)){
2260                  this.options.limit = {
2261                      'x': [cont.left, cont.right - el.width],
2262                      'y': [cont.top, cont.bottom - el.height]
2263                  };
2264              } else {
2265                  this.options.limit = {
2266                      'y': [0, cont.height - el.height],
2267                      'x': [0, cont.width - el.width]
2268                  };
2269              }
2270          }
2271          this.parent(event);
2272      },
2273  
2274      drag: function(event){
2275          this.parent(event);
2276          var overed = this.out ? false : this.droppables.filter(this.checkAgainst, this).getLast();
2277          if (this.overed != overed){
2278              if (this.overed) this.overed.fireEvent('leave', [this.element, this]);
2279              this.overed = overed ? overed.fireEvent('over', [this.element, this]) : null;
2280          }
2281          return this;
2282      },
2283  
2284      checkAgainst: function(el){
2285          el = el.getCoordinates(this.options.overflown);
2286          var now = this.mouse.now;
2287          return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
2288      },
2289  
2290      stop: function(){
2291          if (this.overed && !this.out) this.overed.fireEvent('drop', [this.element, this]);
2292          else this.element.fireEvent('emptydrop', this);
2293          this.parent();
2294          return this;
2295      }
2296  
2297  });
2298  
2299  Element.extend({
2300  
2301      makeDraggable: function(options){
2302          return new Drag.Move(this, options);
2303      }
2304  
2305  });
2306  
2307  var XHR = new Class({
2308  
2309      options: {
2310          method: 'post',
2311          async: true,
2312          onRequest: Class.empty,
2313          onSuccess: Class.empty,
2314          onFailure: Class.empty,
2315          urlEncoded: true,
2316          encoding: 'utf-8',
2317          autoCancel: false,
2318          headers: {}
2319      },
2320  
2321      setTransport: function(){
2322          this.transport = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ie ? new ActiveXObject('Microsoft.XMLHTTP') : false);
2323          return this;
2324      },
2325  
2326      initialize: function(options){
2327          this.setTransport().setOptions(options);
2328          this.options.isSuccess = this.options.isSuccess || this.isSuccess;
2329          this.headers = {};
2330          if (this.options.urlEncoded && this.options.method == 'post'){
2331              var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
2332              this.setHeader('Content-type', 'application/x-www-form-urlencoded' + encoding);
2333          }
2334          if (this.options.initialize) this.options.initialize.call(this);
2335      },
2336  
2337      onStateChange: function(){
2338          if (this.transport.readyState != 4 || !this.running) return;
2339          this.running = false;
2340          var status = 0;
2341          try {status = this.transport.status;} catch(e){};
2342          if (this.options.isSuccess.call(this, status)) this.onSuccess();
2343          else this.onFailure();
2344          this.transport.onreadystatechange = Class.empty;
2345      },
2346  
2347      isSuccess: function(status){
2348          return ((status >= 200) && (status < 300));
2349      },
2350  
2351      onSuccess: function(){
2352          this.response = {
2353              'text': this.transport.responseText,
2354              'xml': this.transport.responseXML
2355          };
2356          this.fireEvent('onSuccess', [this.response.text, this.response.xml]);
2357          this.callChain();
2358      },
2359  
2360      onFailure: function(){
2361          this.fireEvent('onFailure', this.transport);
2362      },
2363  
2364      setHeader: function(name, value){
2365          this.headers[name] = value;
2366          return this;
2367      },
2368  
2369      send: function(url, data){
2370          if (this.options.autoCancel) this.cancel();
2371          else if (this.running) return this;
2372          this.running = true;
2373          if (data && this.options.method == 'get'){
2374              url = url + (url.contains('?') ? '&' : '?') + data;
2375              data = null;
2376          }
2377          this.transport.open(this.options.method.toUpperCase(), url, this.options.async);
2378          this.transport.onreadystatechange = this.onStateChange.bind(this);
2379          if ((this.options.method == 'post') && this.transport.overrideMimeType) this.setHeader('Connection', 'close');
2380          $extend(this.headers, this.options.headers);
2381          for (var type in this.headers) try {this.transport.setRequestHeader(type, this.headers[type]);} catch(e){};
2382          this.fireEvent('onRequest');
2383          this.transport.send($pick(data, null));
2384          return this;
2385      },
2386  
2387      cancel: function(){
2388          if (!this.running) return this;
2389          this.running = false;
2390          this.transport.abort();
2391          this.transport.onreadystatechange = Class.empty;
2392          this.setTransport();
2393          this.fireEvent('onCancel');
2394          return this;
2395      }
2396  
2397  });
2398  
2399  XHR.implement(new Chain, new Events, new Options);
2400  
2401  var Ajax = XHR.extend({
2402  
2403      options: {
2404          data: null,
2405          update: null,
2406          onComplete: Class.empty,
2407          evalScripts: false,
2408          evalResponse: false
2409      },
2410  
2411      initialize: function(url, options){
2412          this.addEvent('onSuccess', this.onComplete);
2413          this.setOptions(options);
2414          this.options.data = this.options.data || this.options.postBody;
2415          if (!['post', 'get'].contains(this.options.method)){
2416              this._method = '_method=' + this.options.method;
2417              this.options.method = 'post';
2418          }
2419          this.parent();
2420          this.setHeader('X-Requested-With', 'XMLHttpRequest');
2421          this.setHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
2422          this.url = url;
2423      },
2424  
2425      onComplete: function(){
2426          if (this.options.update) $(this.options.update).empty().setHTML(this.response.text);
2427          if (this.options.evalScripts || this.options.evalResponse) this.evalScripts();
2428          this.fireEvent('onComplete', [this.response.text, this.response.xml], 20);
2429      },
2430  
2431      request: function(data){
2432          data = data || this.options.data;
2433          switch($type(data)){
2434              case 'element': data = $(data).toQueryString(); break;
2435              case 'object': data = Object.toQueryString(data);
2436          }
2437          if (this._method) data = (data) ? [this._method, data].join('&') : this._method;
2438          return this.send(this.url, data);
2439      },
2440  
2441      evalScripts: function(){
2442          var script, scripts;
2443          if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) scripts = this.response.text;
2444          else {
2445              scripts = [];
2446              var regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi;
2447              while ((script = regexp.exec(this.response.text))) scripts.push(script[1]);
2448              scripts = scripts.join('\n');
2449          }
2450          if (scripts) (window.execScript) ? window.execScript(scripts) : window.setTimeout(scripts, 0);
2451      },
2452  
2453      getHeader: function(name){
2454          try {return this.transport.getResponseHeader(name);} catch(e){};
2455          return null;
2456      }
2457  
2458  });
2459  
2460  Object.toQueryString = function(source){
2461      var queryString = [];
2462      for (var property in source) queryString.push(encodeURIComponent(property) + '=' + encodeURIComponent(source[property]));
2463      return queryString.join('&');
2464  };
2465  
2466  Element.extend({
2467  
2468      send: function(options){
2469          return new Ajax(this.getProperty('action'), $merge({data: this.toQueryString()}, options, {method: 'post'})).request();
2470      }
2471  
2472  });
2473  
2474  var Cookie = new Abstract({
2475  
2476      options: {
2477          domain: false,
2478          path: false,
2479          duration: false,
2480          secure: false
2481      },
2482  
2483      set: function(key, value, options){
2484          options = $merge(this.options, options);
2485          value = encodeURIComponent(value);
2486          if (options.domain) value += '; domain=' + options.domain;
2487          if (options.path) value += '; path=' + options.path;
2488          if (options.duration){
2489              var date = new Date();
2490              date.setTime(date.getTime() + options.duration * 24 * 60 * 60 * 1000);
2491              value += '; expires=' + date.toGMTString();
2492          }
2493          if (options.secure) value += '; secure';
2494          document.cookie = key + '=' + value;
2495          return $extend(options, {'key': key, 'value': value});
2496      },
2497  
2498      get: function(key){
2499          var value = document.cookie.match('(?:^|;)\\s*' + key.escapeRegExp() + '=([^;]*)');
2500          return value ? decodeURIComponent(value[1]) : false;
2501      },
2502  
2503      remove: function(cookie, options){
2504          if ($type(cookie) == 'object') this.set(cookie.key, '', $merge(cookie, {duration: -1}));
2505          else this.set(cookie, '', $merge(options, {duration: -1}));
2506      }
2507  
2508  });
2509  
2510  var Json = {
2511  
2512      toString: function(obj){
2513          switch($type(obj)){
2514              case 'string':
2515                  return '"' + obj.replace(/(["\\])/g, '\\$1') + '"';
2516              case 'array':
2517                  return '[' + obj.map(Json.toString).join(',') + ']';
2518              case 'object':
2519                  var string = [];
2520                  for (var property in obj) string.push(Json.toString(property) + ':' + Json.toString(obj[property]));
2521                  return '{' + string.join(',') + '}';
2522              case 'number':
2523                  if (isFinite(obj)) break;
2524              case false:
2525                  return 'null';
2526          }
2527          return String(obj);
2528      },
2529  
2530      evaluate: function(str, secure){
2531          return (($type(str) != 'string') || (secure && !str.test(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/))) ? null : eval('(' + str + ')');
2532      }
2533  
2534  };
2535  
2536  Json.Remote = XHR.extend({
2537  
2538      initialize: function(url, options){
2539          this.url = url;
2540          this.addEvent('onSuccess', this.onComplete);
2541          this.parent(options);
2542          this.setHeader('X-Request', 'JSON');
2543      },
2544  
2545      send: function(obj){
2546          return this.parent(this.url, 'json=' + Json.toString(obj));
2547      },
2548  
2549      onComplete: function(){
2550          this.fireEvent('onComplete', [Json.evaluate(this.response.text, this.options.secure)]);
2551      }
2552  
2553  });
2554  
2555  var Asset = new Abstract({
2556  
2557      javascript: function(source, properties){
2558          properties = $merge({
2559              'onload': Class.empty
2560          }, properties);
2561          var script = new Element('script', {'src': source}).addEvents({
2562              'load': properties.onload,
2563              'readystatechange': function(){
2564                  if (this.readyState == 'complete') this.fireEvent('load');
2565              }
2566          });
2567          delete properties.onload;
2568          return script.setProperties(properties).inject(document.head);
2569      },
2570  
2571      css: function(source, properties){
2572          return new Element('link', $merge({
2573              'rel': 'stylesheet', 'media': 'screen', 'type': 'text/css', 'href': source
2574          }, properties)).inject(document.head);
2575      },
2576  
2577      image: function(source, properties){
2578          properties = $merge({
2579              'onload': Class.empty,
2580              'onabort': Class.empty,
2581              'onerror': Class.empty
2582          }, properties);
2583          var image = new Image();
2584          image.src = source;
2585          var element = new Element('img', {'src': source});
2586          ['load', 'abort', 'error'].each(function(type){
2587              var event = properties['on' + type];
2588              delete properties['on' + type];
2589              element.addEvent(type, function(){
2590                  this.removeEvent(type, arguments.callee);
2591                  event.call(this);
2592              });
2593          });
2594          if (image.width && image.height) element.fireEvent('load', element, 1);
2595          return element.setProperties(properties);
2596      },
2597  
2598      images: function(sources, options){
2599          options = $merge({
2600              onComplete: Class.empty,
2601              onProgress: Class.empty
2602          }, options);
2603          if (!sources.push) sources = [sources];
2604          var images = [];
2605          var counter = 0;
2606          sources.each(function(source){
2607              var img = new Asset.image(source, {
2608                  'onload': function(){
2609                      options.onProgress.call(this, counter);
2610                      counter++;
2611                      if (counter == sources.length) options.onComplete();
2612                  }
2613              });
2614              images.push(img);
2615          });
2616          return new Elements(images);
2617      }
2618  
2619  });
2620  
2621  var Hash = new Class({
2622  
2623      length: 0,
2624  
2625      initialize: function(object){
2626          this.obj = object || {};
2627          this.setLength();
2628      },
2629  
2630      get: function(key){
2631          return (this.hasKey(key)) ? this.obj[key] : null;
2632      },
2633  
2634      hasKey: function(key){
2635          return (key in this.obj);
2636      },
2637  
2638      set: function(key, value){
2639          if (!this.hasKey(key)) this.length++;
2640          this.obj[key] = value;
2641          return this;
2642      },
2643  
2644      setLength: function(){
2645          this.length = 0;
2646          for (var p in this.obj) this.length++;
2647          return this;
2648      },
2649  
2650      remove: function(key){
2651          if (this.hasKey(key)){
2652              delete this.obj[key];
2653              this.length--;
2654          }
2655          return this;
2656      },
2657  
2658      each: function(fn, bind){
2659          $each(this.obj, fn, bind);
2660      },
2661  
2662      extend: function(obj){
2663          $extend(this.obj, obj);
2664          return this.setLength();
2665      },
2666  
2667      merge: function(){
2668          this.obj = $merge.apply(null, [this.obj].extend(arguments));
2669          return this.setLength();
2670      },
2671  
2672      empty: function(){
2673          this.obj = {};
2674          this.length = 0;
2675          return this;
2676      },
2677  
2678      keys: function(){
2679          var keys = [];
2680          for (var property in this.obj) keys.push(property);
2681          return keys;
2682      },
2683  
2684      values: function(){
2685          var values = [];
2686          for (var property in this.obj) values.push(this.obj[property]);
2687          return values;
2688      }
2689  
2690  });
2691  
2692  function $H(obj){
2693      return new Hash(obj);
2694  };
2695  
2696  Hash.Cookie = Hash.extend({
2697  
2698      initialize: function(name, options){
2699          this.name = name;
2700          this.options = $extend({'autoSave': true}, options || {});
2701          this.load();
2702      },
2703  
2704      save: function(){
2705          if (this.length == 0){
2706              Cookie.remove(this.name, this.options);
2707              return true;
2708          }
2709          var str = Json.toString(this.obj);
2710          if (str.length > 4096) return false;
2711          Cookie.set(this.name, str, this.options);
2712          return true;
2713      },
2714  
2715      load: function(){
2716          this.obj = Json.evaluate(Cookie.get(this.name), true) || {};
2717          this.setLength();
2718      }
2719  
2720  });
2721  
2722  Hash.Cookie.Methods = {};
2723  ['extend', 'set', 'merge', 'empty', 'remove'].each(function(method){
2724      Hash.Cookie.Methods[method] = function(){
2725          Hash.prototype[method].apply(this, arguments);
2726          if (this.options.autoSave) this.save();
2727          return this;
2728      };
2729  });
2730  Hash.Cookie.implement(Hash.Cookie.Methods);
2731  
2732  var Color = new Class({
2733  
2734      initialize: function(color, type){
2735          type = type || (color.push ? 'rgb' : 'hex');
2736          var rgb, hsb;
2737          switch(type){
2738              case 'rgb':
2739                  rgb = color;
2740                  hsb = rgb.rgbToHsb();
2741                  break;
2742              case 'hsb':
2743                  rgb = color.hsbToRgb();
2744                  hsb = color;
2745                  break;
2746              default:
2747                  rgb = color.hexToRgb(true);
2748                  hsb = rgb.rgbToHsb();
2749          }
2750          rgb.hsb = hsb;
2751          rgb.hex = rgb.rgbToHex();
2752          return $extend(rgb, Color.prototype);
2753      },
2754  
2755      mix: function(){
2756          var colors = $A(arguments);
2757          var alpha = ($type(colors[colors.length - 1]) == 'number') ? colors.pop() : 50;
2758          var rgb = this.copy();
2759          colors.each(function(color){
2760              color = new Color(color);
2761              for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
2762          });
2763          return new Color(rgb, 'rgb');
2764      },
2765  
2766      invert: function(){
2767          return new Color(this.map(function(value){
2768              return 255 - value;
2769          }));
2770      },
2771  
2772      setHue: function(value){
2773          return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
2774      },
2775  
2776      setSaturation: function(percent){
2777          return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
2778      },
2779  
2780      setBrightness: function(percent){
2781          return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
2782      }
2783  
2784  });
2785  
2786  function $RGB(r, g, b){
2787      return new Color([r, g, b], 'rgb');
2788  };
2789  
2790  function $HSB(h, s, b){
2791      return new Color([h, s, b], 'hsb');
2792  };
2793  
2794  Array.extend({
2795  
2796      rgbToHsb: function(){
2797          var red = this[0], green = this[1], blue = this[2];
2798          var hue, saturation, brightness;
2799          var max = Math.max(red, green, blue), min = Math.min(red, green, blue);
2800          var delta = max - min;
2801          brightness = max / 255;
2802          saturation = (max != 0) ? delta / max : 0;
2803          if (saturation == 0){
2804              hue = 0;
2805          } else {
2806              var rr = (max - red) / delta;
2807              var gr = (max - green) / delta;
2808              var br = (max - blue) / delta;
2809              if (red == max) hue = br - gr;
2810              else if (green == max) hue = 2 + rr - br;
2811              else hue = 4 + gr - rr;
2812              hue /= 6;
2813              if (hue < 0) hue++;
2814          }
2815          return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
2816      },
2817  
2818      hsbToRgb: function(){
2819          var br = Math.round(this[2] / 100 * 255);
2820          if (this[1] == 0){
2821              return [br, br, br];
2822          } else {
2823              var hue = this[0] % 360;
2824              var f = hue % 60;
2825              var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
2826              var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
2827              var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
2828              switch(Math.floor(hue / 60)){
2829                  case 0: return [br, t, p];
2830                  case 1: return [q, br, p];
2831                  case 2: return [p, br, t];
2832                  case 3: return [p, q, br];
2833                  case 4: return [t, p, br];
2834                  case 5: return [br, p, q];
2835              }
2836          }
2837          return false;
2838      }
2839  
2840  });
2841  
2842  var Scroller = new Class({
2843  
2844      options: {
2845          area: 20,
2846          velocity: 1,
2847          onChange: function(x, y){
2848              this.element.scrollTo(x, y);
2849          }
2850      },
2851  
2852      initialize: function(element, options){
2853          this.setOptions(options);
2854          this.element = $(element);
2855          this.mousemover = ([window, document].contains(element)) ? $(document.body) : this.element;
2856      },
2857  
2858      start: function(){
2859          this.coord = this.getCoords.bindWithEvent(this);
2860          this.mousemover.addListener('mousemove', this.coord);
2861      },
2862  
2863      stop: function(){
2864          this.mousemover.removeListener('mousemove', this.coord);
2865          this.timer = $clear(this.timer);
2866      },
2867  
2868      getCoords: function(event){
2869          this.page = (this.element == window) ? event.client : event.page;
2870          if (!this.timer) this.timer = this.scroll.periodical(50, this);
2871      },
2872  
2873      scroll: function(){
2874          var el = this.element.getSize();
2875          var pos = this.element.getPosition();
2876  
2877          var change = {'x': 0, 'y': 0};
2878          for (var z in this.page){
2879              if (this.page[z] < (this.options.area + pos[z]) && el.scroll[z] != 0)
2880                  change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity;
2881              else if (this.page[z] + this.options.area > (el.size[z] + pos[z]) && el.scroll[z] + el.size[z] != el.scrollSize[z])
2882                  change[z] = (this.page[z] - el.size[z] + this.options.area - pos[z]) * this.options.velocity;
2883          }
2884          if (change.y || change.x) this.fireEvent('onChange', [el.scroll.x + change.x, el.scroll.y + change.y]);
2885      }
2886  
2887  });
2888  
2889  Scroller.implement(new Events, new Options);
2890  
2891  var Slider = new Class({
2892  
2893      options: {
2894          onChange: Class.empty,
2895          onComplete: Class.empty,
2896          onTick: function(pos){
2897              this.knob.setStyle(this.p, pos);
2898          },
2899          mode: 'horizontal',
2900          steps: 100,
2901          offset: 0
2902      },
2903  
2904      initialize: function(el, knob, options){
2905          this.element = $(el);
2906          this.knob = $(knob);
2907          this.setOptions(options);
2908          this.previousChange = -1;
2909          this.previousEnd = -1;
2910          this.step = -1;
2911          this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
2912          var mod, offset;
2913          switch(this.options.mode){
2914              case 'horizontal':
2915                  this.z = 'x';
2916                  this.p = 'left';
2917                  mod = {'x': 'left', 'y': false};
2918                  offset = 'offsetWidth';
2919                  break;
2920              case 'vertical':
2921                  this.z = 'y';
2922                  this.p = 'top';
2923                  mod = {'x': false, 'y': 'top'};
2924                  offset = 'offsetHeight';
2925          }
2926          this.max = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
2927          this.half = this.knob[offset]/2;
2928          this.getPos = this.element['get' + this.p.capitalize()].bind(this.element);
2929          this.knob.setStyle('position', 'relative').setStyle(this.p, - this.options.offset);
2930          var lim = {};
2931          lim[this.z] = [- this.options.offset, this.max - this.options.offset];
2932          this.drag = new Drag.Base(this.knob, {
2933              limit: lim,
2934              modifiers: mod,
2935              snap: 0,
2936              onStart: function(){
2937                  this.draggedKnob();
2938              }.bind(this),
2939              onDrag: function(){
2940                  this.draggedKnob();
2941              }.bind(this),
2942              onComplete: function(){
2943                  this.draggedKnob();
2944                  this.end();
2945              }.bind(this)
2946          });
2947          if (this.options.initialize) this.options.initialize.call(this);
2948      },
2949  
2950      set: function(step){
2951          this.step = step.limit(0, this.options.steps);
2952          this.checkStep();
2953          this.end();
2954          this.fireEvent('onTick', this.toPosition(this.step));
2955          return this;
2956      },
2957  
2958      clickedElement: function(event){
2959          var position = event.page[this.z] - this.getPos() - this.half;
2960          position = position.limit(-this.options.offset, this.max -this.options.offset);
2961          this.step = this.toStep(position);
2962          this.checkStep();
2963          this.end();
2964          this.fireEvent('onTick', position);
2965      },
2966  
2967      draggedKnob: function(){
2968          this.step = this.toStep(this.drag.value.now[this.z]);
2969          this.checkStep();
2970      },
2971  
2972      checkStep: function(){
2973          if (this.previousChange != this.step){
2974              this.previousChange = this.step;
2975              this.fireEvent('onChange', this.step);
2976          }
2977      },
2978  
2979      end: function(){
2980          if (this.previousEnd !== this.step){
2981              this.previousEnd = this.step;
2982              this.fireEvent('onComplete', this.step + '');
2983          }
2984      },
2985  
2986      toStep: function(position){
2987          return Math.round((position + this.options.offset) / this.max * this.options.steps);
2988      },
2989  
2990      toPosition: function(step){
2991          return this.max * step / this.options.steps;
2992      }
2993  
2994  });
2995  
2996  Slider.implement(new Events);
2997  Slider.implement(new Options);
2998  
2999  var SmoothScroll = Fx.Scroll.extend({
3000  
3001      initialize: function(options){
3002          this.parent(window, options);
3003          this.links = (this.options.links) ? $$(this.options.links) : $$(document.links);
3004          var location = window.location.href.match(/^[^#]*/)[0] + '#';
3005          this.links.each(function(link){
3006              if (link.href.indexOf(location) != 0) return;
3007              var anchor = link.href.substr(location.length);
3008              if (anchor && $(anchor)) this.useLink(link, anchor);
3009          }, this);
3010          if (!window.webkit419) this.addEvent('onComplete', function(){
3011              window.location.hash = this.anchor;
3012          });
3013      },
3014  
3015      useLink: function(link, anchor){
3016          link.addEvent('click', function(event){
3017              this.anchor = anchor;
3018              this.toElement(anchor);
3019              event.stop();
3020          }.bindWithEvent(this));
3021      }
3022  
3023  });
3024  
3025  var Sortables = new Class({
3026  
3027      options: {
3028          handles: false,
3029          onStart: Class.empty,
3030          onComplete: Class.empty,
3031          ghost: true,
3032          snap: 3,
3033          onDragStart: function(element, ghost){
3034              ghost.setStyle('opacity', 0.7);
3035              element.setStyle('opacity', 0.7);
3036          },
3037          onDragComplete: function(element, ghost){
3038              element.setStyle('opacity', 1);
3039              ghost.remove();
3040              this.trash.remove();
3041          }
3042      },
3043  
3044      initialize: function(list, options){
3045          this.setOptions(options);
3046          this.list = $(list);
3047          this.elements = this.list.getChildren();
3048          this.handles = (this.options.handles) ? $$(this.options.handles) : this.elements;
3049          this.bound = {
3050              'start': [],
3051              'moveGhost': this.moveGhost.bindWithEvent(this)
3052          };
3053          for (var i = 0, l = this.handles.length; i < l; i++){
3054              this.bound.start[i] = this.start.bindWithEvent(this, this.elements[i]);
3055          }
3056          this.attach();
3057          if (this.options.initialize) this.options.initialize.call(this);
3058          this.bound.move = this.move.bindWithEvent(this);
3059          this.bound.end = this.end.bind(this);
3060      },
3061  
3062      attach: function(){
3063          this.handles.each(function(handle, i){
3064              handle.addEvent('mousedown', this.bound.start[i]);
3065          }, this);
3066      },
3067  
3068      detach: function(){
3069          this.handles.each(function(handle, i){
3070              handle.removeEvent('mousedown', this.bound.start[i]);
3071          }, this);
3072      },
3073  
3074      start: function(event, el){
3075          this.active = el;
3076          this.coordinates = this.list.getCoordinates();
3077          if (this.options.ghost){
3078              var position = el.getPosition();
3079              this.offset = event.page.y - position.y;
3080              this.trash = new Element('div').inject(document.body);
3081              this.ghost = el.clone().inject(this.trash).setStyles({
3082                  'position': 'absolute',
3083                  'left': position.x,
3084                  'top': event.page.y - this.offset
3085              });
3086              document.addListener('mousemove', this.bound.moveGhost);
3087              this.fireEvent('onDragStart', [el, this.ghost]);
3088          }
3089          document.addListener('mousemove', this.bound.move);
3090          document.addListener('mouseup', this.bound.end);
3091          this.fireEvent('onStart', el);
3092          event.stop();
3093      },
3094  
3095      moveGhost: function(event){
3096          var value = event.page.y - this.offset;
3097          value = value.limit(this.coordinates.top, this.coordinates.bottom - this.ghost.offsetHeight);
3098          this.ghost.setStyle('top', value);
3099          event.stop();
3100      },
3101  
3102      move: function(event){
3103          var now = event.page.y;
3104          this.previous = this.previous || now;
3105          var up = ((this.previous - now) > 0);
3106          var prev = this.active.getPrevious();
3107          var next = this.active.getNext();
3108          if (prev && up && now < prev.getCoordinates().bottom) this.active.injectBefore(prev);
3109          if (next && !up && now > next.getCoordinates().top) this.active.injectAfter(next);
3110          this.previous = now;
3111      },
3112  
3113      serialize: function(converter){
3114          return this.list.getChildren().map(converter || function(el){
3115              return this.elements.indexOf(el);
3116          }, this);
3117      },
3118  
3119      end: function(){
3120          this.previous = null;
3121          document.removeListener('mousemove', this.bound.move);
3122          document.removeListener('mouseup', this.bound.end);
3123          if (this.options.ghost){
3124              document.removeListener('mousemove', this.bound.moveGhost);
3125              this.fireEvent('onDragComplete', [this.active, this.ghost]);
3126          }
3127          this.fireEvent('onComplete', this.active);
3128      }
3129  
3130  });
3131  
3132  Sortables.implement(new Events, new Options);
3133  
3134  var Tips = new Class({
3135  
3136      options: {
3137          onShow: function(tip){
3138              tip.setStyle('visibility', 'visible');
3139          },
3140          onHide: function(tip){
3141              tip.setStyle('visibility', 'hidden');
3142          },
3143          maxTitleChars: 30,
3144          showDelay: 100,
3145          hideDelay: 100,
3146          className: 'tool',
3147          offsets: {'x': 16, 'y': 16},
3148          fixed: false
3149      },
3150  
3151      initialize: function(elements, options){
3152          this.setOptions(options);
3153          this.toolTip = new Element('div', {
3154              'class': this.options.className + '-tip',
3155              'styles': {
3156                  'position': 'absolute',
3157                  'top': '0',
3158                  'left': '0',
3159                  'visibility': 'hidden'
3160              }
3161          }).inject(document.body);
3162          this.wrapper = new Element('div').inject(this.toolTip);
3163          $$(elements).each(this.build, this);
3164          if (this.options.initialize) this.options.initialize.call(this);
3165      },
3166  
3167      build: function(el){
3168          el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
3169          if (el.title){
3170              var dual = el.title.split('::');
3171              if (dual.length > 1){
3172                  el.$tmp.myTitle = dual[0].trim();
3173                  el.$tmp.myText = dual[1].trim();
3174              } else {
3175                  el.$tmp.myText = el.title;
3176              }
3177              el.removeAttribute('title');
3178          } else {
3179              el.$tmp.myText = false;
3180          }
3181          if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";
3182          el.addEvent('mouseenter', function(event){
3183              this.start(el);
3184              if (!this.options.fixed) this.locate(event);
3185              else this.position(el);
3186          }.bind(this));
3187          if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this));
3188          var end = this.end.bind(this);
3189          el.addEvent('mouseleave', end);
3190          el.addEvent('trash', end);
3191      },
3192  
3193      start: function(el){
3194          this.wrapper.empty();
3195          if (el.$tmp.myTitle){
3196              this.title = new Element('span').inject(new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)).setHTML(el.$tmp.myTitle);
3197          }
3198          if (el.$tmp.myText){
3199              this.text = new Element('span').inject(new Element('div', {'class': this.options.className + '-text'}).inject(this.wrapper)).setHTML(el.$tmp.myText);
3200          }
3201          $clear(this.timer);
3202          this.timer = this.show.delay(this.options.showDelay, this);
3203      },
3204  
3205      end: function(event){
3206          $clear(this.timer);
3207          this.timer = this.hide.delay(this.options.hideDelay, this);
3208      },
3209  
3210      position: function(element){
3211          var pos = element.getPosition();
3212          this.toolTip.setStyles({
3213              'left': pos.x + this.options.offsets.x,
3214              'top': pos.y + this.options.offsets.y
3215          });
3216      },
3217  
3218      locate: function(event){
3219          var win = {'x': window.getWidth(), 'y': window.getHeight()};
3220          var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
3221          var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
3222          var prop = {'x': 'left', 'y': 'top'};
3223          for (var z in prop){
3224              var pos = event.page[z] + this.options.offsets[z];
3225              if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
3226              this.toolTip.setStyle(prop[z], pos);
3227          };
3228      },
3229  
3230      show: function(){
3231          if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this);
3232          this.fireEvent('onShow', [this.toolTip]);
3233      },
3234  
3235      hide: function(){
3236          this.fireEvent('onHide', [this.toolTip]);
3237      }
3238  
3239  });
3240  
3241  Tips.implement(new Events, new Options);
3242  
3243  var Group = new Class({
3244  
3245      initialize: function(){
3246          this.instances = $A(arguments);
3247          this.events = {};
3248          this.checker = {};
3249      },
3250  
3251      addEvent: function(type, fn){
3252          this.checker[type] = this.checker[type] || {};
3253          this.events[type] = this.events[type] || [];
3254          if (this.events[type].contains(fn)) return false;
3255          else this.events[type].push(fn);
3256          this.instances.each(function(instance, i){
3257              instance.addEvent(type, this.check.bind(this, [type, instance, i]));
3258          }, this);
3259          return this;
3260      },
3261  
3262      check: function(type, instance, i){
3263          this.checker[type][i] = true;
3264          var every = this.instances.every(function(current, j){
3265              return this.checker[type][j] || false;
3266          }, this);
3267          if (!every) return;
3268          this.checker[type] = {};
3269          this.events[type].each(function(event){
3270              event.call(this, this.instances, instance);
3271          }, this);
3272      }
3273  
3274  });
3275  
3276  var Accordion = Fx.Elements.extend({
3277  
3278      options: {
3279          onActive: Class.empty,
3280          onBackground: Class.empty,
3281          display: 0,
3282          show: false,
3283          height: true,
3284          width: false,
3285          opacity: true,
3286          fixedHeight: false,
3287          fixedWidth: false,
3288          wait: false,
3289          alwaysHide: false
3290      },
3291  
3292      initialize: function(){
3293          var options, togglers, elements, container;
3294          $each(arguments, function(argument, i){
3295              switch($type(argument)){
3296                  case 'object': options = argument; break;
3297                  case 'element': container = $(argument); break;
3298                  default:
3299                      var temp = $$(argument);
3300                      if (!togglers) togglers = temp;
3301                      else elements = temp;
3302              }
3303          });
3304          this.togglers = togglers || [];
3305          this.elements = elements || [];
3306          this.container = $(container);
3307          this.setOptions(options);
3308          this.previous = -1;
3309          if (this.options.alwaysHide) this.options.wait = true;
3310          if ($chk(this.options.show)){
3311              this.options.display = false;
3312              this.previous = this.options.show;
3313          }
3314          if (this.options.start){
3315              this.options.display = false;
3316              this.options.show = false;
3317          }
3318          this.effects = {};
3319          if (this.options.opacity) this.effects.opacity = 'fullOpacity';
3320          if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
3321          if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
3322          for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);
3323          this.elements.each(function(el, i){
3324              if (this.options.show === i){
3325                  this.fireEvent('onActive', [this.togglers[i], el]);
3326              } else {
3327                  for (var fx in this.effects) el.setStyle(fx, 0);
3328              }
3329          }, this);
3330          this.parent(this.elements);
3331          if ($chk(this.options.display)) this.display(this.options.display);
3332      },
3333  
3334      addSection: function(toggler, element, pos){
3335          toggler = $(toggler);
3336          element = $(element);
3337          var test = this.togglers.contains(toggler);
3338          var len = this.togglers.length;
3339          this.togglers.include(toggler);
3340          this.elements.include(element);
3341          if (len && (!test || pos)){
3342              pos = $pick(pos, len - 1);
3343              toggler.injectBefore(this.togglers[pos]);
3344              element.injectAfter(toggler);
3345          } else if (this.container && !test){
3346              toggler.inject(this.container);
3347              element.inject(this.container);
3348          }
3349          var idx = this.togglers.indexOf(toggler);
3350          toggler.addEvent('click', this.display.bind(this, idx));
3351          if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
3352          if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
3353          element.fullOpacity = 1;
3354          if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
3355          if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
3356          element.setStyle('overflow', 'hidden');
3357          if (!test){
3358              for (var fx in this.effects) element.setStyle(fx, 0);
3359          }
3360          return this;
3361      },
3362  
3363      display: function(index){
3364          index = ($type(index) == 'element') ? this.elements.indexOf(index) : index;
3365          if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
3366          this.previous = index;
3367          var obj = {};
3368          this.elements.each(function(el, i){
3369              obj[i] = {};
3370              var hide = (i != index) || (this.options.alwaysHide && (el.offsetHeight > 0));
3371              this.fireEvent(hide ? 'onBackground' : 'onActive', [this.togglers[i], el]);
3372              for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];
3373          }, this);
3374          return this.start(obj);
3375      },
3376  
3377      showThisHideOpen: function(index){return this.display(index);}
3378  
3379  });
3380  
3381  Fx.Accordion = Accordion;


Generated: Wed Dec 30 05:55:15 2009 Cross-referenced by PHPXref 0.7