Prototype.js
上传用户:jisenq
上传日期:2014-06-29
资源大小:7216k
文件大小:48k
源码类别:

数据库编程

开发平台:

ASP/ASPX

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