1 <?xml version=
"1.0" encoding=
"utf-8"?>
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">
7 <xsd:choice maxOccurs=
"unbounded">
8 <xsd:element name=
"metadata">
11 <xsd:element name=
"value" type=
"xsd:string" minOccurs=
"0" />
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" />
19 <xsd:element name=
"assembly">
21 <xsd:attribute name=
"alias" type=
"xsd:string" />
22 <xsd:attribute name=
"name" type=
"xsd:string" />
25 <xsd:element name=
"data">
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" />
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" />
37 <xsd:element name=
"resheader">
40 <xsd:element name=
"value" type=
"xsd:string" minOccurs=
"0" msdata:
Ordinal=
"1" />
42 <xsd:attribute name=
"name" type=
"xsd:string" use=
"required" />
49 <resheader name=
"resmimetype">
50 <value>text/microsoft-resx
</value>
52 <resheader name=
"version">
55 <resheader name=
"reader">
56 <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=
2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
58 <resheader name=
"writer">
59 <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=
2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
61 <data name=
"jsfunctions" xml:
space=
"preserve">
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 /*--------------------------------------------------------------------------*/
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
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 }
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];
113 Object.extend(Object, {
114 inspect: function(object) {
116 if (object === undefined) return 'undefined';
117 if (object === null) return 'null';
118 return object.inspect ? object.inspect() : object.toString();
120 if (e instanceof RangeError) return '...';
125 toJSON: function(object) {
126 var type = typeof object;
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;
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) {
147 for (var property in object)
152 values: function(object) {
154 for (var property in object)
155 values.push(object[property]);
159 clone: function(object) {
160 return Object.extend({}, object);
164 Function.prototype.bind = function() {
165 var __method = this, args = $A(arguments), object = args.shift();
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);
187 times: function(iterator) {
188 $R(
0, this, true).each(iterator);
192 toPaddedString: function(length, radix) {
193 var string = this.toString(radix ||
10);
194 return '
0'.times(length - string.length) + string;
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) + '"';
215 for (var i =
0, length = arguments.length; i < length; i++) {
216 var lambda = arguments[i];
218 returnValue = lambda();
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);
244 if (!this.timer) return;
245 clearInterval(this.timer);
249 onTimerEvent: function() {
250 if (!this.currentlyExecuting) {
252 this.currentlyExecuting = true;
255 this.currentlyExecuting = false;
260 Object.extend(String, {
261 interpret: function(value) {
262 return value == null ? '' : String(value);
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);
285 result += source, source = '';
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);
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;
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);
362 if (hash[key].constructor != Array) hash[key] = [hash[key]];
363 hash[key].push(value);
365 else hash[key] = value;
371 toArray: function() {
372 return this.split('');
376 return this.slice(
0, this.length -
1) +
377 String.fromCharCode(this.charCodeAt(this.length -
1) +
1);
380 times: function(count) {
382 for (var i =
0; i < count; i++) result += this;
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)
394 for (var i =
1; i < len; i++)
395 camelized += parts[i].charAt(
0).toUpperCase() + parts[i].substring(
1);
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, '\\\'') +
"'";
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();
432 if (!sanitize || (/^(
"(\\.|[^"\\\n\r])*?
"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json)))
433 return eval('(' + json + ')');
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;
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,'&').replace(/</g,'<').replace(/>/g,'>');
464 unescapeHTML: function() {
465 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/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');
504 each: function(iterator) {
507 this._each(function(value) {
508 iterator(value, index++);
511 if (e != $break) throw e;
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) {
525 this.each(function(value, index) {
526 result = result && !!(iterator || Prototype.K)(value, index);
527 if (!result) throw $break;
532 any: function(iterator) {
534 this.each(function(value, index) {
535 if (result = !!(iterator || Prototype.K)(value, index))
541 collect: function(iterator) {
543 this.each(function(value, index) {
544 results.push((iterator || Prototype.K)(value, index));
549 detect: function(iterator) {
551 this.each(function(value, index) {
552 if (iterator(value, index)) {
560 findAll: function(iterator) {
562 this.each(function(value, index) {
563 if (iterator(value, index))
569 grep: function(pattern, iterator) {
571 this.each(function(value, index) {
572 var stringValue = value.toString();
573 if (stringValue.match(pattern))
574 results.push((iterator || Prototype.K)(value, index));
579 include: function(object) {
581 this.each(function(value) {
582 if (value == object) {
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);
598 inject: function(memo, iterator) {
599 this.each(function(value, index) {
600 memo = iterator(memo, value, index);
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) {
614 this.each(function(value, index) {
615 value = (iterator || Prototype.K)(value, index);
616 if (result == undefined || value >= result)
622 min: function(iterator) {
624 this.each(function(value, index) {
625 value = (iterator || Prototype.K)(value, index);
626 if (result == undefined || value < 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) {
643 this.each(function(value, index) {
644 results.push(value[property]);
649 reject: function(iterator) {
651 this.each(function(value, index) {
652 if (!iterator(value, index))
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;
667 toArray: 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));
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();
704 for (var i = 0, length = iterable.length; i < length; i++)
705 results.push(iterable[i]);
710 if (Prototype.Browser.WebKit) {
711 $A = Array.from = function(iterable) {
712 if (!iterable) return [];
713 if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
715 return iterable.toArray();
718 for (var i = 0, length = iterable.length; i < length; i++)
719 results.push(iterable[i]);
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++)
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;
775 reverse: function(inline) {
776 return (inline !== false ? this : this.toArray())._reverse();
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)))
792 return [].concat(this);
799 inspect: function() {
800 return '[' + this.map(Object.inspect).join(', ') + ']';
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() {
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]);
829 array.push(arguments[i]);
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) {
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);
855 parts.add(pair.key, value);
858 return parts.join('&');
861 toJSON: function(object) {
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];
892 return this.pluck('key');
896 return this.pluck('value');
899 merge: function(hash) {
900 return $H(hash).inject(this, function(mergedHash, pair) {
901 mergedHash[pair.key] = pair.value;
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;
913 if (result.constructor != Array) result = [result];
917 delete this[arguments[i]];
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(', ') + '}>';
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
944 var i = 0, Test = function(value) { this.key = value };
945 Test.prototype.key = 'foo';
946 for (var property in new Test('bar')) i++;
948 }()) Hash.prototype._each = function(iterator) {
950 for (var key in this) {
951 var value = this[key];
952 if ((value && value == Hash.prototype[key]) || cache.include(key)) continue;
954 var pair = [key, value];
960 ObjectRange = Class.create();
961 Object.extend(ObjectRange.prototype, Enumerable);
962 Object.extend(ObjectRange.prototype, {
963 initialize: function(start, end, exclusive) {
966 this.exclusive = exclusive;
969 _each: function(iterator) {
970 var value = this.start;
971 while (this.include(value)) {
973 value = value.succ();
977 include: function(value) {
978 if (value < this.start)
981 return value < this.end;
982 return value <= this.end;
986 var $R = function(start, end, exclusive) {
987 return new ObjectRange(start, end, exclusive);
991 getTransport: function() {
993 function() {return new XMLHttpRequest()},
994 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
995 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
999 activeRequestCount: 0
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') {
1022 responder[callback].apply(responder, [request, transport, json]);
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) {
1046 contentType: 'application/x-www-form-urlencoded',
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(), {
1065 initialize: function(url, options) {
1066 this.transport = Ajax.getTransport();
1067 this.setOptions(options);
1071 request: function(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))
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();
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() {
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];
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') {
1170 this._complete = true;
1171 (this.options['on' + this.transport.status]
1172 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1173 || Prototype.emptyFunction)(transport, json);
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();
1185 (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
1186 Ajax.Responders.dispatch('on' + state, this, transport, json);
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) {
1199 return this.transport.getResponseHeader(name);
1200 } catch (e) { return null }
1203 evalJSON: function() {
1205 var json = this.getHeader('X-JSON');
1206 return json ? json.evalJSON() : null;
1207 } catch (e) { return null }
1210 evalResponse: function() {
1212 return eval((this.transport.responseText || '').unfilterJSON());
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) {
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);
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);
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);
1275 this.container = container;
1282 this.options.onComplete = this.updateComplete.bind(this);
1283 this.onTimerEvent();
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]));
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) {
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));
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));
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)
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;
1376 Element.extend.cache = {
1377 findOrStore: function(value) {
1378 return this[value] = this[value] || function() {
1379 return value.apply(null, [this].concat($A(arguments)));
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);
1395 hide: function(element) {
1396 $(element).style.display = 'none';
1400 show: function(element) {
1401 $(element).style.display = '';
1405 remove: function(element) {
1406 element = $(element);
1407 element.parentNode.removeChild(element);
1411 update: function(element, html) {
1412 html = typeof html == 'undefined' ? '' : html.toString();
1413 $(element).innerHTML = html.stripScripts();
1414 setTimeout(function() {html.evalScripts()}, 10);
1418 replace: function(element, html) {
1419 element = $(element);
1420 html = typeof html == 'undefined' ? '' : html.toString();
1421 if (element.outerHTML) {
1422 element.outerHTML = html.stripScripts();
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);
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);
1447 while (element = element[property])
1448 if (element.nodeType == 1)
1449 elements.push(Element.extend(element));
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;
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());
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|$)
")))
1569 addClassName: function(element, className) {
1570 if (!(element = $(element))) return;
1571 Element.classNames(element).add(className);
1575 removeClassName: function(element, className) {
1576 if (!(element = $(element))) return;
1577 Element.classNames(element).remove(className);
1581 toggleClassName: function(element, className) {
1582 if (!(element = $(element))) return;
1583 Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
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;
1602 var nextNode = node.nextSibling;
1603 if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
1604 element.removeChild(node);
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;
1621 scrollTo: function(element) {
1622 element = $(element);
1623 var pos = Position.cumulativeOffset(element);
1624 window.scrollTo(pos[0], pos[1]);
1628 getStyle: function(element, style) {
1629 element = $(element);
1630 style = style == 'float' ? 'cssFloat' : style.camelize();
1631 var value = element.style[style];
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])
1651 elementStyle[(property == 'float' || property == 'cssFloat') ?
1652 (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') :
1653 (camelized ? property : property.camelize())] = styles[property];
1658 setOpacity: function(element, value) {
1659 element = $(element);
1660 element.style.opacity = (value == 1 || value === '') ? '' :
1661 (value < 0.00001) ? 0 : value;
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
1697 element.style.top = 0;
1698 element.style.left = 0;
1704 undoPositioned: function(element) {
1705 element = $(element);
1706 if (element._madePositioned) {
1707 element._madePositioned = undefined;
1708 element.style.position =
1710 element.style.left =
1711 element.style.bottom =
1712 element.style.right = '';
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';
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;
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) {
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;
1766 if (value == 'auto') {
1767 if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
1768 return element['offset'+style.capitalize()] + 'px';
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,'');
1780 } else if (value < 0.00001) value = 0;
1781 style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') +
1782 'alpha(opacity=' + (value * 100) + ')';
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');
1796 div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
1800 div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
1804 div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
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) });
1811 element.innerHTML = html.stripScripts();
1813 setTimeout(function() { html.evalScripts() }, 10);
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;
1826 Element._attributeTranslations = {
1831 datetime: "dateTime
",
1832 accesskey: "accessKey
",
1833 tabindex: "tabIndex
",
1835 maxlength: "maxLength
",
1836 readonly: "readOnly
",
1837 longdesc: "longDesc
"
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;
1857 Object.extend(this, {
1858 href: 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;
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 || {});
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) {
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];
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) {
1992 this.element.insertAdjacentHTML(this.adjacency, this.content);
1994 var tagName = this.element.tagName.toUpperCase();
1995 if (['TBODY', 'TR'].include(tagName)) {
1996 this.insertContent(this.contentFromAnonymousTable());
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);
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);
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);
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);
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;
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)) {
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], '');
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)) {
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], '');
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, {
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} ')]
",
2211 attrPresence: "[@#{
1}]
",
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]];
2219 if (typeof h === 'function') return h(m);
2220 return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
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}-')]
"
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;
2244 while (e && le != e && (/\S/).test(e)) {
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], '');
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 });
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;',
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
";'
2317 // combinators must be listed first
2318 // (and descendant needs to be last combinator)
2319 laterSibling: /^\s*~\s*/,
2321 adjacent: /^\s*\+\s*/,
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|([^'
"][^\]]*?)))?\]/
2334 // UTILITY FUNCTIONS
2335 // joins two collections
2336 concat: function(a, b) {
2337 for (var i = 0, node; node = b[i]; i++)
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;
2349 unmark: function(nodes) {
2350 for (var i = 0, node; node = nodes[i]; i++)
2351 node._counted = undefined;
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;
2361 for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
2363 if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++;
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) {
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('*'));
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);
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);
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));
2415 nextElementSibling: function(node) {
2416 while (node = node.nextSibling)
2417 if (node.nodeType == 1) return node;
2421 previousElementSibling: function(node) {
2422 while (node = node.previousSibling)
2423 if (node.nodeType == 1) return node;
2428 tagName: function(nodes, root, tagName, combinator) {
2429 tagName = tagName.toUpperCase();
2430 var results = [], h = Selector.handlers;
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));
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);
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] : [];
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];
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))
2488 attrPresence: function(nodes, root, attr) {
2490 for (var i = 0, node; node = nodes[i]; i++)
2491 if (Element.hasAttribute(node, attr)) results.push(node);
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);
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);
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;
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;
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))
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);
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;
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);
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;
2608 'not': function(nodes, selector, root) {
2609 var h = Selector.handlers, selectorType, m;
2610 var exclusions = new Selector(selector).findElements(root);
2612 for (var i = 0, results = [], node; node = nodes[i]; i++)
2613 if (!node._counted) results.push(node);
2614 h.unmark(exclusions);
2618 'enabled': function(nodes, value, root) {
2619 for (var i = 0, results = [], node; node = nodes[i]; i++)
2620 if (!node.disabled) results.push(node);
2624 'disabled': function(nodes, value, root) {
2625 for (var i = 0, results = [], node; node = nodes[i]; i++)
2626 if (node.disabled) results.push(node);
2630 'checked': function(nodes, value, root) {
2631 for (var i = 0, results = [], node; node = nodes[i]; i++)
2632 if (node.checked) results.push(node);
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;
2650 for (var i = 0, results = [], element; element = elements[i]; i++)
2651 if (element._counted) results.push(element);
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;
2678 return Selector.findChildElements(document, $A(arguments));
2681 reset: function(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;
2701 return getHash ? data : Hash.toQueryString(data);
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));
2720 getInputs: function(form, typeName, name) {
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))
2730 matchingInputs.push(Element.extend(input));
2733 return matchingInputs;
2736 disable: function(form) {
2738 Form.getElements(form).invoke('disable');
2742 enable: function(form) {
2744 Form.getElements(form).invoke('enable');
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) {
2757 form.findFirstElement().activate();
2761 request: function(form, options) {
2762 form = $(form), options = Object.clone(options || {});
2764 var params = options.parameters;
2765 options.parameters = form.serialize(true);
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 /*--------------------------------------------------------------------------*/
2782 focus: function(element) {
2787 select: function(element) {
2788 $(element).select();
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) {
2800 pair[element.name] = value;
2801 return Hash.toQueryString(pair);
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 = '';
2818 present: function(element) {
2819 return $(element).value != '';
2822 activate: function(element) {
2823 element = $(element);
2826 if (element.select && (element.tagName.toLowerCase() != 'input' ||
2827 !['button', 'reset', 'submit'].include(element.type)))
2833 disable: function(element) {
2834 element = $(element);
2836 element.disabled = true;
2840 enable: function(element) {
2841 element = $(element);
2842 element.disabled = false;
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()) {
2859 return Form.Element.Serializers.inputSelector(element);
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));
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));
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();
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) {
2971 switch (element.type.toLowerCase()) {
2974 Event.observe(element, 'click', this.onElementEvent.bind(this));
2977 Event.observe(element, 'change', this.onElementEvent.bind(this));
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, {
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();
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;
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))
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))
3096 if (element.removeEventListener) {
3097 element.removeEventListener(name, observer, useCapture);
3098 } else if (element.detachEvent) {
3100 element.detachEvent('on' + name, observer);
3106 /* prevent memory leaks in IE */
3107 if (Prototype.Browser.IE)
3108 Event.observe(window, 'unload', Event.unloadCache, false);
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
3117 prepare: function() {
3118 this.deltaX = window.pageXOffset
3119 || document.documentElement.scrollLeft
3120 || document.body.scrollLeft
3122 this.deltaY = window.pageYOffset
3123 || document.documentElement.scrollTop
3124 || document.body.scrollTop
3128 realOffset: function(element) {
3129 var valueT = 0, valueL = 0;
3131 valueT += element.scrollTop || 0;
3132 valueL += element.scrollLeft || 0;
3133 element = element.parentNode;
3135 return [valueL, valueT];
3138 cumulativeOffset: function(element) {
3139 var valueT = 0, valueL = 0;
3141 valueT += element.offsetTop || 0;
3142 valueL += element.offsetLeft || 0;
3143 element = element.offsetParent;
3145 return [valueL, valueT];
3148 positionedOffset: function(element) {
3149 var valueT = 0, valueL = 0;
3151 valueT += element.offsetTop || 0;
3152 valueL += element.offsetLeft || 0;
3153 element = element.offsetParent;
3155 if(element.tagName=='BODY') break;
3156 var p = Element.getStyle(element, 'position');
3157 if (p == 'relative' || p == 'absolute') break;
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')
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);
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;
3217 valueT += element.offsetTop || 0;
3218 valueL += element.offsetLeft || 0;
3221 if (element.offsetParent == document.body)
3222 if (Element.getStyle(element,'position')=='absolute') break;
3224 } while (element = element.offsetParent);
3226 element = forElement;
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({
3245 }, arguments[2] || {})
3247 // find page position of source
3249 var p = Position.page(source);
3251 // find coordinate system to use
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;
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;
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;
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;
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;
3329 return [valueL, valueT];
3333 Element.addMethods();