prototype.js
上传用户:xinhua
上传日期:2016-04-15
资源大小:19064k
文件大小:48k
源码类别:

通讯/手机编程

开发平台:

MultiPlatform

  1. /*  Prototype JavaScript framework, version 1.4.0
  2.  *  (c) 2005 Sam Stephenson <sam@conio.net>
  3.  *
  4.  *  THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff
  5.  *  against the source tree, available from the Prototype darcs repository.
  6.  *
  7.  *  Prototype is freely distributable under the terms of an MIT-style license.
  8.  *
  9.  *  For details, see the Prototype web site: http://prototype.conio.net/
  10.  *
  11. /*--------------------------------------------------------------------------*/
  12. var Prototype = {
  13.   Version: '1.4.0',
  14.   ScriptFragment: '(?:<script.*?>)((n|r|.)*?)(?:</script>)',
  15.   emptyFunction: function() {},
  16.   K: function(x) {return x}
  17. }
  18. var Class = {
  19.   create: function() {
  20.     return function() {
  21.       this.initialize.apply(this, arguments);
  22.     }
  23.   }
  24. }
  25. var Abstract = new Object();
  26. Object.extend = function(destination, source) {
  27.   for (property in source) {
  28.     destination[property] = source[property];
  29.   }
  30.   return destination;
  31. }
  32. Object.inspect = function(object) {
  33.   try {
  34.     if (object == undefined) return 'undefined';
  35.     if (object == null) return 'null';
  36.     return object.inspect ? object.inspect() : object.toString();
  37.   } catch (e) {
  38.     if (e instanceof RangeError) return '...';
  39.     throw e;
  40.   }
  41. }
  42. Function.prototype.bind = function() {
  43.   var __method = this, args = $A(arguments), object = args.shift();
  44.   return function() {
  45.     return __method.apply(object, args.concat($A(arguments)));
  46.   }
  47. }
  48. Function.prototype.bindAsEventListener = function(object) {
  49.   var __method = this;
  50.   return function(event) {
  51.     return __method.call(object, event || window.event);
  52.   }
  53. }
  54. Object.extend(Number.prototype, {
  55.   toColorPart: function() {
  56.     var digits = this.toString(16);
  57.     if (this < 16) return '0' + digits;
  58.     return digits;
  59.   },
  60.   succ: function() {
  61.     return this + 1;
  62.   },
  63.   times: function(iterator) {
  64.     $R(0, this, true).each(iterator);
  65.     return this;
  66.   }
  67. });
  68. var Try = {
  69.   these: function() {
  70.     var returnValue;
  71.     for (var i = 0; i < arguments.length; i++) {
  72.       var lambda = arguments[i];
  73.       try {
  74.         returnValue = lambda();
  75.         break;
  76.       } catch (e) {}
  77.     }
  78.     return returnValue;
  79.   }
  80. }
  81. /*--------------------------------------------------------------------------*/
  82. var PeriodicalExecuter = Class.create();
  83. PeriodicalExecuter.prototype = {
  84.   initialize: function(callback, frequency) {
  85.     this.callback = callback;
  86.     this.frequency = frequency;
  87.     this.currentlyExecuting = false;
  88.     this.registerCallback();
  89.   },
  90.   registerCallback: function() {
  91.     setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  92.   },
  93.   onTimerEvent: function() {
  94.     if (!this.currentlyExecuting) {
  95.       try {
  96.         this.currentlyExecuting = true;
  97.         this.callback();
  98.       } finally {
  99.         this.currentlyExecuting = false;
  100.       }
  101.     }
  102.   }
  103. }
  104. /*--------------------------------------------------------------------------*/
  105. function $() {
  106.   var elements = new Array();
  107.   for (var i = 0; i < arguments.length; i++) {
  108.     var element = arguments[i];
  109.     if (typeof element == 'string')
  110.       element = document.getElementById(element);
  111.     if (arguments.length == 1)
  112.       return element;
  113.     elements.push(element);
  114.   }
  115.   return elements;
  116. }
  117. Object.extend(String.prototype, {
  118.   stripTags: function() {
  119.     return this.replace(/</?[^>]+>/gi, '');
  120.   },
  121.   stripScripts: function() {
  122.     return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  123.   },
  124.   extractScripts: function() {
  125.     var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
  126.     var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
  127.     return (this.match(matchAll) || []).map(function(scriptTag) {
  128.       return (scriptTag.match(matchOne) || ['', ''])[1];
  129.     });
  130.   },
  131.   evalScripts: function() {
  132.     return this.extractScripts().map(eval);
  133.   },
  134.   escapeHTML: function() {
  135.     var div = document.createElement('div');
  136.     var text = document.createTextNode(this);
  137.     div.appendChild(text);
  138.     return div.innerHTML;
  139.   },
  140.   unescapeHTML: function() {
  141.     var div = document.createElement('div');
  142.     div.innerHTML = this.stripTags();
  143.     return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  144.   },
  145.   toQueryParams: function() {
  146.     var pairs = this.match(/^??(.*)$/)[1].split('&');
  147.     return pairs.inject({}, function(params, pairString) {
  148.       var pair = pairString.split('=');
  149.       params[pair[0]] = pair[1];
  150.       return params;
  151.     });
  152.   },
  153.   toArray: function() {
  154.     return this.split('');
  155.   },
  156.   camelize: function() {
  157.     var oStringList = this.split('-');
  158.     if (oStringList.length == 1) return oStringList[0];
  159.     var camelizedString = this.indexOf('-') == 0
  160.       ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
  161.       : oStringList[0];
  162.     for (var i = 1, len = oStringList.length; i < len; i++) {
  163.       var s = oStringList[i];
  164.       camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
  165.     }
  166.     return camelizedString;
  167.   },
  168.   inspect: function() {
  169.     return "'" + this.replace('\', '\\').replace("'", '\'') + "'";
  170.   }
  171. });
  172. String.prototype.parseQuery = String.prototype.toQueryParams;
  173. var $break    = new Object();
  174. var $continue = new Object();
  175. var Enumerable = {
  176.   each: function(iterator) {
  177.     var index = 0;
  178.     try {
  179.       this._each(function(value) {
  180.         try {
  181.           iterator(value, index++);
  182.         } catch (e) {
  183.           if (e != $continue) throw e;
  184.         }
  185.       });
  186.     } catch (e) {
  187.       if (e != $break) throw e;
  188.     }
  189.   },
  190.   all: function(iterator) {
  191.     var result = true;
  192.     this.each(function(value, index) {
  193.       result = result && !!(iterator || Prototype.K)(value, index);
  194.       if (!result) throw $break;
  195.     });
  196.     return result;
  197.   },
  198.   any: function(iterator) {
  199.     var result = true;
  200.     this.each(function(value, index) {
  201.       if (result = !!(iterator || Prototype.K)(value, index))
  202.         throw $break;
  203.     });
  204.     return result;
  205.   },
  206.   collect: function(iterator) {
  207.     var results = [];
  208.     this.each(function(value, index) {
  209.       results.push(iterator(value, index));
  210.     });
  211.     return results;
  212.   },
  213.   detect: function (iterator) {
  214.     var result;
  215.     this.each(function(value, index) {
  216.       if (iterator(value, index)) {
  217.         result = value;
  218.         throw $break;
  219.       }
  220.     });
  221.     return result;
  222.   },
  223.   findAll: function(iterator) {
  224.     var results = [];
  225.     this.each(function(value, index) {
  226.       if (iterator(value, index))
  227.         results.push(value);
  228.     });
  229.     return results;
  230.   },
  231.   grep: function(pattern, iterator) {
  232.     var results = [];
  233.     this.each(function(value, index) {
  234.       var stringValue = value.toString();
  235.       if (stringValue.match(pattern))
  236.         results.push((iterator || Prototype.K)(value, index));
  237.     })
  238.     return results;
  239.   },
  240.   include: function(object) {
  241.     var found = false;
  242.     this.each(function(value) {
  243.       if (value == object) {
  244.         found = true;
  245.         throw $break;
  246.       }
  247.     });
  248.     return found;
  249.   },
  250.   inject: function(memo, iterator) {
  251.     this.each(function(value, index) {
  252.       memo = iterator(memo, value, index);
  253.     });
  254.     return memo;
  255.   },
  256.   invoke: function(method) {
  257.     var args = $A(arguments).slice(1);
  258.     return this.collect(function(value) {
  259.       return value[method].apply(value, args);
  260.     });
  261.   },
  262.   max: function(iterator) {
  263.     var result;
  264.     this.each(function(value, index) {
  265.       value = (iterator || Prototype.K)(value, index);
  266.       if (value >= (result || value))
  267.         result = value;
  268.     });
  269.     return result;
  270.   },
  271.   min: function(iterator) {
  272.     var result;
  273.     this.each(function(value, index) {
  274.       value = (iterator || Prototype.K)(value, index);
  275.       if (value <= (result || value))
  276.         result = value;
  277.     });
  278.     return result;
  279.   },
  280.   partition: function(iterator) {
  281.     var trues = [], falses = [];
  282.     this.each(function(value, index) {
  283.       ((iterator || Prototype.K)(value, index) ?
  284.         trues : falses).push(value);
  285.     });
  286.     return [trues, falses];
  287.   },
  288.   pluck: function(property) {
  289.     var results = [];
  290.     this.each(function(value, index) {
  291.       results.push(value[property]);
  292.     });
  293.     return results;
  294.   },
  295.   reject: function(iterator) {
  296.     var results = [];
  297.     this.each(function(value, index) {
  298.       if (!iterator(value, index))
  299.         results.push(value);
  300.     });
  301.     return results;
  302.   },
  303.   sortBy: function(iterator) {
  304.     return this.collect(function(value, index) {
  305.       return {value: value, criteria: iterator(value, index)};
  306.     }).sort(function(left, right) {
  307.       var a = left.criteria, b = right.criteria;
  308.       return a < b ? -1 : a > b ? 1 : 0;
  309.     }).pluck('value');
  310.   },
  311.   toArray: function() {
  312.     return this.collect(Prototype.K);
  313.   },
  314.   zip: function() {
  315.     var iterator = Prototype.K, args = $A(arguments);
  316.     if (typeof args.last() == 'function')
  317.       iterator = args.pop();
  318.     var collections = [this].concat(args).map($A);
  319.     return this.map(function(value, index) {
  320.       iterator(value = collections.pluck(index));
  321.       return value;
  322.     });
  323.   },
  324.   inspect: function() {
  325.     return '#<Enumerable:' + this.toArray().inspect() + '>';
  326.   }
  327. }
  328. Object.extend(Enumerable, {
  329.   map:     Enumerable.collect,
  330.   find:    Enumerable.detect,
  331.   select:  Enumerable.findAll,
  332.   member:  Enumerable.include,
  333.   entries: Enumerable.toArray
  334. });
  335. var $A = Array.from = function(iterable) {
  336.   if (!iterable) return [];
  337.   if (iterable.toArray) {
  338.     return iterable.toArray();
  339.   } else {
  340.     var results = [];
  341.     for (var i = 0; i < iterable.length; i++)
  342.       results.push(iterable[i]);
  343.     return results;
  344.   }
  345. }
  346. Object.extend(Array.prototype, Enumerable);
  347. Array.prototype._reverse = Array.prototype.reverse;
  348. Object.extend(Array.prototype, {
  349.   _each: function(iterator) {
  350.     for (var i = 0; i < this.length; i++)
  351.       iterator(this[i]);
  352.   },
  353.   clear: function() {
  354.     this.length = 0;
  355.     return this;
  356.   },
  357.   first: function() {
  358.     return this[0];
  359.   },
  360.   last: function() {
  361.     return this[this.length - 1];
  362.   },
  363.   compact: function() {
  364.     return this.select(function(value) {
  365.       return value != undefined || value != null;
  366.     });
  367.   },
  368.   flatten: function() {
  369.     return this.inject([], function(array, value) {
  370.       return array.concat(value.constructor == Array ?
  371.         value.flatten() : [value]);
  372.     });
  373.   },
  374.   without: function() {
  375.     var values = $A(arguments);
  376.     return this.select(function(value) {
  377.       return !values.include(value);
  378.     });
  379.   },
  380.   indexOf: function(object) {
  381.     for (var i = 0; i < this.length; i++)
  382.       if (this[i] == object) return i;
  383.     return -1;
  384.   },
  385.   reverse: function(inline) {
  386.     return (inline !== false ? this : this.toArray())._reverse();
  387.   },
  388.   shift: function() {
  389.     var result = this[0];
  390.     for (var i = 0; i < this.length - 1; i++)
  391.       this[i] = this[i + 1];
  392.     this.length--;
  393.     return result;
  394.   },
  395.   inspect: function() {
  396.     return '[' + this.map(Object.inspect).join(', ') + ']';
  397.   }
  398. });
  399. var Hash = {
  400.   _each: function(iterator) {
  401.     for (key in this) {
  402.       var value = this[key];
  403.       if (typeof value == 'function') continue;
  404.       var pair = [key, value];
  405.       pair.key = key;
  406.       pair.value = value;
  407.       iterator(pair);
  408.     }
  409.   },
  410.   keys: function() {
  411.     return this.pluck('key');
  412.   },
  413.   values: function() {
  414.     return this.pluck('value');
  415.   },
  416.   merge: function(hash) {
  417.     return $H(hash).inject($H(this), function(mergedHash, pair) {
  418.       mergedHash[pair.key] = pair.value;
  419.       return mergedHash;
  420.     });
  421.   },
  422.   toQueryString: function() {
  423.     return this.map(function(pair) {
  424.       return pair.map(encodeURIComponent).join('=');
  425.     }).join('&');
  426.   },
  427.   inspect: function() {
  428.     return '#<Hash:{' + this.map(function(pair) {
  429.       return pair.map(Object.inspect).join(': ');
  430.     }).join(', ') + '}>';
  431.   }
  432. }
  433. function $H(object) {
  434.   var hash = Object.extend({}, object || {});
  435.   Object.extend(hash, Enumerable);
  436.   Object.extend(hash, Hash);
  437.   return hash;
  438. }
  439. ObjectRange = Class.create();
  440. Object.extend(ObjectRange.prototype, Enumerable);
  441. Object.extend(ObjectRange.prototype, {
  442.   initialize: function(start, end, exclusive) {
  443.     this.start = start;
  444.     this.end = end;
  445.     this.exclusive = exclusive;
  446.   },
  447.   _each: function(iterator) {
  448.     var value = this.start;
  449.     do {
  450.       iterator(value);
  451.       value = value.succ();
  452.     } while (this.include(value));
  453.   },
  454.   include: function(value) {
  455.     if (value < this.start)
  456.       return false;
  457.     if (this.exclusive)
  458.       return value < this.end;
  459.     return value <= this.end;
  460.   }
  461. });
  462. var $R = function(start, end, exclusive) {
  463.   return new ObjectRange(start, end, exclusive);
  464. }
  465. var Ajax = {
  466.   getTransport: function() {
  467.     return Try.these(
  468.       function() {return new ActiveXObject('Msxml2.XMLHTTP')},
  469.       function() {return new ActiveXObject('Microsoft.XMLHTTP')},
  470.       function() {return new XMLHttpRequest()}
  471.     ) || false;
  472.   },
  473.   activeRequestCount: 0
  474. }
  475. Ajax.Responders = {
  476.   responders: [],
  477.   _each: function(iterator) {
  478.     this.responders._each(iterator);
  479.   },
  480.   register: function(responderToAdd) {
  481.     if (!this.include(responderToAdd))
  482.       this.responders.push(responderToAdd);
  483.   },
  484.   unregister: function(responderToRemove) {
  485.     this.responders = this.responders.without(responderToRemove);
  486.   },
  487.   dispatch: function(callback, request, transport, json) {
  488.     this.each(function(responder) {
  489.       if (responder[callback] && typeof responder[callback] == 'function') {
  490.         try {
  491.           responder[callback].apply(responder, [request, transport, json]);
  492.         } catch (e) {}
  493.       }
  494.     });
  495.   }
  496. };
  497. Object.extend(Ajax.Responders, Enumerable);
  498. Ajax.Responders.register({
  499.   onCreate: function() {
  500.     Ajax.activeRequestCount++;
  501.   },
  502.   onComplete: function() {
  503.     Ajax.activeRequestCount--;
  504.   }
  505. });
  506. Ajax.Base = function() {};
  507. Ajax.Base.prototype = {
  508.   setOptions: function(options) {
  509.     this.options = {
  510.       method:       'post',
  511.       asynchronous: true,
  512.       parameters:   ''
  513.     }
  514.     Object.extend(this.options, options || {});
  515.   },
  516.   responseIsSuccess: function() {
  517.     return this.transport.status == undefined
  518.         || this.transport.status == 0
  519.         || (this.transport.status >= 200 && this.transport.status < 300);
  520.   },
  521.   responseIsFailure: function() {
  522.     return !this.responseIsSuccess();
  523.   }
  524. }
  525. Ajax.Request = Class.create();
  526. Ajax.Request.Events =
  527.   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
  528. Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  529.   initialize: function(url, options) {
  530.     this.transport = Ajax.getTransport();
  531.     this.setOptions(options);
  532.     this.request(url);
  533.   },
  534.   request: function(url) {
  535.     var parameters = this.options.parameters || '';
  536.     if (parameters.length > 0) parameters += '&_=';
  537.     try {
  538.       this.url = url;
  539.       if (this.options.method == 'get' && parameters.length > 0)
  540.         this.url += (this.url.match(/?/) ? '&' : '?') + parameters;
  541.       Ajax.Responders.dispatch('onCreate', this, this.transport);
  542.       this.transport.open(this.options.method, this.url,
  543.         this.options.asynchronous);
  544.       if (this.options.asynchronous) {
  545.         this.transport.onreadystatechange = this.onStateChange.bind(this);
  546.         setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
  547.       }
  548.       this.setRequestHeaders();
  549.       var body = this.options.postBody ? this.options.postBody : parameters;
  550.       this.transport.send(this.options.method == 'post' ? body : null);
  551.     } catch (e) {
  552.       this.dispatchException(e);
  553.     }
  554.   },
  555.   setRequestHeaders: function() {
  556.     var requestHeaders =
  557.       ['X-Requested-With', 'XMLHttpRequest',
  558.        'X-Prototype-Version', Prototype.Version];
  559.     if (this.options.method == 'post') {
  560.       requestHeaders.push('Content-type',
  561.         'application/x-www-form-urlencoded');
  562.       /* Force "Connection: close" for Mozilla browsers to work around
  563.        * a bug where XMLHttpReqeuest sends an incorrect Content-length
  564.        * header. See Mozilla Bugzilla #246651.
  565.        */
  566.       if (this.transport.overrideMimeType)
  567.         requestHeaders.push('Connection', 'close');
  568.     }
  569.     if (this.options.requestHeaders)
  570.       requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
  571.     for (var i = 0; i < requestHeaders.length; i += 2)
  572.       this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  573.   },
  574.   onStateChange: function() {
  575.     var readyState = this.transport.readyState;
  576.     if (readyState != 1)
  577.       this.respondToReadyState(this.transport.readyState);
  578.   },
  579.   header: function(name) {
  580.     try {
  581.       return this.transport.getResponseHeader(name);
  582.     } catch (e) {}
  583.   },
  584.   evalJSON: function() {
  585.     try {
  586.       return eval(this.header('X-JSON'));
  587.     } catch (e) {}
  588.   },
  589.   evalResponse: function() {
  590.     try {
  591.       return eval(this.transport.responseText);
  592.     } catch (e) {
  593.       this.dispatchException(e);
  594.     }
  595.   },
  596.   respondToReadyState: function(readyState) {
  597.     var event = Ajax.Request.Events[readyState];
  598.     var transport = this.transport, json = this.evalJSON();
  599.     if (event == 'Complete') {
  600.       try {
  601.         (this.options['on' + this.transport.status]
  602.          || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
  603.          || Prototype.emptyFunction)(transport, json);
  604.       } catch (e) {
  605.         this.dispatchException(e);
  606.       }
  607.       if ((this.header('Content-type') || '').match(/^text/javascript/i))
  608.         this.evalResponse();
  609.     }
  610.     try {
  611.       (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
  612.       Ajax.Responders.dispatch('on' + event, this, transport, json);
  613.     } catch (e) {
  614.       this.dispatchException(e);
  615.     }
  616.     /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
  617.     if (event == 'Complete')
  618.       this.transport.onreadystatechange = Prototype.emptyFunction;
  619.   },
  620.   dispatchException: function(exception) {
  621.     (this.options.onException || Prototype.emptyFunction)(this, exception);
  622.     Ajax.Responders.dispatch('onException', this, exception);
  623.   }
  624. });
  625. Ajax.Updater = Class.create();
  626. Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  627.   initialize: function(container, url, options) {
  628.     this.containers = {
  629.       success: container.success ? $(container.success) : $(container),
  630.       failure: container.failure ? $(container.failure) :
  631.         (container.success ? null : $(container))
  632.     }
  633.     this.transport = Ajax.getTransport();
  634.     this.setOptions(options);
  635.     var onComplete = this.options.onComplete || Prototype.emptyFunction;
  636.     this.options.onComplete = (function(transport, object) {
  637.       this.updateContent();
  638.       onComplete(transport, object);
  639.     }).bind(this);
  640.     this.request(url);
  641.   },
  642.   updateContent: function() {
  643.     var receiver = this.responseIsSuccess() ?
  644.       this.containers.success : this.containers.failure;
  645.     var response = this.transport.responseText;
  646.     if (!this.options.evalScripts)
  647.       response = response.stripScripts();
  648.     if (receiver) {
  649.       if (this.options.insertion) {
  650.         new this.options.insertion(receiver, response);
  651.       } else {
  652.         Element.update(receiver, response);
  653.       }
  654.     }
  655.     if (this.responseIsSuccess()) {
  656.       if (this.onComplete)
  657.         setTimeout(this.onComplete.bind(this), 10);
  658.     }
  659.   }
  660. });
  661. Ajax.PeriodicalUpdater = Class.create();
  662. Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  663.   initialize: function(container, url, options) {
  664.     this.setOptions(options);
  665.     this.onComplete = this.options.onComplete;
  666.     this.frequency = (this.options.frequency || 2);
  667.     this.decay = (this.options.decay || 1);
  668.     this.updater = {};
  669.     this.container = container;
  670.     this.url = url;
  671.     this.start();
  672.   },
  673.   start: function() {
  674.     this.options.onComplete = this.updateComplete.bind(this);
  675.     this.onTimerEvent();
  676.   },
  677.   stop: function() {
  678.     this.updater.onComplete = undefined;
  679.     clearTimeout(this.timer);
  680.     (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  681.   },
  682.   updateComplete: function(request) {
  683.     if (this.options.decay) {
  684.       this.decay = (request.responseText == this.lastText ?
  685.         this.decay * this.options.decay : 1);
  686.       this.lastText = request.responseText;
  687.     }
  688.     this.timer = setTimeout(this.onTimerEvent.bind(this),
  689.       this.decay * this.frequency * 1000);
  690.   },
  691.   onTimerEvent: function() {
  692.     this.updater = new Ajax.Updater(this.container, this.url, this.options);
  693.   }
  694. });
  695. document.getElementsByClassName = function(className, parentElement) {
  696.   var children = ($(parentElement) || document.body).getElementsByTagName('*');
  697.   return $A(children).inject([], function(elements, child) {
  698.     if (child.className.match(new RegExp("(^|\s)" + className + "(\s|$)")))
  699.       elements.push(child);
  700.     return elements;
  701.   });
  702. }
  703. /*--------------------------------------------------------------------------*/
  704. if (!window.Element) {
  705.   var Element = new Object();
  706. }
  707. Object.extend(Element, {
  708.   visible: function(element) {
  709.     return $(element).style.display != 'none';
  710.   },
  711.   toggle: function() {
  712.     for (var i = 0; i < arguments.length; i++) {
  713.       var element = $(arguments[i]);
  714.       Element[Element.visible(element) ? 'hide' : 'show'](element);
  715.     }
  716.   },
  717.   hide: function() {
  718.     for (var i = 0; i < arguments.length; i++) {
  719.       var element = $(arguments[i]);
  720.       element.style.display = 'none';
  721.     }
  722.   },
  723.   show: function() {
  724.     for (var i = 0; i < arguments.length; i++) {
  725.       var element = $(arguments[i]);
  726.       element.style.display = '';
  727.     }
  728.   },
  729.   remove: function(element) {
  730.     element = $(element);
  731.     element.parentNode.removeChild(element);
  732.   },
  733.   update: function(element, html) {
  734.     $(element).innerHTML = html.stripScripts();
  735.     setTimeout(function() {html.evalScripts()}, 10);
  736.   },
  737.   getHeight: function(element) {
  738.     element = $(element);
  739.     return element.offsetHeight;
  740.   },
  741.   classNames: function(element) {
  742.     return new Element.ClassNames(element);
  743.   },
  744.   hasClassName: function(element, className) {
  745.     if (!(element = $(element))) return;
  746.     return Element.classNames(element).include(className);
  747.   },
  748.   addClassName: function(element, className) {
  749.     if (!(element = $(element))) return;
  750.     return Element.classNames(element).add(className);
  751.   },
  752.   removeClassName: function(element, className) {
  753.     if (!(element = $(element))) return;
  754.     return Element.classNames(element).remove(className);
  755.   },
  756.   // removes whitespace-only text node children
  757.   cleanWhitespace: function(element) {
  758.     element = $(element);
  759.     for (var i = 0; i < element.childNodes.length; i++) {
  760.       var node = element.childNodes[i];
  761.       if (node.nodeType == 3 && !/S/.test(node.nodeValue))
  762.         Element.remove(node);
  763.     }
  764.   },
  765.   empty: function(element) {
  766.     return $(element).innerHTML.match(/^s*$/);
  767.   },
  768.   scrollTo: function(element) {
  769.     element = $(element);
  770.     var x = element.x ? element.x : element.offsetLeft,
  771.         y = element.y ? element.y : element.offsetTop;
  772.     window.scrollTo(x, y);
  773.   },
  774.   getStyle: function(element, style) {
  775.     element = $(element);
  776.     var value = element.style[style.camelize()];
  777.     if (!value) {
  778.       if (document.defaultView && document.defaultView.getComputedStyle) {
  779.         var css = document.defaultView.getComputedStyle(element, null);
  780.         value = css ? css.getPropertyValue(style) : null;
  781.       } else if (element.currentStyle) {
  782.         value = element.currentStyle[style.camelize()];
  783.       }
  784.     }
  785.     if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
  786.       if (Element.getStyle(element, 'position') == 'static') value = 'auto';
  787.     return value == 'auto' ? null : value;
  788.   },
  789.   setStyle: function(element, style) {
  790.     element = $(element);
  791.     for (name in style)
  792.       element.style[name.camelize()] = style[name];
  793.   },
  794.   getDimensions: function(element) {
  795.     element = $(element);
  796.     if (Element.getStyle(element, 'display') != 'none')
  797.       return {width: element.offsetWidth, height: element.offsetHeight};
  798.     // All *Width and *Height properties give 0 on elements with display none,
  799.     // so enable the element temporarily
  800.     var els = element.style;
  801.     var originalVisibility = els.visibility;
  802.     var originalPosition = els.position;
  803.     els.visibility = 'hidden';
  804.     els.position = 'absolute';
  805.     els.display = '';
  806.     var originalWidth = element.clientWidth;
  807.     var originalHeight = element.clientHeight;
  808.     els.display = 'none';
  809.     els.position = originalPosition;
  810.     els.visibility = originalVisibility;
  811.     return {width: originalWidth, height: originalHeight};
  812.   },
  813.   makePositioned: function(element) {
  814.     element = $(element);
  815.     var pos = Element.getStyle(element, 'position');
  816.     if (pos == 'static' || !pos) {
  817.       element._madePositioned = true;
  818.       element.style.position = 'relative';
  819.       // Opera returns the offset relative to the positioning context, when an
  820.       // element is position relative but top and left have not been defined
  821.       if (window.opera) {
  822.         element.style.top = 0;
  823.         element.style.left = 0;
  824.       }
  825.     }
  826.   },
  827.   undoPositioned: function(element) {
  828.     element = $(element);
  829.     if (element._madePositioned) {
  830.       element._madePositioned = undefined;
  831.       element.style.position =
  832.         element.style.top =
  833.         element.style.left =
  834.         element.style.bottom =
  835.         element.style.right = '';
  836.     }
  837.   },
  838.   makeClipping: function(element) {
  839.     element = $(element);
  840.     if (element._overflow) return;
  841.     element._overflow = element.style.overflow;
  842.     if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
  843.       element.style.overflow = 'hidden';
  844.   },
  845.   undoClipping: function(element) {
  846.     element = $(element);
  847.     if (element._overflow) return;
  848.     element.style.overflow = element._overflow;
  849.     element._overflow = undefined;
  850.   }
  851. });
  852. var Toggle = new Object();
  853. Toggle.display = Element.toggle;
  854. /*--------------------------------------------------------------------------*/
  855. Abstract.Insertion = function(adjacency) {
  856.   this.adjacency = adjacency;
  857. }
  858. Abstract.Insertion.prototype = {
  859.   initialize: function(element, content) {
  860.     this.element = $(element);
  861.     this.content = content.stripScripts();
  862.     if (this.adjacency && this.element.insertAdjacentHTML) {
  863.       try {
  864.         this.element.insertAdjacentHTML(this.adjacency, this.content);
  865.       } catch (e) {
  866.         if (this.element.tagName.toLowerCase() == 'tbody') {
  867.           this.insertContent(this.contentFromAnonymousTable());
  868.         } else {
  869.           throw e;
  870.         }
  871.       }
  872.     } else {
  873.       this.range = this.element.ownerDocument.createRange();
  874.       if (this.initializeRange) this.initializeRange();
  875.       this.insertContent([this.range.createContextualFragment(this.content)]);
  876.     }
  877.     setTimeout(function() {content.evalScripts()}, 10);
  878.   },
  879.   contentFromAnonymousTable: function() {
  880.     var div = document.createElement('div');
  881.     div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
  882.     return $A(div.childNodes[0].childNodes[0].childNodes);
  883.   }
  884. }
  885. var Insertion = new Object();
  886. Insertion.Before = Class.create();
  887. Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  888.   initializeRange: function() {
  889.     this.range.setStartBefore(this.element);
  890.   },
  891.   insertContent: function(fragments) {
  892.     fragments.each((function(fragment) {
  893.       this.element.parentNode.insertBefore(fragment, this.element);
  894.     }).bind(this));
  895.   }
  896. });
  897. Insertion.Top = Class.create();
  898. Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  899.   initializeRange: function() {
  900.     this.range.selectNodeContents(this.element);
  901.     this.range.collapse(true);
  902.   },
  903.   insertContent: function(fragments) {
  904.     fragments.reverse(false).each((function(fragment) {
  905.       this.element.insertBefore(fragment, this.element.firstChild);
  906.     }).bind(this));
  907.   }
  908. });
  909. Insertion.Bottom = Class.create();
  910. Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  911.   initializeRange: function() {
  912.     this.range.selectNodeContents(this.element);
  913.     this.range.collapse(this.element);
  914.   },
  915.   insertContent: function(fragments) {
  916.     fragments.each((function(fragment) {
  917.       this.element.appendChild(fragment);
  918.     }).bind(this));
  919.   }
  920. });
  921. Insertion.After = Class.create();
  922. Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  923.   initializeRange: function() {
  924.     this.range.setStartAfter(this.element);
  925.   },
  926.   insertContent: function(fragments) {
  927.     fragments.each((function(fragment) {
  928.       this.element.parentNode.insertBefore(fragment,
  929.         this.element.nextSibling);
  930.     }).bind(this));
  931.   }
  932. });
  933. /*--------------------------------------------------------------------------*/
  934. Element.ClassNames = Class.create();
  935. Element.ClassNames.prototype = {
  936.   initialize: function(element) {
  937.     this.element = $(element);
  938.   },
  939.   _each: function(iterator) {
  940.     this.element.className.split(/s+/).select(function(name) {
  941.       return name.length > 0;
  942.     })._each(iterator);
  943.   },
  944.   set: function(className) {
  945.     this.element.className = className;
  946.   },
  947.   add: function(classNameToAdd) {
  948.     if (this.include(classNameToAdd)) return;
  949.     this.set(this.toArray().concat(classNameToAdd).join(' '));
  950.   },
  951.   remove: function(classNameToRemove) {
  952.     if (!this.include(classNameToRemove)) return;
  953.     this.set(this.select(function(className) {
  954.       return className != classNameToRemove;
  955.     }).join(' '));
  956.   },
  957.   toString: function() {
  958.     return this.toArray().join(' ');
  959.   }
  960. }
  961. Object.extend(Element.ClassNames.prototype, Enumerable);
  962. var Field = {
  963.   clear: function() {
  964.     for (var i = 0; i < arguments.length; i++)
  965.       $(arguments[i]).value = '';
  966.   },
  967.   focus: function(element) {
  968.     $(element).focus();
  969.   },
  970.   present: function() {
  971.     for (var i = 0; i < arguments.length; i++)
  972.       if ($(arguments[i]).value == '') return false;
  973.     return true;
  974.   },
  975.   select: function(element) {
  976.     $(element).select();
  977.   },
  978.   activate: function(element) {
  979.     element = $(element);
  980.     element.focus();
  981.     if (element.select)
  982.       element.select();
  983.   }
  984. }
  985. /*--------------------------------------------------------------------------*/
  986. var Form = {
  987.   serialize: function(form) {
  988.     var elements = Form.getElements($(form));
  989.     var queryComponents = new Array();
  990.     for (var i = 0; i < elements.length; i++) {
  991.       var queryComponent = Form.Element.serialize(elements[i]);
  992.       if (queryComponent)
  993.         queryComponents.push(queryComponent);
  994.     }
  995.     return queryComponents.join('&');
  996.   },
  997.   getElements: function(form) {
  998.     form = $(form);
  999.     var elements = new Array();
  1000.     for (tagName in Form.Element.Serializers) {
  1001.       var tagElements = form.getElementsByTagName(tagName);
  1002.       for (var j = 0; j < tagElements.length; j++)
  1003.         elements.push(tagElements[j]);
  1004.     }
  1005.     return elements;
  1006.   },
  1007.   getInputs: function(form, typeName, name) {
  1008.     form = $(form);
  1009.     var inputs = form.getElementsByTagName('input');
  1010.     if (!typeName && !name)
  1011.       return inputs;
  1012.     var matchingInputs = new Array();
  1013.     for (var i = 0; i < inputs.length; i++) {
  1014.       var input = inputs[i];
  1015.       if ((typeName && input.type != typeName) ||
  1016.           (name && input.name != name))
  1017.         continue;
  1018.       matchingInputs.push(input);
  1019.     }
  1020.     return matchingInputs;
  1021.   },
  1022.   disable: function(form) {
  1023.     var elements = Form.getElements(form);
  1024.     for (var i = 0; i < elements.length; i++) {
  1025.       var element = elements[i];
  1026.       element.blur();
  1027.       element.disabled = 'true';
  1028.     }
  1029.   },
  1030.   enable: function(form) {
  1031.     var elements = Form.getElements(form);
  1032.     for (var i = 0; i < elements.length; i++) {
  1033.       var element = elements[i];
  1034.       element.disabled = '';
  1035.     }
  1036.   },
  1037.   findFirstElement: function(form) {
  1038.     return Form.getElements(form).find(function(element) {
  1039.       return element.type != 'hidden' && !element.disabled &&
  1040.         ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
  1041.     });
  1042.   },
  1043.   focusFirstElement: function(form) {
  1044.     Field.activate(Form.findFirstElement(form));
  1045.   },
  1046.   reset: function(form) {
  1047.     $(form).reset();
  1048.   }
  1049. }
  1050. Form.Element = {
  1051.   serialize: function(element) {
  1052.     element = $(element);
  1053.     var method = element.tagName.toLowerCase();
  1054.     var parameter = Form.Element.Serializers[method](element);
  1055.     if (parameter) {
  1056.       var key = encodeURIComponent(parameter[0]);
  1057.       if (key.length == 0) return;
  1058.       if (parameter[1].constructor != Array)
  1059.         parameter[1] = [parameter[1]];
  1060.       return parameter[1].map(function(value) {
  1061.         return key + '=' + encodeURIComponent(value);
  1062.       }).join('&');
  1063.     }
  1064.   },
  1065.   getValue: function(element) {
  1066.     element = $(element);
  1067.     var method = element.tagName.toLowerCase();
  1068.     var parameter = Form.Element.Serializers[method](element);
  1069.     if (parameter)
  1070.       return parameter[1];
  1071.   }
  1072. }
  1073. Form.Element.Serializers = {
  1074.   input: function(element) {
  1075.     switch (element.type.toLowerCase()) {
  1076.       case 'submit':
  1077.       case 'hidden':
  1078.       case 'password':
  1079.       case 'text':
  1080.         return Form.Element.Serializers.textarea(element);
  1081.       case 'checkbox':
  1082.       case 'radio':
  1083.         return Form.Element.Serializers.inputSelector(element);
  1084.     }
  1085.     return false;
  1086.   },
  1087.   inputSelector: function(element) {
  1088.     if (element.checked)
  1089.       return [element.name, element.value];
  1090.   },
  1091.   textarea: function(element) {
  1092.     return [element.name, element.value];
  1093.   },
  1094.   select: function(element) {
  1095.     return Form.Element.Serializers[element.type == 'select-one' ?
  1096.       'selectOne' : 'selectMany'](element);
  1097.   },
  1098.   selectOne: function(element) {
  1099.     var value = '', opt, index = element.selectedIndex;
  1100.     if (index >= 0) {
  1101.       opt = element.options[index];
  1102.       value = opt.value;
  1103.       if (!value && !('value' in opt))
  1104.         value = opt.text;
  1105.     }
  1106.     return [element.name, value];
  1107.   },
  1108.   selectMany: function(element) {
  1109.     var value = new Array();
  1110.     for (var i = 0; i < element.length; i++) {
  1111.       var opt = element.options[i];
  1112.       if (opt.selected) {
  1113.         var optValue = opt.value;
  1114.         if (!optValue && !('value' in opt))
  1115.           optValue = opt.text;
  1116.         value.push(optValue);
  1117.       }
  1118.     }
  1119.     return [element.name, value];
  1120.   }
  1121. }
  1122. /*--------------------------------------------------------------------------*/
  1123. var $F = Form.Element.getValue;
  1124. /*--------------------------------------------------------------------------*/
  1125. Abstract.TimedObserver = function() {}
  1126. Abstract.TimedObserver.prototype = {
  1127.   initialize: function(element, frequency, callback) {
  1128.     this.frequency = frequency;
  1129.     this.element   = $(element);
  1130.     this.callback  = callback;
  1131.     this.lastValue = this.getValue();
  1132.     this.registerCallback();
  1133.   },
  1134.   registerCallback: function() {
  1135.     setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  1136.   },
  1137.   onTimerEvent: function() {
  1138.     var value = this.getValue();
  1139.     if (this.lastValue != value) {
  1140.       this.callback(this.element, value);
  1141.       this.lastValue = value;
  1142.     }
  1143.   }
  1144. }
  1145. Form.Element.Observer = Class.create();
  1146. Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  1147.   getValue: function() {
  1148.     return Form.Element.getValue(this.element);
  1149.   }
  1150. });
  1151. Form.Observer = Class.create();
  1152. Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  1153.   getValue: function() {
  1154.     return Form.serialize(this.element);
  1155.   }
  1156. });
  1157. /*--------------------------------------------------------------------------*/
  1158. Abstract.EventObserver = function() {}
  1159. Abstract.EventObserver.prototype = {
  1160.   initialize: function(element, callback) {
  1161.     this.element  = $(element);
  1162.     this.callback = callback;
  1163.     this.lastValue = this.getValue();
  1164.     if (this.element.tagName.toLowerCase() == 'form')
  1165.       this.registerFormCallbacks();
  1166.     else
  1167.       this.registerCallback(this.element);
  1168.   },
  1169.   onElementEvent: function() {
  1170.     var value = this.getValue();
  1171.     if (this.lastValue != value) {
  1172.       this.callback(this.element, value);
  1173.       this.lastValue = value;
  1174.     }
  1175.   },
  1176.   registerFormCallbacks: function() {
  1177.     var elements = Form.getElements(this.element);
  1178.     for (var i = 0; i < elements.length; i++)
  1179.       this.registerCallback(elements[i]);
  1180.   },
  1181.   registerCallback: function(element) {
  1182.     if (element.type) {
  1183.       switch (element.type.toLowerCase()) {
  1184.         case 'checkbox':
  1185.         case 'radio':
  1186.           Event.observe(element, 'click', this.onElementEvent.bind(this));
  1187.           break;
  1188.         case 'password':
  1189.         case 'text':
  1190.         case 'textarea':
  1191.         case 'select-one':
  1192.         case 'select-multiple':
  1193.           Event.observe(element, 'change', this.onElementEvent.bind(this));
  1194.           break;
  1195.       }
  1196.     }
  1197.   }
  1198. }
  1199. Form.Element.EventObserver = Class.create();
  1200. Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  1201.   getValue: function() {
  1202.     return Form.Element.getValue(this.element);
  1203.   }
  1204. });
  1205. Form.EventObserver = Class.create();
  1206. Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  1207.   getValue: function() {
  1208.     return Form.serialize(this.element);
  1209.   }
  1210. });
  1211. if (!window.Event) {
  1212.   var Event = new Object();
  1213. }
  1214. Object.extend(Event, {
  1215.   KEY_BACKSPACE: 8,
  1216.   KEY_TAB:       9,
  1217.   KEY_RETURN:   13,
  1218.   KEY_ESC:      27,
  1219.   KEY_LEFT:     37,
  1220.   KEY_UP:       38,
  1221.   KEY_RIGHT:    39,
  1222.   KEY_DOWN:     40,
  1223.   KEY_DELETE:   46,
  1224.   element: function(event) {
  1225.     return event.target || event.srcElement;
  1226.   },
  1227.   isLeftClick: function(event) {
  1228.     return (((event.which) && (event.which == 1)) ||
  1229.             ((event.button) && (event.button == 1)));
  1230.   },
  1231.   pointerX: function(event) {
  1232.     return event.pageX || (event.clientX +
  1233.       (document.documentElement.scrollLeft || document.body.scrollLeft));
  1234.   },
  1235.   pointerY: function(event) {
  1236.     return event.pageY || (event.clientY +
  1237.       (document.documentElement.scrollTop || document.body.scrollTop));
  1238.   },
  1239.   stop: function(event) {
  1240.     if (event.preventDefault) {
  1241.       event.preventDefault();
  1242.       event.stopPropagation();
  1243.     } else {
  1244.       event.returnValue = false;
  1245.       event.cancelBubble = true;
  1246.     }
  1247.   },
  1248.   // find the first node with the given tagName, starting from the
  1249.   // node the event was triggered on; traverses the DOM upwards
  1250.   findElement: function(event, tagName) {
  1251.     var element = Event.element(event);
  1252.     while (element.parentNode && (!element.tagName ||
  1253.         (element.tagName.toUpperCase() != tagName.toUpperCase())))
  1254.       element = element.parentNode;
  1255.     return element;
  1256.   },
  1257.   observers: false,
  1258.   _observeAndCache: function(element, name, observer, useCapture) {
  1259.     if (!this.observers) this.observers = [];
  1260.     if (element.addEventListener) {
  1261.       this.observers.push([element, name, observer, useCapture]);
  1262.       element.addEventListener(name, observer, useCapture);
  1263.     } else if (element.attachEvent) {
  1264.       this.observers.push([element, name, observer, useCapture]);
  1265.       element.attachEvent('on' + name, observer);
  1266.     }
  1267.   },
  1268.   unloadCache: function() {
  1269.     if (!Event.observers) return;
  1270.     for (var i = 0; i < Event.observers.length; i++) {
  1271.       Event.stopObserving.apply(this, Event.observers[i]);
  1272.       Event.observers[i][0] = null;
  1273.     }
  1274.     Event.observers = false;
  1275.   },
  1276.   observe: function(element, name, observer, useCapture) {
  1277.     var element = $(element);
  1278.     useCapture = useCapture || false;
  1279.     if (name == 'keypress' &&
  1280.         (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
  1281.         || element.attachEvent))
  1282.       name = 'keydown';
  1283.     this._observeAndCache(element, name, observer, useCapture);
  1284.   },
  1285.   stopObserving: function(element, name, observer, useCapture) {
  1286.     var element = $(element);
  1287.     useCapture = useCapture || false;
  1288.     if (name == 'keypress' &&
  1289.         (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
  1290.         || element.detachEvent))
  1291.       name = 'keydown';
  1292.     if (element.removeEventListener) {
  1293.       element.removeEventListener(name, observer, useCapture);
  1294.     } else if (element.detachEvent) {
  1295.       element.detachEvent('on' + name, observer);
  1296.     }
  1297.   }
  1298. });
  1299. /* prevent memory leaks in IE */
  1300. Event.observe(window, 'unload', Event.unloadCache, false);
  1301. var Position = {
  1302.   // set to true if needed, warning: firefox performance problems
  1303.   // NOT neeeded for page scrolling, only if draggable contained in
  1304.   // scrollable elements
  1305.   includeScrollOffsets: false,
  1306.   // must be called before calling withinIncludingScrolloffset, every time the
  1307.   // page is scrolled
  1308.   prepare: function() {
  1309.     this.deltaX =  window.pageXOffset
  1310.                 || document.documentElement.scrollLeft
  1311.                 || document.body.scrollLeft
  1312.                 || 0;
  1313.     this.deltaY =  window.pageYOffset
  1314.                 || document.documentElement.scrollTop
  1315.                 || document.body.scrollTop
  1316.                 || 0;
  1317.   },
  1318.   realOffset: function(element) {
  1319.     var valueT = 0, valueL = 0;
  1320.     do {
  1321.       valueT += element.scrollTop  || 0;
  1322.       valueL += element.scrollLeft || 0;
  1323.       element = element.parentNode;
  1324.     } while (element);
  1325.     return [valueL, valueT];
  1326.   },
  1327.   cumulativeOffset: function(element) {
  1328.     var valueT = 0, valueL = 0;
  1329.     do {
  1330.       valueT += element.offsetTop  || 0;
  1331.       valueL += element.offsetLeft || 0;
  1332.       element = element.offsetParent;
  1333.     } while (element);
  1334.     return [valueL, valueT];
  1335.   },
  1336.   positionedOffset: function(element) {
  1337.     var valueT = 0, valueL = 0;
  1338.     do {
  1339.       valueT += element.offsetTop  || 0;
  1340.       valueL += element.offsetLeft || 0;
  1341.       element = element.offsetParent;
  1342.       if (element) {
  1343.         p = Element.getStyle(element, 'position');
  1344.         if (p == 'relative' || p == 'absolute') break;
  1345.       }
  1346.     } while (element);
  1347.     return [valueL, valueT];
  1348.   },
  1349.   offsetParent: function(element) {
  1350.     if (element.offsetParent) return element.offsetParent;
  1351.     if (element == document.body) return element;
  1352.     while ((element = element.parentNode) && element != document.body)
  1353.       if (Element.getStyle(element, 'position') != 'static')
  1354.         return element;
  1355.     return document.body;
  1356.   },
  1357.   // caches x/y coordinate pair to use with overlap
  1358.   within: function(element, x, y) {
  1359.     if (this.includeScrollOffsets)
  1360.       return this.withinIncludingScrolloffsets(element, x, y);
  1361.     this.xcomp = x;
  1362.     this.ycomp = y;
  1363.     this.offset = this.cumulativeOffset(element);
  1364.     return (y >= this.offset[1] &&
  1365.             y <  this.offset[1] + element.offsetHeight &&
  1366.             x >= this.offset[0] &&
  1367.             x <  this.offset[0] + element.offsetWidth);
  1368.   },
  1369.   withinIncludingScrolloffsets: function(element, x, y) {
  1370.     var offsetcache = this.realOffset(element);
  1371.     this.xcomp = x + offsetcache[0] - this.deltaX;
  1372.     this.ycomp = y + offsetcache[1] - this.deltaY;
  1373.     this.offset = this.cumulativeOffset(element);
  1374.     return (this.ycomp >= this.offset[1] &&
  1375.             this.ycomp <  this.offset[1] + element.offsetHeight &&
  1376.             this.xcomp >= this.offset[0] &&
  1377.             this.xcomp <  this.offset[0] + element.offsetWidth);
  1378.   },
  1379.   // within must be called directly before
  1380.   overlap: function(mode, element) {
  1381.     if (!mode) return 0;
  1382.     if (mode == 'vertical')
  1383.       return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
  1384.         element.offsetHeight;
  1385.     if (mode == 'horizontal')
  1386.       return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
  1387.         element.offsetWidth;
  1388.   },
  1389.   clone: function(source, target) {
  1390.     source = $(source);
  1391.     target = $(target);
  1392.     target.style.position = 'absolute';
  1393.     var offsets = this.cumulativeOffset(source);
  1394.     target.style.top    = offsets[1] + 'px';
  1395.     target.style.left   = offsets[0] + 'px';
  1396.     target.style.width  = source.offsetWidth + 'px';
  1397.     target.style.height = source.offsetHeight + 'px';
  1398.   },
  1399.   page: function(forElement) {
  1400.     var valueT = 0, valueL = 0;
  1401.     var element = forElement;
  1402.     do {
  1403.       valueT += element.offsetTop  || 0;
  1404.       valueL += element.offsetLeft || 0;
  1405.       // Safari fix
  1406.       if (element.offsetParent==document.body)
  1407.         if (Element.getStyle(element,'position')=='absolute') break;
  1408.     } while (element = element.offsetParent);
  1409.     element = forElement;
  1410.     do {
  1411.       valueT -= element.scrollTop  || 0;
  1412.       valueL -= element.scrollLeft || 0;
  1413.     } while (element = element.parentNode);
  1414.     return [valueL, valueT];
  1415.   },
  1416.   clone: function(source, target) {
  1417.     var options = Object.extend({
  1418.       setLeft:    true,
  1419.       setTop:     true,
  1420.       setWidth:   true,
  1421.       setHeight:  true,
  1422.       offsetTop:  0,
  1423.       offsetLeft: 0
  1424.     }, arguments[2] || {})
  1425.     // find page position of source
  1426.     source = $(source);
  1427.     var p = Position.page(source);
  1428.     // find coordinate system to use
  1429.     target = $(target);
  1430.     var delta = [0, 0];
  1431.     var parent = null;
  1432.     // delta [0,0] will do fine with position: fixed elements,
  1433.     // position:absolute needs offsetParent deltas
  1434.     if (Element.getStyle(target,'position') == 'absolute') {
  1435.       parent = Position.offsetParent(target);
  1436.       delta = Position.page(parent);
  1437.     }
  1438.     // correct by body offsets (fixes Safari)
  1439.     if (parent == document.body) {
  1440.       delta[0] -= document.body.offsetLeft;
  1441.       delta[1] -= document.body.offsetTop;
  1442.     }
  1443.     // set position
  1444.     if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
  1445.     if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
  1446.     if(options.setWidth)  target.style.width = source.offsetWidth + 'px';
  1447.     if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  1448.   },
  1449.   absolutize: function(element) {
  1450.     element = $(element);
  1451.     if (element.style.position == 'absolute') return;
  1452.     Position.prepare();
  1453.     var offsets = Position.positionedOffset(element);
  1454.     var top     = offsets[1];
  1455.     var left    = offsets[0];
  1456.     var width   = element.clientWidth;
  1457.     var height  = element.clientHeight;
  1458.     element._originalLeft   = left - parseFloat(element.style.left  || 0);
  1459.     element._originalTop    = top  - parseFloat(element.style.top || 0);
  1460.     element._originalWidth  = element.style.width;
  1461.     element._originalHeight = element.style.height;
  1462.     element.style.position = 'absolute';
  1463.     element.style.top    = top + 'px';;
  1464.     element.style.left   = left + 'px';;
  1465.     element.style.width  = width + 'px';;
  1466.     element.style.height = height + 'px';;
  1467.   },
  1468.   relativize: function(element) {
  1469.     element = $(element);
  1470.     if (element.style.position == 'relative') return;
  1471.     Position.prepare();
  1472.     element.style.position = 'relative';
  1473.     var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
  1474.     var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
  1475.     element.style.top    = top + 'px';
  1476.     element.style.left   = left + 'px';
  1477.     element.style.height = element._originalHeight;
  1478.     element.style.width  = element._originalWidth;
  1479.   }
  1480. }
  1481. // Safari returns margins on body which is incorrect if the child is absolutely
  1482. // positioned.  For performance reasons, redefine Position.cumulativeOffset for
  1483. // KHTML/WebKit only.
  1484. if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  1485.   Position.cumulativeOffset = function(element) {
  1486.     var valueT = 0, valueL = 0;
  1487.     do {
  1488.       valueT += element.offsetTop  || 0;
  1489.       valueL += element.offsetLeft || 0;
  1490.       if (element.offsetParent == document.body)
  1491.         if (Element.getStyle(element, 'position') == 'absolute') break;
  1492.       element = element.offsetParent;
  1493.     } while (element);
  1494.     return [valueL, valueT];
  1495.   }
  1496. }