Fixing an issue with output parameters that are of type IntPtr
[castle.git] / MonoRail / Castle.MonoRail.Framework / JSResources / Ajax.resx
blobc78c3b1fd3f2dff26842d08b590d89a142a99b6e
1 <?xml version="1.0" encoding="utf-8"?>
2 <root>
3 <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
4 <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
5 <xsd:element name="root" msdata:IsDataSet="true">
6 <xsd:complexType>
7 <xsd:choice maxOccurs="unbounded">
8 <xsd:element name="metadata">
9 <xsd:complexType>
10 <xsd:sequence>
11 <xsd:element name="value" type="xsd:string" minOccurs="0" />
12 </xsd:sequence>
13 <xsd:attribute name="name" use="required" type="xsd:string" />
14 <xsd:attribute name="type" type="xsd:string" />
15 <xsd:attribute name="mimetype" type="xsd:string" />
16 <xsd:attribute ref="xml:space" />
17 </xsd:complexType>
18 </xsd:element>
19 <xsd:element name="assembly">
20 <xsd:complexType>
21 <xsd:attribute name="alias" type="xsd:string" />
22 <xsd:attribute name="name" type="xsd:string" />
23 </xsd:complexType>
24 </xsd:element>
25 <xsd:element name="data">
26 <xsd:complexType>
27 <xsd:sequence>
28 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
29 <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
30 </xsd:sequence>
31 <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
32 <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
33 <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
34 <xsd:attribute ref="xml:space" />
35 </xsd:complexType>
36 </xsd:element>
37 <xsd:element name="resheader">
38 <xsd:complexType>
39 <xsd:sequence>
40 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
41 </xsd:sequence>
42 <xsd:attribute name="name" type="xsd:string" use="required" />
43 </xsd:complexType>
44 </xsd:element>
45 </xsd:choice>
46 </xsd:complexType>
47 </xsd:element>
48 </xsd:schema>
49 <resheader name="resmimetype">
50 <value>text/microsoft-resx</value>
51 </resheader>
52 <resheader name="version">
53 <value>2.0</value>
54 </resheader>
55 <resheader name="reader">
56 <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
57 </resheader>
58 <resheader name="writer">
59 <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
60 </resheader>
61 <data name="jsfunctions" xml:space="preserve">
62 <value><![CDATA[
63 /* Prototype JavaScript framework, version 1.5.1
64 * (c) 2005-2007 Sam Stephenson
66 * Prototype is freely distributable under the terms of an MIT-style license.
67 * For details, see the Prototype web site: http://www.prototypejs.org/
69 /*--------------------------------------------------------------------------*/
71 var Prototype = {
72 Version: '1.5.1',
74 Browser: {
75 IE: !!(window.attachEvent && !window.opera),
76 Opera: !!window.opera,
77 WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
78 Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
81 BrowserFeatures: {
82 XPath: !!document.evaluate,
83 ElementExtensions: !!window.HTMLElement,
84 SpecificElementExtensions:
85 (document.createElement('div').__proto__ !==
86 document.createElement('form').__proto__)
89 ScriptFragment: '<script[^>]*>([\u0001-\uFFFF]*?)</script>',
90 JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/,
92 emptyFunction: function() { },
93 K: function(x) { return x }
96 var Class = {
97 create: function() {
98 return function() {
99 this.initialize.apply(this, arguments);
104 var Abstract = new Object();
106 Object.extend = function(destination, source) {
107 for (var property in source) {
108 destination[property] = source[property];
110 return destination;
113 Object.extend(Object, {
114 inspect: function(object) {
115 try {
116 if (object === undefined) return 'undefined';
117 if (object === null) return 'null';
118 return object.inspect ? object.inspect() : object.toString();
119 } catch (e) {
120 if (e instanceof RangeError) return '...';
121 throw e;
125 toJSON: function(object) {
126 var type = typeof object;
127 switch(type) {
128 case 'undefined':
129 case 'function':
130 case 'unknown': return;
131 case 'boolean': return object.toString();
133 if (object === null) return 'null';
134 if (object.toJSON) return object.toJSON();
135 if (object.ownerDocument === document) return;
136 var results = [];
137 for (var property in object) {
138 var value = Object.toJSON(object[property]);
139 if (value !== undefined)
140 results.push(property.toJSON() + ': ' + value);
142 return '{' + results.join(', ') + '}';
145 keys: function(object) {
146 var keys = [];
147 for (var property in object)
148 keys.push(property);
149 return keys;
152 values: function(object) {
153 var values = [];
154 for (var property in object)
155 values.push(object[property]);
156 return values;
159 clone: function(object) {
160 return Object.extend({}, object);
164 Function.prototype.bind = function() {
165 var __method = this, args = $A(arguments), object = args.shift();
166 return function() {
167 return __method.apply(object, args.concat($A(arguments)));
171 Function.prototype.bindAsEventListener = function(object) {
172 var __method = this, args = $A(arguments), object = args.shift();
173 return function(event) {
174 return __method.apply(object, [event || window.event].concat(args));
178 Object.extend(Number.prototype, {
179 toColorPart: function() {
180 return this.toPaddedString(2, 16);
183 succ: function() {
184 return this + 1;
187 times: function(iterator) {
188 $R(0, this, true).each(iterator);
189 return this;
192 toPaddedString: function(length, radix) {
193 var string = this.toString(radix || 10);
194 return '0'.times(length - string.length) + string;
197 toJSON: function() {
198 return isFinite(this) ? this.toString() : 'null';
202 Date.prototype.toJSON = function() {
203 return '"' + this.getFullYear() + '-' +
204 (this.getMonth() + 1).toPaddedString(2) + '-' +
205 this.getDate().toPaddedString(2) + 'T' +
206 this.getHours().toPaddedString(2) + ':' +
207 this.getMinutes().toPaddedString(2) + ':' +
208 this.getSeconds().toPaddedString(2) + '"';
211 var Try = {
212 these: function() {
213 var returnValue;
215 for (var i = 0, length = arguments.length; i < length; i++) {
216 var lambda = arguments[i];
217 try {
218 returnValue = lambda();
219 break;
220 } catch (e) {}
223 return returnValue;
227 /*--------------------------------------------------------------------------*/
229 var PeriodicalExecuter = Class.create();
230 PeriodicalExecuter.prototype = {
231 initialize: function(callback, frequency) {
232 this.callback = callback;
233 this.frequency = frequency;
234 this.currentlyExecuting = false;
236 this.registerCallback();
239 registerCallback: function() {
240 this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
243 stop: function() {
244 if (!this.timer) return;
245 clearInterval(this.timer);
246 this.timer = null;
249 onTimerEvent: function() {
250 if (!this.currentlyExecuting) {
251 try {
252 this.currentlyExecuting = true;
253 this.callback(this);
254 } finally {
255 this.currentlyExecuting = false;
260 Object.extend(String, {
261 interpret: function(value) {
262 return value == null ? '' : String(value);
264 specialChar: {
265 '\b': '\\b',
266 '\t': '\\t',
267 '\n': '\\n',
268 '\f': '\\f',
269 '\r': '\\r',
270 '\\': '\\\\'
274 Object.extend(String.prototype, {
275 gsub: function(pattern, replacement) {
276 var result = '', source = this, match;
277 replacement = arguments.callee.prepareReplacement(replacement);
279 while (source.length > 0) {
280 if (match = source.match(pattern)) {
281 result += source.slice(0, match.index);
282 result += String.interpret(replacement(match));
283 source = source.slice(match.index + match[0].length);
284 } else {
285 result += source, source = '';
288 return result;
291 sub: function(pattern, replacement, count) {
292 replacement = this.gsub.prepareReplacement(replacement);
293 count = count === undefined ? 1 : count;
295 return this.gsub(pattern, function(match) {
296 if (--count < 0) return match[0];
297 return replacement(match);
301 scan: function(pattern, iterator) {
302 this.gsub(pattern, iterator);
303 return this;
306 truncate: function(length, truncation) {
307 length = length || 30;
308 truncation = truncation === undefined ? '...' : truncation;
309 return this.length > length ?
310 this.slice(0, length - truncation.length) + truncation : this;
313 strip: function() {
314 return this.replace(/^\s+/, '').replace(/\s+$/, '');
317 stripTags: function() {
318 return this.replace(/<\/?[^>]+>/gi, '');
321 stripScripts: function() {
322 return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
325 extractScripts: function() {
326 var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
327 var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
328 return (this.match(matchAll) || []).map(function(scriptTag) {
329 return (scriptTag.match(matchOne) || ['', ''])[1];
333 evalScripts: function() {
334 return this.extractScripts().map(function(script) { return eval(script) });
337 escapeHTML: function() {
338 var self = arguments.callee;
339 self.text.data = this;
340 return self.div.innerHTML;
343 unescapeHTML: function() {
344 var div = document.createElement('div');
345 div.innerHTML = this.stripTags();
346 return div.childNodes[0] ? (div.childNodes.length > 1 ?
347 $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
348 div.childNodes[0].nodeValue) : '';
351 toQueryParams: function(separator) {
352 var match = this.strip().match(/([^?#]*)(#.*)?$/);
353 if (!match) return {};
355 return match[1].split(separator || '&').inject({}, function(hash, pair) {
356 if ((pair = pair.split('='))[0]) {
357 var key = decodeURIComponent(pair.shift());
358 var value = pair.length > 1 ? pair.join('=') : pair[0];
359 if (value != undefined) value = decodeURIComponent(value);
361 if (key in hash) {
362 if (hash[key].constructor != Array) hash[key] = [hash[key]];
363 hash[key].push(value);
365 else hash[key] = value;
367 return hash;
371 toArray: function() {
372 return this.split('');
375 succ: function() {
376 return this.slice(0, this.length - 1) +
377 String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
380 times: function(count) {
381 var result = '';
382 for (var i = 0; i < count; i++) result += this;
383 return result;
386 camelize: function() {
387 var parts = this.split('-'), len = parts.length;
388 if (len == 1) return parts[0];
390 var camelized = this.charAt(0) == '-'
391 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
392 : parts[0];
394 for (var i = 1; i < len; i++)
395 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
397 return camelized;
400 capitalize: function() {
401 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
404 underscore: function() {
405 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
408 dasherize: function() {
409 return this.gsub(/_/,'-');
412 inspect: function(useDoubleQuotes) {
413 var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
414 var character = String.specialChar[match[0]];
415 return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
417 if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
418 return "'" + escapedString.replace(/'/g, '\\\'') + "'";
421 toJSON: function() {
422 return this.inspect(true);
425 unfilterJSON: function(filter) {
426 return this.sub(filter || Prototype.JSONFilter, '#{1}');
429 evalJSON: function(sanitize) {
430 var json = this.unfilterJSON();
431 try {
432 if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
433 return eval('(' + json + ')');
434 } catch (e) { }
435 throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
438 include: function(pattern) {
439 return this.indexOf(pattern) > -1;
442 startsWith: function(pattern) {
443 return this.indexOf(pattern) === 0;
446 endsWith: function(pattern) {
447 var d = this.length - pattern.length;
448 return d >= 0 && this.lastIndexOf(pattern) === d;
451 empty: function() {
452 return this == '';
455 blank: function() {
456 return /^\s*$/.test(this);
460 if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
461 escapeHTML: function() {
462 return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
464 unescapeHTML: function() {
465 return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
469 String.prototype.gsub.prepareReplacement = function(replacement) {
470 if (typeof replacement == 'function') return replacement;
471 var template = new Template(replacement);
472 return function(match) { return template.evaluate(match) };
475 String.prototype.parseQuery = String.prototype.toQueryParams;
477 Object.extend(String.prototype.escapeHTML, {
478 div: document.createElement('div'),
479 text: document.createTextNode('')
482 with (String.prototype.escapeHTML) div.appendChild(text);
484 var Template = Class.create();
485 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
486 Template.prototype = {
487 initialize: function(template, pattern) {
488 this.template = template.toString();
489 this.pattern = pattern || Template.Pattern;
492 evaluate: function(object) {
493 return this.template.gsub(this.pattern, function(match) {
494 var before = match[1];
495 if (before == '\\') return match[2];
496 return before + String.interpret(object[match[3]]);
501 var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
503 var Enumerable = {
504 each: function(iterator) {
505 var index = 0;
506 try {
507 this._each(function(value) {
508 iterator(value, index++);
510 } catch (e) {
511 if (e != $break) throw e;
513 return this;
516 eachSlice: function(number, iterator) {
517 var index = -number, slices = [], array = this.toArray();
518 while ((index += number) < array.length)
519 slices.push(array.slice(index, index+number));
520 return slices.map(iterator);
523 all: function(iterator) {
524 var result = true;
525 this.each(function(value, index) {
526 result = result && !!(iterator || Prototype.K)(value, index);
527 if (!result) throw $break;
529 return result;
532 any: function(iterator) {
533 var result = false;
534 this.each(function(value, index) {
535 if (result = !!(iterator || Prototype.K)(value, index))
536 throw $break;
538 return result;
541 collect: function(iterator) {
542 var results = [];
543 this.each(function(value, index) {
544 results.push((iterator || Prototype.K)(value, index));
546 return results;
549 detect: function(iterator) {
550 var result;
551 this.each(function(value, index) {
552 if (iterator(value, index)) {
553 result = value;
554 throw $break;
557 return result;
560 findAll: function(iterator) {
561 var results = [];
562 this.each(function(value, index) {
563 if (iterator(value, index))
564 results.push(value);
566 return results;
569 grep: function(pattern, iterator) {
570 var results = [];
571 this.each(function(value, index) {
572 var stringValue = value.toString();
573 if (stringValue.match(pattern))
574 results.push((iterator || Prototype.K)(value, index));
576 return results;
579 include: function(object) {
580 var found = false;
581 this.each(function(value) {
582 if (value == object) {
583 found = true;
584 throw $break;
587 return found;
590 inGroupsOf: function(number, fillWith) {
591 fillWith = fillWith === undefined ? null : fillWith;
592 return this.eachSlice(number, function(slice) {
593 while(slice.length < number) slice.push(fillWith);
594 return slice;
598 inject: function(memo, iterator) {
599 this.each(function(value, index) {
600 memo = iterator(memo, value, index);
602 return memo;
605 invoke: function(method) {
606 var args = $A(arguments).slice(1);
607 return this.map(function(value) {
608 return value[method].apply(value, args);
612 max: function(iterator) {
613 var result;
614 this.each(function(value, index) {
615 value = (iterator || Prototype.K)(value, index);
616 if (result == undefined || value >= result)
617 result = value;
619 return result;
622 min: function(iterator) {
623 var result;
624 this.each(function(value, index) {
625 value = (iterator || Prototype.K)(value, index);
626 if (result == undefined || value < result)
627 result = value;
629 return result;
632 partition: function(iterator) {
633 var trues = [], falses = [];
634 this.each(function(value, index) {
635 ((iterator || Prototype.K)(value, index) ?
636 trues : falses).push(value);
638 return [trues, falses];
641 pluck: function(property) {
642 var results = [];
643 this.each(function(value, index) {
644 results.push(value[property]);
646 return results;
649 reject: function(iterator) {
650 var results = [];
651 this.each(function(value, index) {
652 if (!iterator(value, index))
653 results.push(value);
655 return results;
658 sortBy: function(iterator) {
659 return this.map(function(value, index) {
660 return {value: value, criteria: iterator(value, index)};
661 }).sort(function(left, right) {
662 var a = left.criteria, b = right.criteria;
663 return a < b ? -1 : a > b ? 1 : 0;
664 }).pluck('value');
667 toArray: function() {
668 return this.map();
671 zip: function() {
672 var iterator = Prototype.K, args = $A(arguments);
673 if (typeof args.last() == 'function')
674 iterator = args.pop();
676 var collections = [this].concat(args).map($A);
677 return this.map(function(value, index) {
678 return iterator(collections.pluck(index));
682 size: function() {
683 return this.toArray().length;
686 inspect: function() {
687 return '#<Enumerable:' + this.toArray().inspect() + '>';
691 Object.extend(Enumerable, {
692 map: Enumerable.collect,
693 find: Enumerable.detect,
694 select: Enumerable.findAll,
695 member: Enumerable.include,
696 entries: Enumerable.toArray
698 var $A = Array.from = function(iterable) {
699 if (!iterable) return [];
700 if (iterable.toArray) {
701 return iterable.toArray();
702 } else {
703 var results = [];
704 for (var i = 0, length = iterable.length; i < length; i++)
705 results.push(iterable[i]);
706 return results;
710 if (Prototype.Browser.WebKit) {
711 $A = Array.from = function(iterable) {
712 if (!iterable) return [];
713 if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
714 iterable.toArray) {
715 return iterable.toArray();
716 } else {
717 var results = [];
718 for (var i = 0, length = iterable.length; i < length; i++)
719 results.push(iterable[i]);
720 return results;
725 Object.extend(Array.prototype, Enumerable);
727 if (!Array.prototype._reverse)
728 Array.prototype._reverse = Array.prototype.reverse;
730 Object.extend(Array.prototype, {
731 _each: function(iterator) {
732 for (var i = 0, length = this.length; i < length; i++)
733 iterator(this[i]);
736 clear: function() {
737 this.length = 0;
738 return this;
741 first: function() {
742 return this[0];
745 last: function() {
746 return this[this.length - 1];
749 compact: function() {
750 return this.select(function(value) {
751 return value != null;
755 flatten: function() {
756 return this.inject([], function(array, value) {
757 return array.concat(value && value.constructor == Array ?
758 value.flatten() : [value]);
762 without: function() {
763 var values = $A(arguments);
764 return this.select(function(value) {
765 return !values.include(value);
769 indexOf: function(object) {
770 for (var i = 0, length = this.length; i < length; i++)
771 if (this[i] == object) return i;
772 return -1;
775 reverse: function(inline) {
776 return (inline !== false ? this : this.toArray())._reverse();
779 reduce: function() {
780 return this.length > 1 ? this : this[0];
783 uniq: function(sorted) {
784 return this.inject([], function(array, value, index) {
785 if (0 == index || (sorted ? array.last() != value : !array.include(value)))
786 array.push(value);
787 return array;
791 clone: function() {
792 return [].concat(this);
795 size: function() {
796 return this.length;
799 inspect: function() {
800 return '[' + this.map(Object.inspect).join(', ') + ']';
803 toJSON: function() {
804 var results = [];
805 this.each(function(object) {
806 var value = Object.toJSON(object);
807 if (value !== undefined) results.push(value);
809 return '[' + results.join(', ') + ']';
813 Array.prototype.toArray = Array.prototype.clone;
815 function $w(string) {
816 string = string.strip();
817 return string ? string.split(/\s+/) : [];
820 if (Prototype.Browser.Opera){
821 Array.prototype.concat = function() {
822 var array = [];
823 for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
824 for (var i = 0, length = arguments.length; i < length; i++) {
825 if (arguments[i].constructor == Array) {
826 for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
827 array.push(arguments[i][j]);
828 } else {
829 array.push(arguments[i]);
832 return array;
835 var Hash = function(object) {
836 if (object instanceof Hash) this.merge(object);
837 else Object.extend(this, object || {});
840 Object.extend(Hash, {
841 toQueryString: function(obj) {
842 var parts = [];
843 parts.add = arguments.callee.addPair;
845 this.prototype._each.call(obj, function(pair) {
846 if (!pair.key) return;
847 var value = pair.value;
849 if (value && typeof value == 'object') {
850 if (value.constructor == Array) value.each(function(value) {
851 parts.add(pair.key, value);
853 return;
855 parts.add(pair.key, value);
858 return parts.join('&');
861 toJSON: function(object) {
862 var results = [];
863 this.prototype._each.call(object, function(pair) {
864 var value = Object.toJSON(pair.value);
865 if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value);
867 return '{' + results.join(', ') + '}';
871 Hash.toQueryString.addPair = function(key, value, prefix) {
872 key = encodeURIComponent(key);
873 if (value === undefined) this.push(key);
874 else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value)));
877 Object.extend(Hash.prototype, Enumerable);
878 Object.extend(Hash.prototype, {
879 _each: function(iterator) {
880 for (var key in this) {
881 var value = this[key];
882 if (value && value == Hash.prototype[key]) continue;
884 var pair = [key, value];
885 pair.key = key;
886 pair.value = value;
887 iterator(pair);
891 keys: function() {
892 return this.pluck('key');
895 values: function() {
896 return this.pluck('value');
899 merge: function(hash) {
900 return $H(hash).inject(this, function(mergedHash, pair) {
901 mergedHash[pair.key] = pair.value;
902 return mergedHash;
906 remove: function() {
907 var result;
908 for(var i = 0, length = arguments.length; i < length; i++) {
909 var value = this[arguments[i]];
910 if (value !== undefined){
911 if (result === undefined) result = value;
912 else {
913 if (result.constructor != Array) result = [result];
914 result.push(value)
917 delete this[arguments[i]];
919 return result;
922 toQueryString: function() {
923 return Hash.toQueryString(this);
926 inspect: function() {
927 return '#<Hash:{' + this.map(function(pair) {
928 return pair.map(Object.inspect).join(': ');
929 }).join(', ') + '}>';
932 toJSON: function() {
933 return Hash.toJSON(this);
937 function $H(object) {
938 if (object instanceof Hash) return object;
939 return new Hash(object);
942 // Safari iterates over shadowed properties
943 if (function() {
944 var i = 0, Test = function(value) { this.key = value };
945 Test.prototype.key = 'foo';
946 for (var property in new Test('bar')) i++;
947 return i > 1;
948 }()) Hash.prototype._each = function(iterator) {
949 var cache = [];
950 for (var key in this) {
951 var value = this[key];
952 if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
953 cache.push(key);
954 var pair = [key, value];
955 pair.key = key;
956 pair.value = value;
957 iterator(pair);
960 ObjectRange = Class.create();
961 Object.extend(ObjectRange.prototype, Enumerable);
962 Object.extend(ObjectRange.prototype, {
963 initialize: function(start, end, exclusive) {
964 this.start = start;
965 this.end = end;
966 this.exclusive = exclusive;
969 _each: function(iterator) {
970 var value = this.start;
971 while (this.include(value)) {
972 iterator(value);
973 value = value.succ();
977 include: function(value) {
978 if (value < this.start)
979 return false;
980 if (this.exclusive)
981 return value < this.end;
982 return value <= this.end;
986 var $R = function(start, end, exclusive) {
987 return new ObjectRange(start, end, exclusive);
990 var Ajax = {
991 getTransport: function() {
992 return Try.these(
993 function() {return new XMLHttpRequest()},
994 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
995 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
996 ) || false;
999 activeRequestCount: 0
1002 Ajax.Responders = {
1003 responders: [],
1005 _each: function(iterator) {
1006 this.responders._each(iterator);
1009 register: function(responder) {
1010 if (!this.include(responder))
1011 this.responders.push(responder);
1014 unregister: function(responder) {
1015 this.responders = this.responders.without(responder);
1018 dispatch: function(callback, request, transport, json) {
1019 this.each(function(responder) {
1020 if (typeof responder[callback] == 'function') {
1021 try {
1022 responder[callback].apply(responder, [request, transport, json]);
1023 } catch (e) {}
1029 Object.extend(Ajax.Responders, Enumerable);
1031 Ajax.Responders.register({
1032 onCreate: function() {
1033 Ajax.activeRequestCount++;
1035 onComplete: function() {
1036 Ajax.activeRequestCount--;
1040 Ajax.Base = function() {};
1041 Ajax.Base.prototype = {
1042 setOptions: function(options) {
1043 this.options = {
1044 method: 'post',
1045 asynchronous: true,
1046 contentType: 'application/x-www-form-urlencoded',
1047 encoding: 'UTF-8',
1048 parameters: ''
1050 Object.extend(this.options, options || {});
1052 this.options.method = this.options.method.toLowerCase();
1053 if (typeof this.options.parameters == 'string')
1054 this.options.parameters = this.options.parameters.toQueryParams();
1058 Ajax.Request = Class.create();
1059 Ajax.Request.Events =
1060 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1062 Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
1063 _complete: false,
1065 initialize: function(url, options) {
1066 this.transport = Ajax.getTransport();
1067 this.setOptions(options);
1068 this.request(url);
1071 request: function(url) {
1072 this.url = url;
1073 this.method = this.options.method;
1074 var params = Object.clone(this.options.parameters);
1076 if (!['get', 'post'].include(this.method)) {
1077 // simulate other verbs over post
1078 params['_method'] = this.method;
1079 this.method = 'post';
1082 this.parameters = params;
1084 if (params = Hash.toQueryString(params)) {
1085 // when GET, append parameters to URL
1086 if (this.method == 'get')
1087 this.url += (this.url.include('?') ? '&' : '?') + params;
1088 else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
1089 params += '&_=';
1092 try {
1093 if (this.options.onCreate) this.options.onCreate(this.transport);
1094 Ajax.Responders.dispatch('onCreate', this, this.transport);
1096 this.transport.open(this.method.toUpperCase(), this.url,
1097 this.options.asynchronous);
1099 if (this.options.asynchronous)
1100 setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
1102 this.transport.onreadystatechange = this.onStateChange.bind(this);
1103 this.setRequestHeaders();
1105 this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1106 this.transport.send(this.body);
1108 /* Force Firefox to handle ready state 4 for synchronous requests */
1109 if (!this.options.asynchronous && this.transport.overrideMimeType)
1110 this.onStateChange();
1113 catch (e) {
1114 this.dispatchException(e);
1118 onStateChange: function() {
1119 var readyState = this.transport.readyState;
1120 if (readyState > 1 && !((readyState == 4) && this._complete))
1121 this.respondToReadyState(this.transport.readyState);
1124 setRequestHeaders: function() {
1125 var headers = {
1126 'X-Requested-With': 'XMLHttpRequest',
1127 'X-Prototype-Version': Prototype.Version,
1128 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1131 if (this.method == 'post') {
1132 headers['Content-type'] = this.options.contentType +
1133 (this.options.encoding ? '; charset=' + this.options.encoding : '');
1135 /* Force "Connection: close" for older Mozilla browsers to work
1136 * around a bug where XMLHttpRequest sends an incorrect
1137 * Content-length header. See Mozilla Bugzilla #246651.
1139 if (this.transport.overrideMimeType &&
1140 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1141 headers['Connection'] = 'close';
1144 // user-defined headers
1145 if (typeof this.options.requestHeaders == 'object') {
1146 var extras = this.options.requestHeaders;
1148 if (typeof extras.push == 'function')
1149 for (var i = 0, length = extras.length; i < length; i += 2)
1150 headers[extras[i]] = extras[i+1];
1151 else
1152 $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1155 for (var name in headers)
1156 this.transport.setRequestHeader(name, headers[name]);
1159 success: function() {
1160 return !this.transport.status
1161 || (this.transport.status >= 200 && this.transport.status < 300);
1164 respondToReadyState: function(readyState) {
1165 var state = Ajax.Request.Events[readyState];
1166 var transport = this.transport, json = this.evalJSON();
1168 if (state == 'Complete') {
1169 try {
1170 this._complete = true;
1171 (this.options['on' + this.transport.status]
1172 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1173 || Prototype.emptyFunction)(transport, json);
1174 } catch (e) {
1175 this.dispatchException(e);
1178 var contentType = this.getHeader('Content-type');
1179 if (contentType && contentType.strip().
1180 match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
1181 this.evalResponse();
1184 try {
1185 (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1186 Ajax.Responders.dispatch('on' + state, this, transport, json);
1187 } catch (e) {
1188 this.dispatchException(e);
1191 if (state == 'Complete') {
1192 // avoid memory leak in MSIE: clean up
1193 this.transport.onreadystatechange = Prototype.emptyFunction;
1197 getHeader: function(name) {
1198 try {
1199 return this.transport.getResponseHeader(name);
1200 } catch (e) { return null }
1203 evalJSON: function() {
1204 try {
1205 var json = this.getHeader('X-JSON');
1206 return json ? json.evalJSON() : null;
1207 } catch (e) { return null }
1210 evalResponse: function() {
1211 try {
1212 return eval((this.transport.responseText || '').unfilterJSON());
1213 } catch (e) {
1214 this.dispatchException(e);
1218 dispatchException: function(exception) {
1219 (this.options.onException || Prototype.emptyFunction)(this, exception);
1220 Ajax.Responders.dispatch('onException', this, exception);
1224 Ajax.Updater = Class.create();
1226 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
1227 initialize: function(container, url, options) {
1228 this.container = {
1229 success: (container.success || container),
1230 failure: (container.failure || (container.success ? null : container))
1233 this.transport = Ajax.getTransport();
1234 this.setOptions(options);
1236 var onComplete = this.options.onComplete || Prototype.emptyFunction;
1237 this.options.onComplete = (function(transport, param) {
1238 this.updateContent();
1239 onComplete(transport, param);
1240 }).bind(this);
1242 this.request(url);
1245 updateContent: function() {
1246 var receiver = this.container[this.success() ? 'success' : 'failure'];
1247 var response = this.transport.responseText;
1249 if (!this.options.evalScripts) response = response.stripScripts();
1251 if (receiver = $(receiver)) {
1252 if (this.options.insertion)
1253 new this.options.insertion(receiver, response);
1254 else
1255 receiver.update(response);
1258 if (this.success()) {
1259 if (this.onComplete)
1260 setTimeout(this.onComplete.bind(this), 10);
1265 Ajax.PeriodicalUpdater = Class.create();
1266 Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
1267 initialize: function(container, url, options) {
1268 this.setOptions(options);
1269 this.onComplete = this.options.onComplete;
1271 this.frequency = (this.options.frequency || 2);
1272 this.decay = (this.options.decay || 1);
1274 this.updater = {};
1275 this.container = container;
1276 this.url = url;
1278 this.start();
1281 start: function() {
1282 this.options.onComplete = this.updateComplete.bind(this);
1283 this.onTimerEvent();
1286 stop: function() {
1287 this.updater.options.onComplete = undefined;
1288 clearTimeout(this.timer);
1289 (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
1292 updateComplete: function(request) {
1293 if (this.options.decay) {
1294 this.decay = (request.responseText == this.lastText ?
1295 this.decay * this.options.decay : 1);
1297 this.lastText = request.responseText;
1299 this.timer = setTimeout(this.onTimerEvent.bind(this),
1300 this.decay * this.frequency * 1000);
1303 onTimerEvent: function() {
1304 this.updater = new Ajax.Updater(this.container, this.url, this.options);
1307 function $(element) {
1308 if (arguments.length > 1) {
1309 for (var i = 0, elements = [], length = arguments.length; i < length; i++)
1310 elements.push($(arguments[i]));
1311 return elements;
1313 if (typeof element == 'string')
1314 element = document.getElementById(element);
1315 return Element.extend(element);
1318 if (Prototype.BrowserFeatures.XPath) {
1319 document._getElementsByXPath = function(expression, parentElement) {
1320 var results = [];
1321 var query = document.evaluate(expression, $(parentElement) || document,
1322 null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
1323 for (var i = 0, length = query.snapshotLength; i < length; i++)
1324 results.push(query.snapshotItem(i));
1325 return results;
1328 document.getElementsByClassName = function(className, parentElement) {
1329 var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
1330 return document._getElementsByXPath(q, parentElement);
1333 } else document.getElementsByClassName = function(className, parentElement) {
1334 var children = ($(parentElement) || document.body).getElementsByTagName('*');
1335 var elements = [], child;
1336 for (var i = 0, length = children.length; i < length; i++) {
1337 child = children[i];
1338 if (Element.hasClassName(child, className))
1339 elements.push(Element.extend(child));
1341 return elements;
1344 /*--------------------------------------------------------------------------*/
1346 if (!window.Element) var Element = {};
1348 Element.extend = function(element) {
1349 var F = Prototype.BrowserFeatures;
1350 if (!element || !element.tagName || element.nodeType == 3 ||
1351 element._extended || F.SpecificElementExtensions || element == window)
1352 return element;
1354 var methods = {}, tagName = element.tagName, cache = Element.extend.cache,
1355 T = Element.Methods.ByTag;
1357 // extend methods for all tags (Safari doesn't need this)
1358 if (!F.ElementExtensions) {
1359 Object.extend(methods, Element.Methods),
1360 Object.extend(methods, Element.Methods.Simulated);
1363 // extend methods for specific tags
1364 if (T[tagName]) Object.extend(methods, T[tagName]);
1366 for (var property in methods) {
1367 var value = methods[property];
1368 if (typeof value == 'function' && !(property in element))
1369 element[property] = cache.findOrStore(value);
1372 element._extended = Prototype.emptyFunction;
1373 return element;
1376 Element.extend.cache = {
1377 findOrStore: function(value) {
1378 return this[value] = this[value] || function() {
1379 return value.apply(null, [this].concat($A(arguments)));
1384 Element.Methods = {
1385 visible: function(element) {
1386 return $(element).style.display != 'none';
1389 toggle: function(element) {
1390 element = $(element);
1391 Element[Element.visible(element) ? 'hide' : 'show'](element);
1392 return element;
1395 hide: function(element) {
1396 $(element).style.display = 'none';
1397 return element;
1400 show: function(element) {
1401 $(element).style.display = '';
1402 return element;
1405 remove: function(element) {
1406 element = $(element);
1407 element.parentNode.removeChild(element);
1408 return element;
1411 update: function(element, html) {
1412 html = typeof html == 'undefined' ? '' : html.toString();
1413 $(element).innerHTML = html.stripScripts();
1414 setTimeout(function() {html.evalScripts()}, 10);
1415 return element;
1418 replace: function(element, html) {
1419 element = $(element);
1420 html = typeof html == 'undefined' ? '' : html.toString();
1421 if (element.outerHTML) {
1422 element.outerHTML = html.stripScripts();
1423 } else {
1424 var range = element.ownerDocument.createRange();
1425 range.selectNodeContents(element);
1426 element.parentNode.replaceChild(
1427 range.createContextualFragment(html.stripScripts()), element);
1429 setTimeout(function() {html.evalScripts()}, 10);
1430 return element;
1433 inspect: function(element) {
1434 element = $(element);
1435 var result = '<' + element.tagName.toLowerCase();
1436 $H({'id': 'id', 'className': 'class'}).each(function(pair) {
1437 var property = pair.first(), attribute = pair.last();
1438 var value = (element[property] || '').toString();
1439 if (value) result += ' ' + attribute + '=' + value.inspect(true);
1441 return result + '>';
1444 recursivelyCollect: function(element, property) {
1445 element = $(element);
1446 var elements = [];
1447 while (element = element[property])
1448 if (element.nodeType == 1)
1449 elements.push(Element.extend(element));
1450 return elements;
1453 ancestors: function(element) {
1454 return $(element).recursivelyCollect('parentNode');
1457 descendants: function(element) {
1458 return $A($(element).getElementsByTagName('*')).each(Element.extend);
1461 firstDescendant: function(element) {
1462 element = $(element).firstChild;
1463 while (element && element.nodeType != 1) element = element.nextSibling;
1464 return $(element);
1467 immediateDescendants: function(element) {
1468 if (!(element = $(element).firstChild)) return [];
1469 while (element && element.nodeType != 1) element = element.nextSibling;
1470 if (element) return [element].concat($(element).nextSiblings());
1471 return [];
1474 previousSiblings: function(element) {
1475 return $(element).recursivelyCollect('previousSibling');
1478 nextSiblings: function(element) {
1479 return $(element).recursivelyCollect('nextSibling');
1482 siblings: function(element) {
1483 element = $(element);
1484 return element.previousSiblings().reverse().concat(element.nextSiblings());
1487 match: function(element, selector) {
1488 if (typeof selector == 'string')
1489 selector = new Selector(selector);
1490 return selector.match($(element));
1493 up: function(element, expression, index) {
1494 element = $(element);
1495 if (arguments.length == 1) return $(element.parentNode);
1496 var ancestors = element.ancestors();
1497 return expression ? Selector.findElement(ancestors, expression, index) :
1498 ancestors[index || 0];
1501 down: function(element, expression, index) {
1502 element = $(element);
1503 if (arguments.length == 1) return element.firstDescendant();
1504 var descendants = element.descendants();
1505 return expression ? Selector.findElement(descendants, expression, index) :
1506 descendants[index || 0];
1509 previous: function(element, expression, index) {
1510 element = $(element);
1511 if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1512 var previousSiblings = element.previousSiblings();
1513 return expression ? Selector.findElement(previousSiblings, expression, index) :
1514 previousSiblings[index || 0];
1517 next: function(element, expression, index) {
1518 element = $(element);
1519 if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1520 var nextSiblings = element.nextSiblings();
1521 return expression ? Selector.findElement(nextSiblings, expression, index) :
1522 nextSiblings[index || 0];
1525 getElementsBySelector: function() {
1526 var args = $A(arguments), element = $(args.shift());
1527 return Selector.findChildElements(element, args);
1530 getElementsByClassName: function(element, className) {
1531 return document.getElementsByClassName(className, element);
1534 readAttribute: function(element, name) {
1535 element = $(element);
1536 if (Prototype.Browser.IE) {
1537 if (!element.attributes) return null;
1538 var t = Element._attributeTranslations;
1539 if (t.values[name]) return t.values[name](element, name);
1540 if (t.names[name]) name = t.names[name];
1541 var attribute = element.attributes[name];
1542 return attribute ? attribute.nodeValue : null;
1544 return element.getAttribute(name);
1547 getHeight: function(element) {
1548 return $(element).getDimensions().height;
1551 getWidth: function(element) {
1552 return $(element).getDimensions().width;
1555 classNames: function(element) {
1556 return new Element.ClassNames(element);
1559 hasClassName: function(element, className) {
1560 if (!(element = $(element))) return;
1561 var elementClassName = element.className;
1562 if (elementClassName.length == 0) return false;
1563 if (elementClassName == className ||
1564 elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
1565 return true;
1566 return false;
1569 addClassName: function(element, className) {
1570 if (!(element = $(element))) return;
1571 Element.classNames(element).add(className);
1572 return element;
1575 removeClassName: function(element, className) {
1576 if (!(element = $(element))) return;
1577 Element.classNames(element).remove(className);
1578 return element;
1581 toggleClassName: function(element, className) {
1582 if (!(element = $(element))) return;
1583 Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
1584 return element;
1587 observe: function() {
1588 Event.observe.apply(Event, arguments);
1589 return $A(arguments).first();
1592 stopObserving: function() {
1593 Event.stopObserving.apply(Event, arguments);
1594 return $A(arguments).first();
1597 // removes whitespace-only text node children
1598 cleanWhitespace: function(element) {
1599 element = $(element);
1600 var node = element.firstChild;
1601 while (node) {
1602 var nextNode = node.nextSibling;
1603 if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1604 element.removeChild(node);
1605 node = nextNode;
1607 return element;
1610 empty: function(element) {
1611 return $(element).innerHTML.blank();
1614 descendantOf: function(element, ancestor) {
1615 element = $(element), ancestor = $(ancestor);
1616 while (element = element.parentNode)
1617 if (element == ancestor) return true;
1618 return false;
1621 scrollTo: function(element) {
1622 element = $(element);
1623 var pos = Position.cumulativeOffset(element);
1624 window.scrollTo(pos[0], pos[1]);
1625 return element;
1628 getStyle: function(element, style) {
1629 element = $(element);
1630 style = style == 'float' ? 'cssFloat' : style.camelize();
1631 var value = element.style[style];
1632 if (!value) {
1633 var css = document.defaultView.getComputedStyle(element, null);
1634 value = css ? css[style] : null;
1636 if (style == 'opacity') return value ? parseFloat(value) : 1.0;
1637 return value == 'auto' ? null : value;
1640 getOpacity: function(element) {
1641 return $(element).getStyle('opacity');
1644 setStyle: function(element, styles, camelized) {
1645 element = $(element);
1646 var elementStyle = element.style;
1648 for (var property in styles)
1649 if (property == 'opacity') element.setOpacity(styles[property])
1650 else
1651 elementStyle[(property == 'float' || property == 'cssFloat') ?
1652 (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1653 (camelized ? property : property.camelize())] = styles[property];
1655 return element;
1658 setOpacity: function(element, value) {
1659 element = $(element);
1660 element.style.opacity = (value == 1 || value === '') ? '' :
1661 (value < 0.00001) ? 0 : value;
1662 return element;
1665 getDimensions: function(element) {
1666 element = $(element);
1667 var display = $(element).getStyle('display');
1668 if (display != 'none' && display != null) // Safari bug
1669 return {width: element.offsetWidth, height: element.offsetHeight};
1671 // All *Width and *Height properties give 0 on elements with display none,
1672 // so enable the element temporarily
1673 var els = element.style;
1674 var originalVisibility = els.visibility;
1675 var originalPosition = els.position;
1676 var originalDisplay = els.display;
1677 els.visibility = 'hidden';
1678 els.position = 'absolute';
1679 els.display = 'block';
1680 var originalWidth = element.clientWidth;
1681 var originalHeight = element.clientHeight;
1682 els.display = originalDisplay;
1683 els.position = originalPosition;
1684 els.visibility = originalVisibility;
1685 return {width: originalWidth, height: originalHeight};
1688 makePositioned: function(element) {
1689 element = $(element);
1690 var pos = Element.getStyle(element, 'position');
1691 if (pos == 'static' || !pos) {
1692 element._madePositioned = true;
1693 element.style.position = 'relative';
1694 // Opera returns the offset relative to the positioning context, when an
1695 // element is position relative but top and left have not been defined
1696 if (window.opera) {
1697 element.style.top = 0;
1698 element.style.left = 0;
1701 return element;
1704 undoPositioned: function(element) {
1705 element = $(element);
1706 if (element._madePositioned) {
1707 element._madePositioned = undefined;
1708 element.style.position =
1709 element.style.top =
1710 element.style.left =
1711 element.style.bottom =
1712 element.style.right = '';
1714 return element;
1717 makeClipping: function(element) {
1718 element = $(element);
1719 if (element._overflow) return element;
1720 element._overflow = element.style.overflow || 'auto';
1721 if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
1722 element.style.overflow = 'hidden';
1723 return element;
1726 undoClipping: function(element) {
1727 element = $(element);
1728 if (!element._overflow) return element;
1729 element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
1730 element._overflow = null;
1731 return element;
1735 Object.extend(Element.Methods, {
1736 childOf: Element.Methods.descendantOf,
1737 childElements: Element.Methods.immediateDescendants
1740 if (Prototype.Browser.Opera) {
1741 Element.Methods._getStyle = Element.Methods.getStyle;
1742 Element.Methods.getStyle = function(element, style) {
1743 switch(style) {
1744 case 'left':
1745 case 'top':
1746 case 'right':
1747 case 'bottom':
1748 if (Element._getStyle(element, 'position') == 'static') return null;
1749 default: return Element._getStyle(element, style);
1753 else if (Prototype.Browser.IE) {
1754 Element.Methods.getStyle = function(element, style) {
1755 element = $(element);
1756 style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
1757 var value = element.style[style];
1758 if (!value && element.currentStyle) value = element.currentStyle[style];
1760 if (style == 'opacity') {
1761 if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
1762 if (value[1]) return parseFloat(value[1]) / 100;
1763 return 1.0;
1766 if (value == 'auto') {
1767 if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
1768 return element['offset'+style.capitalize()] + 'px';
1769 return null;
1771 return value;
1774 Element.Methods.setOpacity = function(element, value) {
1775 element = $(element);
1776 var filter = element.getStyle('filter'), style = element.style;
1777 if (value == 1 || value === '') {
1778 style.filter = filter.replace(/alpha\([^\)]*\)/gi,'');
1779 return element;
1780 } else if (value < 0.00001) value = 0;
1781 style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
1782 'alpha(opacity=' + (value * 100) + ')';
1783 return element;
1786 // IE is missing .innerHTML support for TABLE-related elements
1787 Element.Methods.update = function(element, html) {
1788 element = $(element);
1789 html = typeof html == 'undefined' ? '' : html.toString();
1790 var tagName = element.tagName.toUpperCase();
1791 if (['THEAD','TBODY','TR','TD'].include(tagName)) {
1792 var div = document.createElement('div');
1793 switch (tagName) {
1794 case 'THEAD':
1795 case 'TBODY':
1796 div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1797 depth = 2;
1798 break;
1799 case 'TR':
1800 div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1801 depth = 3;
1802 break;
1803 case 'TD':
1804 div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
1805 depth = 4;
1807 $A(element.childNodes).each(function(node) { element.removeChild(node) });
1808 depth.times(function() { div = div.firstChild });
1809 $A(div.childNodes).each(function(node) { element.appendChild(node) });
1810 } else {
1811 element.innerHTML = html.stripScripts();
1813 setTimeout(function() { html.evalScripts() }, 10);
1814 return element;
1817 else if (Prototype.Browser.Gecko) {
1818 Element.Methods.setOpacity = function(element, value) {
1819 element = $(element);
1820 element.style.opacity = (value == 1) ? 0.999999 :
1821 (value === '') ? '' : (value < 0.00001) ? 0 : value;
1822 return element;
1826 Element._attributeTranslations = {
1827 names: {
1828 colspan: "colSpan",
1829 rowspan: "rowSpan",
1830 valign: "vAlign",
1831 datetime: "dateTime",
1832 accesskey: "accessKey",
1833 tabindex: "tabIndex",
1834 enctype: "encType",
1835 maxlength: "maxLength",
1836 readonly: "readOnly",
1837 longdesc: "longDesc"
1839 values: {
1840 _getAttr: function(element, attribute) {
1841 return element.getAttribute(attribute, 2);
1843 _flag: function(element, attribute) {
1844 return $(element).hasAttribute(attribute) ? attribute : null;
1846 style: function(element) {
1847 return element.style.cssText.toLowerCase();
1849 title: function(element) {
1850 var node = element.getAttributeNode('title');
1851 return node.specified ? node.nodeValue : null;
1856 (function() {
1857 Object.extend(this, {
1858 href: this._getAttr,
1859 src: this._getAttr,
1860 type: this._getAttr,
1861 disabled: this._flag,
1862 checked: this._flag,
1863 readonly: this._flag,
1864 multiple: this._flag
1866 }).call(Element._attributeTranslations.values);
1868 Element.Methods.Simulated = {
1869 hasAttribute: function(element, attribute) {
1870 var t = Element._attributeTranslations, node;
1871 attribute = t.names[attribute] || attribute;
1872 node = $(element).getAttributeNode(attribute);
1873 return node && node.specified;
1877 Element.Methods.ByTag = {};
1879 Object.extend(Element, Element.Methods);
1881 if (!Prototype.BrowserFeatures.ElementExtensions &&
1882 document.createElement('div').__proto__) {
1883 window.HTMLElement = {};
1884 window.HTMLElement.prototype = document.createElement('div').__proto__;
1885 Prototype.BrowserFeatures.ElementExtensions = true;
1888 Element.hasAttribute = function(element, attribute) {
1889 if (element.hasAttribute) return element.hasAttribute(attribute);
1890 return Element.Methods.Simulated.hasAttribute(element, attribute);
1893 Element.addMethods = function(methods) {
1894 var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
1896 if (!methods) {
1897 Object.extend(Form, Form.Methods);
1898 Object.extend(Form.Element, Form.Element.Methods);
1899 Object.extend(Element.Methods.ByTag, {
1900 "FORM": Object.clone(Form.Methods),
1901 "INPUT": Object.clone(Form.Element.Methods),
1902 "SELECT": Object.clone(Form.Element.Methods),
1903 "TEXTAREA": Object.clone(Form.Element.Methods)
1907 if (arguments.length == 2) {
1908 var tagName = methods;
1909 methods = arguments[1];
1912 if (!tagName) Object.extend(Element.Methods, methods || {});
1913 else {
1914 if (tagName.constructor == Array) tagName.each(extend);
1915 else extend(tagName);
1918 function extend(tagName) {
1919 tagName = tagName.toUpperCase();
1920 if (!Element.Methods.ByTag[tagName])
1921 Element.Methods.ByTag[tagName] = {};
1922 Object.extend(Element.Methods.ByTag[tagName], methods);
1925 function copy(methods, destination, onlyIfAbsent) {
1926 onlyIfAbsent = onlyIfAbsent || false;
1927 var cache = Element.extend.cache;
1928 for (var property in methods) {
1929 var value = methods[property];
1930 if (!onlyIfAbsent || !(property in destination))
1931 destination[property] = cache.findOrStore(value);
1935 function findDOMClass(tagName) {
1936 var klass;
1937 var trans = {
1938 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
1939 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
1940 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
1941 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
1942 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
1943 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
1944 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
1945 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
1946 "FrameSet", "IFRAME": "IFrame"
1948 if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
1949 if (window[klass]) return window[klass];
1950 klass = 'HTML' + tagName + 'Element';
1951 if (window[klass]) return window[klass];
1952 klass = 'HTML' + tagName.capitalize() + 'Element';
1953 if (window[klass]) return window[klass];
1955 window[klass] = {};
1956 window[klass].prototype = document.createElement(tagName).__proto__;
1957 return window[klass];
1960 if (F.ElementExtensions) {
1961 copy(Element.Methods, HTMLElement.prototype);
1962 copy(Element.Methods.Simulated, HTMLElement.prototype, true);
1965 if (F.SpecificElementExtensions) {
1966 for (var tag in Element.Methods.ByTag) {
1967 var klass = findDOMClass(tag);
1968 if (typeof klass == "undefined") continue;
1969 copy(T[tag], klass.prototype);
1973 Object.extend(Element, Element.Methods);
1974 delete Element.ByTag;
1977 var Toggle = { display: Element.toggle };
1979 /*--------------------------------------------------------------------------*/
1981 Abstract.Insertion = function(adjacency) {
1982 this.adjacency = adjacency;
1985 Abstract.Insertion.prototype = {
1986 initialize: function(element, content) {
1987 this.element = $(element);
1988 this.content = content.stripScripts();
1990 if (this.adjacency && this.element.insertAdjacentHTML) {
1991 try {
1992 this.element.insertAdjacentHTML(this.adjacency, this.content);
1993 } catch (e) {
1994 var tagName = this.element.tagName.toUpperCase();
1995 if (['TBODY', 'TR'].include(tagName)) {
1996 this.insertContent(this.contentFromAnonymousTable());
1997 } else {
1998 throw e;
2001 } else {
2002 this.range = this.element.ownerDocument.createRange();
2003 if (this.initializeRange) this.initializeRange();
2004 this.insertContent([this.range.createContextualFragment(this.content)]);
2007 setTimeout(function() {content.evalScripts()}, 10);
2010 contentFromAnonymousTable: function() {
2011 var div = document.createElement('div');
2012 div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
2013 return $A(div.childNodes[0].childNodes[0].childNodes);
2017 var Insertion = new Object();
2019 Insertion.Before = Class.create();
2020 Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
2021 initializeRange: function() {
2022 this.range.setStartBefore(this.element);
2025 insertContent: function(fragments) {
2026 fragments.each((function(fragment) {
2027 this.element.parentNode.insertBefore(fragment, this.element);
2028 }).bind(this));
2032 Insertion.Top = Class.create();
2033 Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
2034 initializeRange: function() {
2035 this.range.selectNodeContents(this.element);
2036 this.range.collapse(true);
2039 insertContent: function(fragments) {
2040 fragments.reverse(false).each((function(fragment) {
2041 this.element.insertBefore(fragment, this.element.firstChild);
2042 }).bind(this));
2046 Insertion.Bottom = Class.create();
2047 Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
2048 initializeRange: function() {
2049 this.range.selectNodeContents(this.element);
2050 this.range.collapse(this.element);
2053 insertContent: function(fragments) {
2054 fragments.each((function(fragment) {
2055 this.element.appendChild(fragment);
2056 }).bind(this));
2060 Insertion.After = Class.create();
2061 Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
2062 initializeRange: function() {
2063 this.range.setStartAfter(this.element);
2066 insertContent: function(fragments) {
2067 fragments.each((function(fragment) {
2068 this.element.parentNode.insertBefore(fragment,
2069 this.element.nextSibling);
2070 }).bind(this));
2074 /*--------------------------------------------------------------------------*/
2076 Element.ClassNames = Class.create();
2077 Element.ClassNames.prototype = {
2078 initialize: function(element) {
2079 this.element = $(element);
2082 _each: function(iterator) {
2083 this.element.className.split(/\s+/).select(function(name) {
2084 return name.length > 0;
2085 })._each(iterator);
2088 set: function(className) {
2089 this.element.className = className;
2092 add: function(classNameToAdd) {
2093 if (this.include(classNameToAdd)) return;
2094 this.set($A(this).concat(classNameToAdd).join(' '));
2097 remove: function(classNameToRemove) {
2098 if (!this.include(classNameToRemove)) return;
2099 this.set($A(this).without(classNameToRemove).join(' '));
2102 toString: function() {
2103 return $A(this).join(' ');
2107 Object.extend(Element.ClassNames.prototype, Enumerable);
2108 // Portions of the Selector class are derived from Jack Slocum's DomQuery,
2109 // part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2110 // license. Please see http://www.yui-ext.com/ for more information.
2112 var Selector = Class.create();
2114 Selector.prototype = {
2115 initialize: function(expression) {
2116 this.expression = expression.strip();
2117 this.compileMatcher();
2120 compileMatcher: function() {
2121 // Selectors with namespaced attributes can't use the XPath version
2122 if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression))
2123 return this.compileXPathMatcher();
2125 var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2126 c = Selector.criteria, le, p, m;
2128 if (Selector._cache[e]) {
2129 this.matcher = Selector._cache[e]; return;
2131 this.matcher = ["this.matcher = function(root) {",
2132 "var r = root, h = Selector.handlers, c = false, n;"];
2134 while (e && le != e && (/\S/).test(e)) {
2135 le = e;
2136 for (var i in ps) {
2137 p = ps[i];
2138 if (m = e.match(p)) {
2139 this.matcher.push(typeof c[i] == 'function' ? c[i](m) :
2140 new Template(c[i]).evaluate(m));
2141 e = e.replace(m[0], '');
2142 break;
2147 this.matcher.push("return h.unique(n);\n}");
2148 eval(this.matcher.join('\n'));
2149 Selector._cache[this.expression] = this.matcher;
2152 compileXPathMatcher: function() {
2153 var e = this.expression, ps = Selector.patterns,
2154 x = Selector.xpath, le, m;
2156 if (Selector._cache[e]) {
2157 this.xpath = Selector._cache[e]; return;
2160 this.matcher = ['.//*'];
2161 while (e && le != e && (/\S/).test(e)) {
2162 le = e;
2163 for (var i in ps) {
2164 if (m = e.match(ps[i])) {
2165 this.matcher.push(typeof x[i] == 'function' ? x[i](m) :
2166 new Template(x[i]).evaluate(m));
2167 e = e.replace(m[0], '');
2168 break;
2173 this.xpath = this.matcher.join('');
2174 Selector._cache[this.expression] = this.xpath;
2177 findElements: function(root) {
2178 root = root || document;
2179 if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2180 return this.matcher(root);
2183 match: function(element) {
2184 return this.findElements(document).include(element);
2187 toString: function() {
2188 return this.expression;
2191 inspect: function() {
2192 return "#<Selector:" + this.expression.inspect() + ">";
2196 Object.extend(Selector, {
2197 _cache: {},
2199 xpath: {
2200 descendant: "//*",
2201 child: "/*",
2202 adjacent: "/following-sibling::*[1]",
2203 laterSibling: '/following-sibling::*',
2204 tagName: function(m) {
2205 if (m[1] == '*') return '';
2206 return "[local-name()='" + m[1].toLowerCase() +
2207 "' or local-name()='" + m[1].toUpperCase() + "']";
2209 className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
2210 id: "[@id='#{1}']",
2211 attrPresence: "[@#{1}]",
2212 attr: function(m) {
2213 m[3] = m[5] || m[6];
2214 return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
2216 pseudo: function(m) {
2217 var h = Selector.xpath.pseudos[m[1]];
2218 if (!h) return '';
2219 if (typeof h === 'function') return h(m);
2220 return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
2222 operators: {
2223 '=': "[@#{1}='#{3}']",
2224 '!=': "[@#{1}!='#{3}']",
2225 '^=': "[starts-with(@#{1}, '#{3}')]",
2226 '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
2227 '*=': "[contains(@#{1}, '#{3}')]",
2228 '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
2229 '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
2231 pseudos: {
2232 'first-child': '[not(preceding-sibling::*)]',
2233 'last-child': '[not(following-sibling::*)]',
2234 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2235 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2236 'checked': "[@checked]",
2237 'disabled': "[@disabled]",
2238 'enabled': "[not(@disabled)]",
2239 'not': function(m) {
2240 var e = m[6], p = Selector.patterns,
2241 x = Selector.xpath, le, m, v;
2243 var exclusion = [];
2244 while (e && le != e && (/\S/).test(e)) {
2245 le = e;
2246 for (var i in p) {
2247 if (m = e.match(p[i])) {
2248 v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m);
2249 exclusion.push("(" + v.substring(1, v.length - 1) + ")");
2250 e = e.replace(m[0], '');
2251 break;
2255 return "[not(" + exclusion.join(" and ") + ")]";
2257 'nth-child': function(m) {
2258 return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
2260 'nth-last-child': function(m) {
2261 return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
2263 'nth-of-type': function(m) {
2264 return Selector.xpath.pseudos.nth("position() ", m);
2266 'nth-last-of-type': function(m) {
2267 return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
2269 'first-of-type': function(m) {
2270 m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
2272 'last-of-type': function(m) {
2273 m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
2275 'only-of-type': function(m) {
2276 var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
2278 nth: function(fragment, m) {
2279 var mm, formula = m[6], predicate;
2280 if (formula == 'even') formula = '2n+0';
2281 if (formula == 'odd') formula = '2n+1';
2282 if (mm = formula.match(/^(\d+)$/)) // digit only
2283 return '[' + fragment + "= " + mm[1] + ']';
2284 if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2285 if (mm[1] == "-") mm[1] = -1;
2286 var a = mm[1] ? Number(mm[1]) : 1;
2287 var b = mm[2] ? Number(mm[2]) : 0;
2288 predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
2289 "((#{fragment} - #{b}) div #{a} >= 0)]";
2290 return new Template(predicate).evaluate({
2291 fragment: fragment, a: a, b: b });
2297 criteria: {
2298 tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2299 className: 'n = h.className(n, r, "#{1}", c); c = false;',
2300 id: 'n = h.id(n, r, "#{1}", c); c = false;',
2301 attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
2302 attr: function(m) {
2303 m[3] = (m[5] || m[6]);
2304 return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
2306 pseudo: function(m) {
2307 if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
2308 return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
2310 descendant: 'c = "descendant";',
2311 child: 'c = "child";',
2312 adjacent: 'c = "adjacent";',
2313 laterSibling: 'c = "laterSibling";'
2316 patterns: {
2317 // combinators must be listed first
2318 // (and descendant needs to be last combinator)
2319 laterSibling: /^\s*~\s*/,
2320 child: /^\s*>\s*/,
2321 adjacent: /^\s*\+\s*/,
2322 descendant: /^\s/,
2324 // selectors follow
2325 tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
2326 id: /^#([\w\-\*]+)(\b|$)/,
2327 className: /^\.([\w\-\*]+)(\b|$)/,
2328 pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/,
2329 attrPresence: /^\[([\w]+)\]/,
2330 attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/
2333 handlers: {
2334 // UTILITY FUNCTIONS
2335 // joins two collections
2336 concat: function(a, b) {
2337 for (var i = 0, node; node = b[i]; i++)
2338 a.push(node);
2339 return a;
2342 // marks an array of nodes for counting
2343 mark: function(nodes) {
2344 for (var i = 0, node; node = nodes[i]; i++)
2345 node._counted = true;
2346 return nodes;
2349 unmark: function(nodes) {
2350 for (var i = 0, node; node = nodes[i]; i++)
2351 node._counted = undefined;
2352 return nodes;
2355 // mark each child node with its position (for nth calls)
2356 // "ofType" flag indicates whether we're indexing for nth-of-type
2357 // rather than nth-child
2358 index: function(parentNode, reverse, ofType) {
2359 parentNode._counted = true;
2360 if (reverse) {
2361 for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
2362 node = nodes[i];
2363 if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2365 } else {
2366 for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
2367 if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
2371 // filters out duplicates and extends all nodes
2372 unique: function(nodes) {
2373 if (nodes.length == 0) return nodes;
2374 var results = [], n;
2375 for (var i = 0, l = nodes.length; i < l; i++)
2376 if (!(n = nodes[i])._counted) {
2377 n._counted = true;
2378 results.push(Element.extend(n));
2380 return Selector.handlers.unmark(results);
2383 // COMBINATOR FUNCTIONS
2384 descendant: function(nodes) {
2385 var h = Selector.handlers;
2386 for (var i = 0, results = [], node; node = nodes[i]; i++)
2387 h.concat(results, node.getElementsByTagName('*'));
2388 return results;
2391 child: function(nodes) {
2392 var h = Selector.handlers;
2393 for (var i = 0, results = [], node; node = nodes[i]; i++) {
2394 for (var j = 0, children = [], child; child = node.childNodes[j]; j++)
2395 if (child.nodeType == 1 && child.tagName != '!') results.push(child);
2397 return results;
2400 adjacent: function(nodes) {
2401 for (var i = 0, results = [], node; node = nodes[i]; i++) {
2402 var next = this.nextElementSibling(node);
2403 if (next) results.push(next);
2405 return results;
2408 laterSibling: function(nodes) {
2409 var h = Selector.handlers;
2410 for (var i = 0, results = [], node; node = nodes[i]; i++)
2411 h.concat(results, Element.nextSiblings(node));
2412 return results;
2415 nextElementSibling: function(node) {
2416 while (node = node.nextSibling)
2417 if (node.nodeType == 1) return node;
2418 return null;
2421 previousElementSibling: function(node) {
2422 while (node = node.previousSibling)
2423 if (node.nodeType == 1) return node;
2424 return null;
2427 // TOKEN FUNCTIONS
2428 tagName: function(nodes, root, tagName, combinator) {
2429 tagName = tagName.toUpperCase();
2430 var results = [], h = Selector.handlers;
2431 if (nodes) {
2432 if (combinator) {
2433 // fastlane for ordinary descendant combinators
2434 if (combinator == "descendant") {
2435 for (var i = 0, node; node = nodes[i]; i++)
2436 h.concat(results, node.getElementsByTagName(tagName));
2437 return results;
2438 } else nodes = this[combinator](nodes);
2439 if (tagName == "*") return nodes;
2441 for (var i = 0, node; node = nodes[i]; i++)
2442 if (node.tagName.toUpperCase() == tagName) results.push(node);
2443 return results;
2444 } else return root.getElementsByTagName(tagName);
2447 id: function(nodes, root, id, combinator) {
2448 var targetNode = $(id), h = Selector.handlers;
2449 if (!nodes && root == document) return targetNode ? [targetNode] : [];
2450 if (nodes) {
2451 if (combinator) {
2452 if (combinator == 'child') {
2453 for (var i = 0, node; node = nodes[i]; i++)
2454 if (targetNode.parentNode == node) return [targetNode];
2455 } else if (combinator == 'descendant') {
2456 for (var i = 0, node; node = nodes[i]; i++)
2457 if (Element.descendantOf(targetNode, node)) return [targetNode];
2458 } else if (combinator == 'adjacent') {
2459 for (var i = 0, node; node = nodes[i]; i++)
2460 if (Selector.handlers.previousElementSibling(targetNode) == node)
2461 return [targetNode];
2462 } else nodes = h[combinator](nodes);
2464 for (var i = 0, node; node = nodes[i]; i++)
2465 if (node == targetNode) return [targetNode];
2466 return [];
2468 return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
2471 className: function(nodes, root, className, combinator) {
2472 if (nodes && combinator) nodes = this[combinator](nodes);
2473 return Selector.handlers.byClassName(nodes, root, className);
2476 byClassName: function(nodes, root, className) {
2477 if (!nodes) nodes = Selector.handlers.descendant([root]);
2478 var needle = ' ' + className + ' ';
2479 for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
2480 nodeClassName = node.className;
2481 if (nodeClassName.length == 0) continue;
2482 if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
2483 results.push(node);
2485 return results;
2488 attrPresence: function(nodes, root, attr) {
2489 var results = [];
2490 for (var i = 0, node; node = nodes[i]; i++)
2491 if (Element.hasAttribute(node, attr)) results.push(node);
2492 return results;
2495 attr: function(nodes, root, attr, value, operator) {
2496 if (!nodes) nodes = root.getElementsByTagName("*");
2497 var handler = Selector.operators[operator], results = [];
2498 for (var i = 0, node; node = nodes[i]; i++) {
2499 var nodeValue = Element.readAttribute(node, attr);
2500 if (nodeValue === null) continue;
2501 if (handler(nodeValue, value)) results.push(node);
2503 return results;
2506 pseudo: function(nodes, name, value, root, combinator) {
2507 if (nodes && combinator) nodes = this[combinator](nodes);
2508 if (!nodes) nodes = root.getElementsByTagName("*");
2509 return Selector.pseudos[name](nodes, value, root);
2513 pseudos: {
2514 'first-child': function(nodes, value, root) {
2515 for (var i = 0, results = [], node; node = nodes[i]; i++) {
2516 if (Selector.handlers.previousElementSibling(node)) continue;
2517 results.push(node);
2519 return results;
2521 'last-child': function(nodes, value, root) {
2522 for (var i = 0, results = [], node; node = nodes[i]; i++) {
2523 if (Selector.handlers.nextElementSibling(node)) continue;
2524 results.push(node);
2526 return results;
2528 'only-child': function(nodes, value, root) {
2529 var h = Selector.handlers;
2530 for (var i = 0, results = [], node; node = nodes[i]; i++)
2531 if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
2532 results.push(node);
2533 return results;
2535 'nth-child': function(nodes, formula, root) {
2536 return Selector.pseudos.nth(nodes, formula, root);
2538 'nth-last-child': function(nodes, formula, root) {
2539 return Selector.pseudos.nth(nodes, formula, root, true);
2541 'nth-of-type': function(nodes, formula, root) {
2542 return Selector.pseudos.nth(nodes, formula, root, false, true);
2544 'nth-last-of-type': function(nodes, formula, root) {
2545 return Selector.pseudos.nth(nodes, formula, root, true, true);
2547 'first-of-type': function(nodes, formula, root) {
2548 return Selector.pseudos.nth(nodes, "1", root, false, true);
2550 'last-of-type': function(nodes, formula, root) {
2551 return Selector.pseudos.nth(nodes, "1", root, true, true);
2553 'only-of-type': function(nodes, formula, root) {
2554 var p = Selector.pseudos;
2555 return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
2558 // handles the an+b logic
2559 getIndices: function(a, b, total) {
2560 if (a == 0) return b > 0 ? [b] : [];
2561 return $R(1, total).inject([], function(memo, i) {
2562 if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
2563 return memo;
2567 // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
2568 nth: function(nodes, formula, root, reverse, ofType) {
2569 if (nodes.length == 0) return [];
2570 if (formula == 'even') formula = '2n+0';
2571 if (formula == 'odd') formula = '2n+1';
2572 var h = Selector.handlers, results = [], indexed = [], m;
2573 h.mark(nodes);
2574 for (var i = 0, node; node = nodes[i]; i++) {
2575 if (!node.parentNode._counted) {
2576 h.index(node.parentNode, reverse, ofType);
2577 indexed.push(node.parentNode);
2580 if (formula.match(/^\d+$/)) { // just a number
2581 formula = Number(formula);
2582 for (var i = 0, node; node = nodes[i]; i++)
2583 if (node.nodeIndex == formula) results.push(node);
2584 } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
2585 if (m[1] == "-") m[1] = -1;
2586 var a = m[1] ? Number(m[1]) : 1;
2587 var b = m[2] ? Number(m[2]) : 0;
2588 var indices = Selector.pseudos.getIndices(a, b, nodes.length);
2589 for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
2590 for (var j = 0; j < l; j++)
2591 if (node.nodeIndex == indices[j]) results.push(node);
2594 h.unmark(nodes);
2595 h.unmark(indexed);
2596 return results;
2599 'empty': function(nodes, value, root) {
2600 for (var i = 0, results = [], node; node = nodes[i]; i++) {
2601 // IE treats comments as element nodes
2602 if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
2603 results.push(node);
2605 return results;
2608 'not': function(nodes, selector, root) {
2609 var h = Selector.handlers, selectorType, m;
2610 var exclusions = new Selector(selector).findElements(root);
2611 h.mark(exclusions);
2612 for (var i = 0, results = [], node; node = nodes[i]; i++)
2613 if (!node._counted) results.push(node);
2614 h.unmark(exclusions);
2615 return results;
2618 'enabled': function(nodes, value, root) {
2619 for (var i = 0, results = [], node; node = nodes[i]; i++)
2620 if (!node.disabled) results.push(node);
2621 return results;
2624 'disabled': function(nodes, value, root) {
2625 for (var i = 0, results = [], node; node = nodes[i]; i++)
2626 if (node.disabled) results.push(node);
2627 return results;
2630 'checked': function(nodes, value, root) {
2631 for (var i = 0, results = [], node; node = nodes[i]; i++)
2632 if (node.checked) results.push(node);
2633 return results;
2637 operators: {
2638 '=': function(nv, v) { return nv == v; },
2639 '!=': function(nv, v) { return nv != v; },
2640 '^=': function(nv, v) { return nv.startsWith(v); },
2641 '$=': function(nv, v) { return nv.endsWith(v); },
2642 '*=': function(nv, v) { return nv.include(v); },
2643 '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
2644 '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
2647 matchElements: function(elements, expression) {
2648 var matches = new Selector(expression).findElements(), h = Selector.handlers;
2649 h.mark(matches);
2650 for (var i = 0, results = [], element; element = elements[i]; i++)
2651 if (element._counted) results.push(element);
2652 h.unmark(matches);
2653 return results;
2656 findElement: function(elements, expression, index) {
2657 if (typeof expression == 'number') {
2658 index = expression; expression = false;
2660 return Selector.matchElements(elements, expression || '*')[index || 0];
2663 findChildElements: function(element, expressions) {
2664 var exprs = expressions.join(','), expressions = [];
2665 exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
2666 expressions.push(m[1].strip());
2668 var results = [], h = Selector.handlers;
2669 for (var i = 0, l = expressions.length, selector; i < l; i++) {
2670 selector = new Selector(expressions[i].strip());
2671 h.concat(results, selector.findElements(element));
2673 return (l > 1) ? h.unique(results) : results;
2677 function $$() {
2678 return Selector.findChildElements(document, $A(arguments));
2680 var Form = {
2681 reset: function(form) {
2682 $(form).reset();
2683 return form;
2686 serializeElements: function(elements, getHash) {
2687 var data = elements.inject({}, function(result, element) {
2688 if (!element.disabled && element.name) {
2689 var key = element.name, value = $(element).getValue();
2690 if (value != null) {
2691 if (key in result) {
2692 if (result[key].constructor != Array) result[key] = [result[key]];
2693 result[key].push(value);
2695 else result[key] = value;
2698 return result;
2701 return getHash ? data : Hash.toQueryString(data);
2705 Form.Methods = {
2706 serialize: function(form, getHash) {
2707 return Form.serializeElements(Form.getElements(form), getHash);
2710 getElements: function(form) {
2711 return $A($(form).getElementsByTagName('*')).inject([],
2712 function(elements, child) {
2713 if (Form.Element.Serializers[child.tagName.toLowerCase()])
2714 elements.push(Element.extend(child));
2715 return elements;
2720 getInputs: function(form, typeName, name) {
2721 form = $(form);
2722 var inputs = form.getElementsByTagName('input');
2724 if (!typeName && !name) return $A(inputs).map(Element.extend);
2726 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
2727 var input = inputs[i];
2728 if ((typeName && input.type != typeName) || (name && input.name != name))
2729 continue;
2730 matchingInputs.push(Element.extend(input));
2733 return matchingInputs;
2736 disable: function(form) {
2737 form = $(form);
2738 Form.getElements(form).invoke('disable');
2739 return form;
2742 enable: function(form) {
2743 form = $(form);
2744 Form.getElements(form).invoke('enable');
2745 return form;
2748 findFirstElement: function(form) {
2749 return $(form).getElements().find(function(element) {
2750 return element.type != 'hidden' && !element.disabled &&
2751 ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
2755 focusFirstElement: function(form) {
2756 form = $(form);
2757 form.findFirstElement().activate();
2758 return form;
2761 request: function(form, options) {
2762 form = $(form), options = Object.clone(options || {});
2764 var params = options.parameters;
2765 options.parameters = form.serialize(true);
2767 if (params) {
2768 if (typeof params == 'string') params = params.toQueryParams();
2769 Object.extend(options.parameters, params);
2772 if (form.hasAttribute('method') && !options.method)
2773 options.method = form.method;
2775 return new Ajax.Request(form.readAttribute('action'), options);
2779 /*--------------------------------------------------------------------------*/
2781 Form.Element = {
2782 focus: function(element) {
2783 $(element).focus();
2784 return element;
2787 select: function(element) {
2788 $(element).select();
2789 return element;
2793 Form.Element.Methods = {
2794 serialize: function(element) {
2795 element = $(element);
2796 if (!element.disabled && element.name) {
2797 var value = element.getValue();
2798 if (value != undefined) {
2799 var pair = {};
2800 pair[element.name] = value;
2801 return Hash.toQueryString(pair);
2804 return '';
2807 getValue: function(element) {
2808 element = $(element);
2809 var method = element.tagName.toLowerCase();
2810 return Form.Element.Serializers[method](element);
2813 clear: function(element) {
2814 $(element).value = '';
2815 return element;
2818 present: function(element) {
2819 return $(element).value != '';
2822 activate: function(element) {
2823 element = $(element);
2824 try {
2825 element.focus();
2826 if (element.select && (element.tagName.toLowerCase() != 'input' ||
2827 !['button', 'reset', 'submit'].include(element.type)))
2828 element.select();
2829 } catch (e) {}
2830 return element;
2833 disable: function(element) {
2834 element = $(element);
2835 element.blur();
2836 element.disabled = true;
2837 return element;
2840 enable: function(element) {
2841 element = $(element);
2842 element.disabled = false;
2843 return element;
2847 /*--------------------------------------------------------------------------*/
2849 var Field = Form.Element;
2850 var $F = Form.Element.Methods.getValue;
2852 /*--------------------------------------------------------------------------*/
2854 Form.Element.Serializers = {
2855 input: function(element) {
2856 switch (element.type.toLowerCase()) {
2857 case 'checkbox':
2858 case 'radio':
2859 return Form.Element.Serializers.inputSelector(element);
2860 default:
2861 return Form.Element.Serializers.textarea(element);
2865 inputSelector: function(element) {
2866 return element.checked ? element.value : null;
2869 textarea: function(element) {
2870 return element.value;
2873 select: function(element) {
2874 return this[element.type == 'select-one' ?
2875 'selectOne' : 'selectMany'](element);
2878 selectOne: function(element) {
2879 var index = element.selectedIndex;
2880 return index >= 0 ? this.optionValue(element.options[index]) : null;
2883 selectMany: function(element) {
2884 var values, length = element.length;
2885 if (!length) return null;
2887 for (var i = 0, values = []; i < length; i++) {
2888 var opt = element.options[i];
2889 if (opt.selected) values.push(this.optionValue(opt));
2891 return values;
2894 optionValue: function(opt) {
2895 // extend element because hasAttribute may not be native
2896 return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
2900 /*--------------------------------------------------------------------------*/
2902 Abstract.TimedObserver = function() {}
2903 Abstract.TimedObserver.prototype = {
2904 initialize: function(element, frequency, callback) {
2905 this.frequency = frequency;
2906 this.element = $(element);
2907 this.callback = callback;
2909 this.lastValue = this.getValue();
2910 this.registerCallback();
2913 registerCallback: function() {
2914 setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
2917 onTimerEvent: function() {
2918 var value = this.getValue();
2919 var changed = ('string' == typeof this.lastValue && 'string' == typeof value
2920 ? this.lastValue != value : String(this.lastValue) != String(value));
2921 if (changed) {
2922 this.callback(this.element, value);
2923 this.lastValue = value;
2928 Form.Element.Observer = Class.create();
2929 Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2930 getValue: function() {
2931 return Form.Element.getValue(this.element);
2935 Form.Observer = Class.create();
2936 Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
2937 getValue: function() {
2938 return Form.serialize(this.element);
2942 /*--------------------------------------------------------------------------*/
2944 Abstract.EventObserver = function() {}
2945 Abstract.EventObserver.prototype = {
2946 initialize: function(element, callback) {
2947 this.element = $(element);
2948 this.callback = callback;
2950 this.lastValue = this.getValue();
2951 if (this.element.tagName.toLowerCase() == 'form')
2952 this.registerFormCallbacks();
2953 else
2954 this.registerCallback(this.element);
2957 onElementEvent: function() {
2958 var value = this.getValue();
2959 if (this.lastValue != value) {
2960 this.callback(this.element, value);
2961 this.lastValue = value;
2965 registerFormCallbacks: function() {
2966 Form.getElements(this.element).each(this.registerCallback.bind(this));
2969 registerCallback: function(element) {
2970 if (element.type) {
2971 switch (element.type.toLowerCase()) {
2972 case 'checkbox':
2973 case 'radio':
2974 Event.observe(element, 'click', this.onElementEvent.bind(this));
2975 break;
2976 default:
2977 Event.observe(element, 'change', this.onElementEvent.bind(this));
2978 break;
2984 Form.Element.EventObserver = Class.create();
2985 Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2986 getValue: function() {
2987 return Form.Element.getValue(this.element);
2991 Form.EventObserver = Class.create();
2992 Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
2993 getValue: function() {
2994 return Form.serialize(this.element);
2997 if (!window.Event) {
2998 var Event = new Object();
3001 Object.extend(Event, {
3002 KEY_BACKSPACE: 8,
3003 KEY_TAB: 9,
3004 KEY_RETURN: 13,
3005 KEY_ESC: 27,
3006 KEY_LEFT: 37,
3007 KEY_UP: 38,
3008 KEY_RIGHT: 39,
3009 KEY_DOWN: 40,
3010 KEY_DELETE: 46,
3011 KEY_HOME: 36,
3012 KEY_END: 35,
3013 KEY_PAGEUP: 33,
3014 KEY_PAGEDOWN: 34,
3016 element: function(event) {
3017 return $(event.target || event.srcElement);
3020 isLeftClick: function(event) {
3021 return (((event.which) && (event.which == 1)) ||
3022 ((event.button) && (event.button == 1)));
3025 pointerX: function(event) {
3026 return event.pageX || (event.clientX +
3027 (document.documentElement.scrollLeft || document.body.scrollLeft));
3030 pointerY: function(event) {
3031 return event.pageY || (event.clientY +
3032 (document.documentElement.scrollTop || document.body.scrollTop));
3035 stop: function(event) {
3036 if (event.preventDefault) {
3037 event.preventDefault();
3038 event.stopPropagation();
3039 } else {
3040 event.returnValue = false;
3041 event.cancelBubble = true;
3045 // find the first node with the given tagName, starting from the
3046 // node the event was triggered on; traverses the DOM upwards
3047 findElement: function(event, tagName) {
3048 var element = Event.element(event);
3049 while (element.parentNode && (!element.tagName ||
3050 (element.tagName.toUpperCase() != tagName.toUpperCase())))
3051 element = element.parentNode;
3052 return element;
3055 observers: false,
3057 _observeAndCache: function(element, name, observer, useCapture) {
3058 if (!this.observers) this.observers = [];
3059 if (element.addEventListener) {
3060 this.observers.push([element, name, observer, useCapture]);
3061 element.addEventListener(name, observer, useCapture);
3062 } else if (element.attachEvent) {
3063 this.observers.push([element, name, observer, useCapture]);
3064 element.attachEvent('on' + name, observer);
3068 unloadCache: function() {
3069 if (!Event.observers) return;
3070 for (var i = 0, length = Event.observers.length; i < length; i++) {
3071 Event.stopObserving.apply(this, Event.observers[i]);
3072 Event.observers[i][0] = null;
3074 Event.observers = false;
3077 observe: function(element, name, observer, useCapture) {
3078 element = $(element);
3079 useCapture = useCapture || false;
3081 if (name == 'keypress' &&
3082 (Prototype.Browser.WebKit || element.attachEvent))
3083 name = 'keydown';
3085 Event._observeAndCache(element, name, observer, useCapture);
3088 stopObserving: function(element, name, observer, useCapture) {
3089 element = $(element);
3090 useCapture = useCapture || false;
3092 if (name == 'keypress' &&
3093 (Prototype.Browser.WebKit || element.attachEvent))
3094 name = 'keydown';
3096 if (element.removeEventListener) {
3097 element.removeEventListener(name, observer, useCapture);
3098 } else if (element.detachEvent) {
3099 try {
3100 element.detachEvent('on' + name, observer);
3101 } catch (e) {}
3106 /* prevent memory leaks in IE */
3107 if (Prototype.Browser.IE)
3108 Event.observe(window, 'unload', Event.unloadCache, false);
3109 var Position = {
3110 // set to true if needed, warning: firefox performance problems
3111 // NOT neeeded for page scrolling, only if draggable contained in
3112 // scrollable elements
3113 includeScrollOffsets: false,
3115 // must be called before calling withinIncludingScrolloffset, every time the
3116 // page is scrolled
3117 prepare: function() {
3118 this.deltaX = window.pageXOffset
3119 || document.documentElement.scrollLeft
3120 || document.body.scrollLeft
3121 || 0;
3122 this.deltaY = window.pageYOffset
3123 || document.documentElement.scrollTop
3124 || document.body.scrollTop
3125 || 0;
3128 realOffset: function(element) {
3129 var valueT = 0, valueL = 0;
3130 do {
3131 valueT += element.scrollTop || 0;
3132 valueL += element.scrollLeft || 0;
3133 element = element.parentNode;
3134 } while (element);
3135 return [valueL, valueT];
3138 cumulativeOffset: function(element) {
3139 var valueT = 0, valueL = 0;
3140 do {
3141 valueT += element.offsetTop || 0;
3142 valueL += element.offsetLeft || 0;
3143 element = element.offsetParent;
3144 } while (element);
3145 return [valueL, valueT];
3148 positionedOffset: function(element) {
3149 var valueT = 0, valueL = 0;
3150 do {
3151 valueT += element.offsetTop || 0;
3152 valueL += element.offsetLeft || 0;
3153 element = element.offsetParent;
3154 if (element) {
3155 if(element.tagName=='BODY') break;
3156 var p = Element.getStyle(element, 'position');
3157 if (p == 'relative' || p == 'absolute') break;
3159 } while (element);
3160 return [valueL, valueT];
3163 offsetParent: function(element) {
3164 if (element.offsetParent) return element.offsetParent;
3165 if (element == document.body) return element;
3167 while ((element = element.parentNode) && element != document.body)
3168 if (Element.getStyle(element, 'position') != 'static')
3169 return element;
3171 return document.body;
3174 // caches x/y coordinate pair to use with overlap
3175 within: function(element, x, y) {
3176 if (this.includeScrollOffsets)
3177 return this.withinIncludingScrolloffsets(element, x, y);
3178 this.xcomp = x;
3179 this.ycomp = y;
3180 this.offset = this.cumulativeOffset(element);
3182 return (y >= this.offset[1] &&
3183 y < this.offset[1] + element.offsetHeight &&
3184 x >= this.offset[0] &&
3185 x < this.offset[0] + element.offsetWidth);
3188 withinIncludingScrolloffsets: function(element, x, y) {
3189 var offsetcache = this.realOffset(element);
3191 this.xcomp = x + offsetcache[0] - this.deltaX;
3192 this.ycomp = y + offsetcache[1] - this.deltaY;
3193 this.offset = this.cumulativeOffset(element);
3195 return (this.ycomp >= this.offset[1] &&
3196 this.ycomp < this.offset[1] + element.offsetHeight &&
3197 this.xcomp >= this.offset[0] &&
3198 this.xcomp < this.offset[0] + element.offsetWidth);
3201 // within must be called directly before
3202 overlap: function(mode, element) {
3203 if (!mode) return 0;
3204 if (mode == 'vertical')
3205 return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
3206 element.offsetHeight;
3207 if (mode == 'horizontal')
3208 return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
3209 element.offsetWidth;
3212 page: function(forElement) {
3213 var valueT = 0, valueL = 0;
3215 var element = forElement;
3216 do {
3217 valueT += element.offsetTop || 0;
3218 valueL += element.offsetLeft || 0;
3220 // Safari fix
3221 if (element.offsetParent == document.body)
3222 if (Element.getStyle(element,'position')=='absolute') break;
3224 } while (element = element.offsetParent);
3226 element = forElement;
3227 do {
3228 if (!window.opera || element.tagName=='BODY') {
3229 valueT -= element.scrollTop || 0;
3230 valueL -= element.scrollLeft || 0;
3232 } while (element = element.parentNode);
3234 return [valueL, valueT];
3237 clone: function(source, target) {
3238 var options = Object.extend({
3239 setLeft: true,
3240 setTop: true,
3241 setWidth: true,
3242 setHeight: true,
3243 offsetTop: 0,
3244 offsetLeft: 0
3245 }, arguments[2] || {})
3247 // find page position of source
3248 source = $(source);
3249 var p = Position.page(source);
3251 // find coordinate system to use
3252 target = $(target);
3253 var delta = [0, 0];
3254 var parent = null;
3255 // delta [0,0] will do fine with position: fixed elements,
3256 // position:absolute needs offsetParent deltas
3257 if (Element.getStyle(target,'position') == 'absolute') {
3258 parent = Position.offsetParent(target);
3259 delta = Position.page(parent);
3262 // correct by body offsets (fixes Safari)
3263 if (parent == document.body) {
3264 delta[0] -= document.body.offsetLeft;
3265 delta[1] -= document.body.offsetTop;
3268 // set position
3269 if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
3270 if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
3271 if(options.setWidth) target.style.width = source.offsetWidth + 'px';
3272 if(options.setHeight) target.style.height = source.offsetHeight + 'px';
3275 absolutize: function(element) {
3276 element = $(element);
3277 if (element.style.position == 'absolute') return;
3278 Position.prepare();
3280 var offsets = Position.positionedOffset(element);
3281 var top = offsets[1];
3282 var left = offsets[0];
3283 var width = element.clientWidth;
3284 var height = element.clientHeight;
3286 element._originalLeft = left - parseFloat(element.style.left || 0);
3287 element._originalTop = top - parseFloat(element.style.top || 0);
3288 element._originalWidth = element.style.width;
3289 element._originalHeight = element.style.height;
3291 element.style.position = 'absolute';
3292 element.style.top = top + 'px';
3293 element.style.left = left + 'px';
3294 element.style.width = width + 'px';
3295 element.style.height = height + 'px';
3298 relativize: function(element) {
3299 element = $(element);
3300 if (element.style.position == 'relative') return;
3301 Position.prepare();
3303 element.style.position = 'relative';
3304 var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
3305 var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
3307 element.style.top = top + 'px';
3308 element.style.left = left + 'px';
3309 element.style.height = element._originalHeight;
3310 element.style.width = element._originalWidth;
3314 // Safari returns margins on body which is incorrect if the child is absolutely
3315 // positioned. For performance reasons, redefine Position.cumulativeOffset for
3316 // KHTML/WebKit only.
3317 if (Prototype.Browser.WebKit) {
3318 Position.cumulativeOffset = function(element) {
3319 var valueT = 0, valueL = 0;
3320 do {
3321 valueT += element.offsetTop || 0;
3322 valueL += element.offsetLeft || 0;
3323 if (element.offsetParent == document.body)
3324 if (Element.getStyle(element, 'position') == 'absolute') break;
3326 element = element.offsetParent;
3327 } while (element);
3329 return [valueL, valueT];
3333 Element.addMethods();
3336 </value>
3337 </data>
3338 </root>