1 /* Prototype JavaScript framework, version 1.7.3
2 * (c) 2005-2010 Sam Stephenson
4 * Prototype is freely distributable under the terms of an MIT-style license.
5 * For details, see the Prototype web site: http://www.prototypejs.org/
7 *--------------------------------------------------------------------------*/
14 var ua
= navigator
.userAgent
;
15 var isOpera
= Object
.prototype.toString
.call(window
.opera
) == '[object Opera]';
17 IE
: !!window
.attachEvent
&& !isOpera
,
19 WebKit
: ua
.indexOf('AppleWebKit/') > -1,
20 Gecko
: ua
.indexOf('Gecko') > -1 && ua
.indexOf('KHTML') === -1,
21 MobileSafari
: /Apple.*Mobile/.test(ua
)
26 XPath
: !!document
.evaluate
,
28 SelectorsAPI
: !!document
.querySelector
,
30 ElementExtensions
: (function() {
31 var constructor = window
.Element
|| window
.HTMLElement
;
32 return !!(constructor && constructor.prototype);
34 SpecificElementExtensions
: (function() {
35 if (typeof window
.HTMLDivElement
!== 'undefined')
38 var div
= document
.createElement('div'),
39 form
= document
.createElement('form'),
42 if (div
['__proto__'] && (div
['__proto__'] !== form
['__proto__'])) {
52 ScriptFragment
: '<script[^>]*>([\\S\\s]*?)<\/script\\s*>',
53 JSONFilter
: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
55 emptyFunction: function() { },
57 K: function(x
) { return x
}
60 if (Prototype
.Browser
.MobileSafari
)
61 Prototype
.BrowserFeatures
.SpecificElementExtensions
= false;
62 /* Based on Alex Arnell's inheritance implementation. */
64 var Class
= (function() {
66 var IS_DONTENUM_BUGGY
= (function(){
67 for (var p
in { toString
: 1 }) {
68 if (p
=== 'toString') return false;
73 function subclass() {};
75 var parent
= null, properties
= $A(arguments
);
76 if (Object
.isFunction(properties
[0]))
77 parent
= properties
.shift();
80 this.initialize
.apply(this, arguments
);
83 Object
.extend(klass
, Class
.Methods
);
84 klass
.superclass
= parent
;
85 klass
.subclasses
= [];
88 subclass
.prototype = parent
.prototype;
89 klass
.prototype = new subclass
;
90 parent
.subclasses
.push(klass
);
93 for (var i
= 0, length
= properties
.length
; i
< length
; i
++)
94 klass
.addMethods(properties
[i
]);
96 if (!klass
.prototype.initialize
)
97 klass
.prototype.initialize
= Prototype
.emptyFunction
;
99 klass
.prototype.constructor = klass
;
103 function addMethods(source
) {
104 var ancestor
= this.superclass
&& this.superclass
.prototype,
105 properties
= Object
.keys(source
);
107 if (IS_DONTENUM_BUGGY
) {
108 if (source
.toString
!= Object
.prototype.toString
)
109 properties
.push("toString");
110 if (source
.valueOf
!= Object
.prototype.valueOf
)
111 properties
.push("valueOf");
114 for (var i
= 0, length
= properties
.length
; i
< length
; i
++) {
115 var property
= properties
[i
], value
= source
[property
];
116 if (ancestor
&& Object
.isFunction(value
) &&
117 value
.argumentNames()[0] == "$super") {
119 value
= (function(m
) {
120 return function() { return ancestor
[m
].apply(this, arguments
); };
121 })(property
).wrap(method
);
123 value
.valueOf
= (function(method
) {
124 return function() { return method
.valueOf
.call(method
); };
127 value
.toString
= (function(method
) {
128 return function() { return method
.toString
.call(method
); };
131 this.prototype[property
] = value
;
140 addMethods
: addMethods
146 var _toString
= Object
.prototype.toString
,
147 _hasOwnProperty
= Object
.prototype.hasOwnProperty
,
149 UNDEFINED_TYPE
= 'Undefined',
150 BOOLEAN_TYPE
= 'Boolean',
151 NUMBER_TYPE
= 'Number',
152 STRING_TYPE
= 'String',
153 OBJECT_TYPE
= 'Object',
154 FUNCTION_CLASS
= '[object Function]',
155 BOOLEAN_CLASS
= '[object Boolean]',
156 NUMBER_CLASS
= '[object Number]',
157 STRING_CLASS
= '[object String]',
158 ARRAY_CLASS
= '[object Array]',
159 DATE_CLASS
= '[object Date]',
160 NATIVE_JSON_STRINGIFY_SUPPORT
= window
.JSON
&&
161 typeof JSON
.stringify
=== 'function' &&
162 JSON
.stringify(0) === '0' &&
163 typeof JSON
.stringify(Prototype
.K
) === 'undefined';
167 var DONT_ENUMS
= ['toString', 'toLocaleString', 'valueOf',
168 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
170 var IS_DONTENUM_BUGGY
= (function(){
171 for (var p
in { toString
: 1 }) {
172 if (p
=== 'toString') return false;
179 case null: return NULL_TYPE
;
180 case (void 0): return UNDEFINED_TYPE
;
184 case 'boolean': return BOOLEAN_TYPE
;
185 case 'number': return NUMBER_TYPE
;
186 case 'string': return STRING_TYPE
;
191 function extend(destination
, source
) {
192 for (var property
in source
)
193 destination
[property
] = source
[property
];
197 function inspect(object
) {
199 if (isUndefined(object
)) return 'undefined';
200 if (object
=== null) return 'null';
201 return object
.inspect
? object
.inspect() : String(object
);
203 if (e
instanceof RangeError
) return '...';
208 function toJSON(value
) {
209 return Str('', { '': value
}, []);
212 function Str(key
, holder
, stack
) {
213 var value
= holder
[key
];
214 if (Type(value
) === OBJECT_TYPE
&& typeof value
.toJSON
=== 'function') {
215 value
= value
.toJSON(key
);
218 var _class
= _toString
.call(value
);
224 value
= value
.valueOf();
228 case null: return 'null';
229 case true: return 'true';
230 case false: return 'false';
233 var type
= typeof value
;
236 return value
.inspect(true);
238 return isFinite(value
) ? String(value
) : 'null';
241 for (var i
= 0, length
= stack
.length
; i
< length
; i
++) {
242 if (stack
[i
] === value
) {
243 throw new TypeError("Cyclic reference to '" + value
+ "' in object");
249 if (_class
=== ARRAY_CLASS
) {
250 for (var i
= 0, length
= value
.length
; i
< length
; i
++) {
251 var str
= Str(i
, value
, stack
);
252 partial
.push(typeof str
=== 'undefined' ? 'null' : str
);
254 partial
= '[' + partial
.join(',') + ']';
256 var keys
= Object
.keys(value
);
257 for (var i
= 0, length
= keys
.length
; i
< length
; i
++) {
258 var key
= keys
[i
], str
= Str(key
, value
, stack
);
259 if (typeof str
!== "undefined") {
260 partial
.push(key
.inspect(true)+ ':' + str
);
263 partial
= '{' + partial
.join(',') + '}';
270 function stringify(object
) {
271 return JSON
.stringify(object
);
274 function toQueryString(object
) {
275 return $H(object
).toQueryString();
278 function toHTML(object
) {
279 return object
&& object
.toHTML
? object
.toHTML() : String
.interpret(object
);
282 function keys(object
) {
283 if (Type(object
) !== OBJECT_TYPE
) { throw new TypeError(); }
285 for (var property
in object
) {
286 if (_hasOwnProperty
.call(object
, property
))
287 results
.push(property
);
290 if (IS_DONTENUM_BUGGY
) {
291 for (var i
= 0; property
= DONT_ENUMS
[i
]; i
++) {
292 if (_hasOwnProperty
.call(object
, property
))
293 results
.push(property
);
300 function values(object
) {
302 for (var property
in object
)
303 results
.push(object
[property
]);
307 function clone(object
) {
308 return extend({ }, object
);
311 function isElement(object
) {
312 return !!(object
&& object
.nodeType
== 1);
315 function isArray(object
) {
316 return _toString
.call(object
) === ARRAY_CLASS
;
319 var hasNativeIsArray
= (typeof Array
.isArray
== 'function')
320 && Array
.isArray([]) && !Array
.isArray({});
322 if (hasNativeIsArray
) {
323 isArray
= Array
.isArray
;
326 function isHash(object
) {
327 return object
instanceof Hash
;
330 function isFunction(object
) {
331 return _toString
.call(object
) === FUNCTION_CLASS
;
334 function isString(object
) {
335 return _toString
.call(object
) === STRING_CLASS
;
338 function isNumber(object
) {
339 return _toString
.call(object
) === NUMBER_CLASS
;
342 function isDate(object
) {
343 return _toString
.call(object
) === DATE_CLASS
;
346 function isUndefined(object
) {
347 return typeof object
=== "undefined";
353 toJSON
: NATIVE_JSON_STRINGIFY_SUPPORT
? stringify
: toJSON
,
354 toQueryString
: toQueryString
,
356 keys
: Object
.keys
|| keys
,
359 isElement
: isElement
,
362 isFunction
: isFunction
,
366 isUndefined
: isUndefined
369 Object
.extend(Function
.prototype, (function() {
370 var slice
= Array
.prototype.slice
;
372 function update(array
, args
) {
373 var arrayLength
= array
.length
, length
= args
.length
;
374 while (length
--) array
[arrayLength
+ length
] = args
[length
];
378 function merge(array
, args
) {
379 array
= slice
.call(array
, 0);
380 return update(array
, args
);
383 function argumentNames() {
384 var names
= this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
385 .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
386 .replace(/\s+/g, '').split(',');
387 return names
.length
== 1 && !names
[0] ? [] : names
;
391 function bind(context
) {
392 if (arguments
.length
< 2 && Object
.isUndefined(arguments
[0]))
395 if (!Object
.isFunction(this))
396 throw new TypeError("The object is not callable.");
398 var nop = function() {};
399 var __method
= this, args
= slice
.call(arguments
, 1);
401 var bound = function() {
402 var a
= merge(args
, arguments
);
403 var c
= this instanceof bound
? this : context
;
404 return __method
.apply(c
, a
);
407 nop
.prototype = this.prototype;
408 bound
.prototype = new nop();
413 function bindAsEventListener(context
) {
414 var __method
= this, args
= slice
.call(arguments
, 1);
415 return function(event
) {
416 var a
= update([event
|| window
.event
], args
);
417 return __method
.apply(context
, a
);
422 if (!arguments
.length
) return this;
423 var __method
= this, args
= slice
.call(arguments
, 0);
425 var a
= merge(args
, arguments
);
426 return __method
.apply(this, a
);
430 function delay(timeout
) {
431 var __method
= this, args
= slice
.call(arguments
, 1);
432 timeout
= timeout
* 1000;
433 return window
.setTimeout(function() {
434 return __method
.apply(__method
, args
);
439 var args
= update([0.01], arguments
);
440 return this.delay
.apply(this, args
);
443 function wrap(wrapper
) {
446 var a
= update([__method
.bind(this)], arguments
);
447 return wrapper
.apply(this, a
);
451 function methodize() {
452 if (this._methodized
) return this._methodized
;
454 return this._methodized = function() {
455 var a
= update([this], arguments
);
456 return __method
.apply(null, a
);
461 argumentNames
: argumentNames
,
462 bindAsEventListener
: bindAsEventListener
,
470 if (!Function
.prototype.bind
)
471 extensions
.bind
= bind
;
481 function toISOString() {
482 return this.getUTCFullYear() + '-' +
483 (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
484 this.getUTCDate().toPaddedString(2) + 'T' +
485 this.getUTCHours().toPaddedString(2) + ':' +
486 this.getUTCMinutes().toPaddedString(2) + ':' +
487 this.getUTCSeconds().toPaddedString(2) + 'Z';
492 return this.toISOString();
495 if (!proto
.toISOString
) proto
.toISOString
= toISOString
;
496 if (!proto
.toJSON
) proto
.toJSON
= toJSON
;
501 RegExp
.prototype.match
= RegExp
.prototype.test
;
503 RegExp
.escape = function(str
) {
504 return String(str
).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
506 var PeriodicalExecuter
= Class
.create({
507 initialize: function(callback
, frequency
) {
508 this.callback
= callback
;
509 this.frequency
= frequency
;
510 this.currentlyExecuting
= false;
512 this.registerCallback();
515 registerCallback: function() {
516 this.timer
= setInterval(this.onTimerEvent
.bind(this), this.frequency
* 1000);
519 execute: function() {
524 if (!this.timer
) return;
525 clearInterval(this.timer
);
529 onTimerEvent: function() {
530 if (!this.currentlyExecuting
) {
532 this.currentlyExecuting
= true;
534 this.currentlyExecuting
= false;
536 this.currentlyExecuting
= false;
542 Object
.extend(String
, {
543 interpret: function(value
) {
544 return value
== null ? '' : String(value
);
556 Object
.extend(String
.prototype, (function() {
557 var NATIVE_JSON_PARSE_SUPPORT
= window
.JSON
&&
558 typeof JSON
.parse
=== 'function' &&
559 JSON
.parse('{"test": true}').test
;
561 function prepareReplacement(replacement
) {
562 if (Object
.isFunction(replacement
)) return replacement
;
563 var template
= new Template(replacement
);
564 return function(match
) { return template
.evaluate(match
) };
567 function isNonEmptyRegExp(regexp
) {
568 return regexp
.source
&& regexp
.source
!== '(?:)';
572 function gsub(pattern
, replacement
) {
573 var result
= '', source
= this, match
;
574 replacement
= prepareReplacement(replacement
);
576 if (Object
.isString(pattern
))
577 pattern
= RegExp
.escape(pattern
);
579 if (!(pattern
.length
|| isNonEmptyRegExp(pattern
))) {
580 replacement
= replacement('');
581 return replacement
+ source
.split('').join(replacement
) + replacement
;
584 while (source
.length
> 0) {
585 match
= source
.match(pattern
)
586 if (match
&& match
[0].length
> 0) {
587 result
+= source
.slice(0, match
.index
);
588 result
+= String
.interpret(replacement(match
));
589 source
= source
.slice(match
.index
+ match
[0].length
);
591 result
+= source
, source
= '';
597 function sub(pattern
, replacement
, count
) {
598 replacement
= prepareReplacement(replacement
);
599 count
= Object
.isUndefined(count
) ? 1 : count
;
601 return this.gsub(pattern
, function(match
) {
602 if (--count
< 0) return match
[0];
603 return replacement(match
);
607 function scan(pattern
, iterator
) {
608 this.gsub(pattern
, iterator
);
612 function truncate(length
, truncation
) {
613 length
= length
|| 30;
614 truncation
= Object
.isUndefined(truncation
) ? '...' : truncation
;
615 return this.length
> length
?
616 this.slice(0, length
- truncation
.length
) + truncation
: String(this);
620 return this.replace(/^\s+/, '').replace(/\s+$/, '');
623 function stripTags() {
624 return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?(\/)?>|<\/\w+>/gi, '');
627 function stripScripts() {
628 return this.replace(new RegExp(Prototype
.ScriptFragment
, 'img'), '');
631 function extractScripts() {
632 var matchAll
= new RegExp(Prototype
.ScriptFragment
, 'img'),
633 matchOne
= new RegExp(Prototype
.ScriptFragment
, 'im');
634 return (this.match(matchAll
) || []).map(function(scriptTag
) {
635 return (scriptTag
.match(matchOne
) || ['', ''])[1];
639 function evalScripts() {
640 return this.extractScripts().map(function(script
) { return eval(script
); });
643 function escapeHTML() {
644 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g
,'>');
647 function unescapeHTML() {
648 return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
652 function toQueryParams(separator
) {
653 var match
= this.strip().match(/([^?#]*)(#.*)?$/);
654 if (!match
) return { };
656 return match
[1].split(separator
|| '&').inject({ }, function(hash
, pair
) {
657 if ((pair
= pair
.split('='))[0]) {
658 var key
= decodeURIComponent(pair
.shift()),
659 value
= pair
.length
> 1 ? pair
.join('=') : pair
[0];
661 if (value
!= undefined) {
662 value
= value
.gsub('+', ' ');
663 value
= decodeURIComponent(value
);
667 if (!Object
.isArray(hash
[key
])) hash
[key
] = [hash
[key
]];
668 hash
[key
].push(value
);
670 else hash
[key
] = value
;
677 return this.split('');
681 return this.slice(0, this.length
- 1) +
682 String
.fromCharCode(this.charCodeAt(this.length
- 1) + 1);
685 function times(count
) {
686 return count
< 1 ? '' : new Array(count
+ 1).join(this);
689 function camelize() {
690 return this.replace(/-+(.)?/g, function(match
, chr
) {
691 return chr
? chr
.toUpperCase() : '';
695 function capitalize() {
696 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
699 function underscore() {
700 return this.replace(/::/g, '/')
701 .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
702 .replace(/([a-z\d])([A-Z])/g, '$1_$2')
707 function dasherize() {
708 return this.replace(/_
/g
, '-');
711 function inspect(useDoubleQuotes
) {
712 var escapedString
= this.replace(/[\x00-\x1f\\]/g, function(character
) {
713 if (character
in String
.specialChar
) {
714 return String
.specialChar
[character
];
716 return '\\u00' + character
.charCodeAt().toPaddedString(2, 16);
718 if (useDoubleQuotes
) return '"' + escapedString
.replace(/"/g, '\\"') + '"';
719 return "'" + escapedString.replace(/'/g
, '\\\'') + "'";
722 function unfilterJSON(filter
) {
723 return this.replace(filter
|| Prototype
.JSONFilter
, '$1');
728 if (str
.blank()) return false;
729 str
= str
.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
730 str
= str
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
731 str
= str
.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
732 return (/^[\],:{}\s]*$/).test(str
);
735 function evalJSON(sanitize
) {
736 var json
= this.unfilterJSON(),
737 cx
= /[\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff\u0000]/g;
739 json
= json
.replace(cx
, function (a
) {
740 return '\\u' + ('0000' + a
.charCodeAt(0).toString(16)).slice(-4);
744 if (!sanitize
|| json
.isJSON()) return eval('(' + json
+ ')');
746 throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
749 function parseJSON() {
750 var json
= this.unfilterJSON();
751 return JSON
.parse(json
);
754 function include(pattern
) {
755 return this.indexOf(pattern
) > -1;
758 function startsWith(pattern
, position
) {
759 position
= Object
.isNumber(position
) ? position
: 0;
760 return this.lastIndexOf(pattern
, position
) === position
;
763 function endsWith(pattern
, position
) {
764 pattern
= String(pattern
);
765 position
= Object
.isNumber(position
) ? position
: this.length
;
766 if (position
< 0) position
= 0;
767 if (position
> this.length
) position
= this.length
;
768 var d
= position
- pattern
.length
;
769 return d
>= 0 && this.indexOf(pattern
, d
) === d
;
777 return /^\s*$/.test(this);
780 function interpolate(object
, pattern
) {
781 return new Template(this, pattern
).evaluate(object
);
789 strip
: String
.prototype.trim
|| strip
,
790 stripTags
: stripTags
,
791 stripScripts
: stripScripts
,
792 extractScripts
: extractScripts
,
793 evalScripts
: evalScripts
,
794 escapeHTML
: escapeHTML
,
795 unescapeHTML
: unescapeHTML
,
796 toQueryParams
: toQueryParams
,
797 parseQuery
: toQueryParams
,
802 capitalize
: capitalize
,
803 underscore
: underscore
,
804 dasherize
: dasherize
,
806 unfilterJSON
: unfilterJSON
,
808 evalJSON
: NATIVE_JSON_PARSE_SUPPORT
? parseJSON
: evalJSON
,
810 startsWith
: String
.prototype.startsWith
|| startsWith
,
811 endsWith
: String
.prototype.endsWith
|| endsWith
,
814 interpolate
: interpolate
818 var Template
= Class
.create({
819 initialize: function(template
, pattern
) {
820 this.template
= template
.toString();
821 this.pattern
= pattern
|| Template
.Pattern
;
824 evaluate: function(object
) {
825 if (object
&& Object
.isFunction(object
.toTemplateReplacements
))
826 object
= object
.toTemplateReplacements();
828 return this.template
.gsub(this.pattern
, function(match
) {
829 if (object
== null) return (match
[1] + '');
831 var before
= match
[1] || '';
832 if (before
== '\\') return match
[2];
834 var ctx
= object
, expr
= match
[3],
835 pattern
= /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
837 match
= pattern
.exec(expr
);
838 if (match
== null) return before
;
840 while (match
!= null) {
841 var comp
= match
[1].startsWith('[') ? match
[2].replace(/\\\\]/g, ']') : match
[1];
843 if (null == ctx
|| '' == match
[3]) break;
844 expr
= expr
.substring('[' == match
[3] ? match
[1].length
: match
[0].length
);
845 match
= pattern
.exec(expr
);
848 return before
+ String
.interpret(ctx
);
852 Template
.Pattern
= /(^|.|\r|\n)(#\{(.*?)\})/;
856 var Enumerable
= (function() {
857 function each(iterator
, context
) {
859 this._each(iterator
, context
);
861 if (e
!= $break) throw e
;
866 function eachSlice(number
, iterator
, context
) {
867 var index
= -number
, slices
= [], array
= this.toArray();
868 if (number
< 1) return array
;
869 while ((index
+= number
) < array
.length
)
870 slices
.push(array
.slice(index
, index
+number
));
871 return slices
.collect(iterator
, context
);
874 function all(iterator
, context
) {
875 iterator
= iterator
|| Prototype
.K
;
877 this.each(function(value
, index
) {
878 result
= result
&& !!iterator
.call(context
, value
, index
, this);
879 if (!result
) throw $break;
884 function any(iterator
, context
) {
885 iterator
= iterator
|| Prototype
.K
;
887 this.each(function(value
, index
) {
888 if (result
= !!iterator
.call(context
, value
, index
, this))
894 function collect(iterator
, context
) {
895 iterator
= iterator
|| Prototype
.K
;
897 this.each(function(value
, index
) {
898 results
.push(iterator
.call(context
, value
, index
, this));
903 function detect(iterator
, context
) {
905 this.each(function(value
, index
) {
906 if (iterator
.call(context
, value
, index
, this)) {
914 function findAll(iterator
, context
) {
916 this.each(function(value
, index
) {
917 if (iterator
.call(context
, value
, index
, this))
923 function grep(filter
, iterator
, context
) {
924 iterator
= iterator
|| Prototype
.K
;
927 if (Object
.isString(filter
))
928 filter
= new RegExp(RegExp
.escape(filter
));
930 this.each(function(value
, index
) {
931 if (filter
.match(value
))
932 results
.push(iterator
.call(context
, value
, index
, this));
937 function include(object
) {
938 if (Object
.isFunction(this.indexOf
) && this.indexOf(object
) != -1)
942 this.each(function(value
) {
943 if (value
== object
) {
951 function inGroupsOf(number
, fillWith
) {
952 fillWith
= Object
.isUndefined(fillWith
) ? null : fillWith
;
953 return this.eachSlice(number
, function(slice
) {
954 while(slice
.length
< number
) slice
.push(fillWith
);
959 function inject(memo
, iterator
, context
) {
960 this.each(function(value
, index
) {
961 memo
= iterator
.call(context
, memo
, value
, index
, this);
966 function invoke(method
) {
967 var args
= $A(arguments
).slice(1);
968 return this.map(function(value
) {
969 return value
[method
].apply(value
, args
);
973 function max(iterator
, context
) {
974 iterator
= iterator
|| Prototype
.K
;
976 this.each(function(value
, index
) {
977 value
= iterator
.call(context
, value
, index
, this);
978 if (result
== null || value
>= result
)
984 function min(iterator
, context
) {
985 iterator
= iterator
|| Prototype
.K
;
987 this.each(function(value
, index
) {
988 value
= iterator
.call(context
, value
, index
, this);
989 if (result
== null || value
< result
)
995 function partition(iterator
, context
) {
996 iterator
= iterator
|| Prototype
.K
;
997 var trues
= [], falses
= [];
998 this.each(function(value
, index
) {
999 (iterator
.call(context
, value
, index
, this) ?
1000 trues
: falses
).push(value
);
1002 return [trues
, falses
];
1005 function pluck(property
) {
1007 this.each(function(value
) {
1008 results
.push(value
[property
]);
1013 function reject(iterator
, context
) {
1015 this.each(function(value
, index
) {
1016 if (!iterator
.call(context
, value
, index
, this))
1017 results
.push(value
);
1022 function sortBy(iterator
, context
) {
1023 return this.map(function(value
, index
) {
1026 criteria
: iterator
.call(context
, value
, index
, this)
1028 }, this).sort(function(left
, right
) {
1029 var a
= left
.criteria
, b
= right
.criteria
;
1030 return a
< b
? -1 : a
> b
? 1 : 0;
1034 function toArray() {
1039 var iterator
= Prototype
.K
, args
= $A(arguments
);
1040 if (Object
.isFunction(args
.last()))
1041 iterator
= args
.pop();
1043 var collections
= [this].concat(args
).map($A
);
1044 return this.map(function(value
, index
) {
1045 return iterator(collections
.pluck(index
));
1050 return this.toArray().length
;
1053 function inspect() {
1054 return '#<Enumerable:' + this.toArray().inspect() + '>';
1067 eachSlice
: eachSlice
,
1081 inGroupsOf
: inGroupsOf
,
1086 partition
: partition
,
1099 function $A(iterable
) {
1100 if (!iterable
) return [];
1101 if ('toArray' in Object(iterable
)) return iterable
.toArray();
1102 var length
= iterable
.length
|| 0, results
= new Array(length
);
1103 while (length
--) results
[length
] = iterable
[length
];
1108 function $w(string
) {
1109 if (!Object
.isString(string
)) return [];
1110 string
= string
.strip();
1111 return string
? string
.split(/\s+/) : [];
1118 var arrayProto
= Array
.prototype,
1119 slice
= arrayProto
.slice
,
1120 _each
= arrayProto
.forEach
; // use native browser JS 1.6 implementation if available
1122 function each(iterator
, context
) {
1123 for (var i
= 0, length
= this.length
>>> 0; i
< length
; i
++) {
1124 if (i
in this) iterator
.call(context
, this[i
], i
, this);
1127 if (!_each
) _each
= each
;
1139 return this[this.length
- 1];
1142 function compact() {
1143 return this.select(function(value
) {
1144 return value
!= null;
1148 function flatten() {
1149 return this.inject([], function(array
, value
) {
1150 if (Object
.isArray(value
))
1151 return array
.concat(value
.flatten());
1157 function without() {
1158 var values
= slice
.call(arguments
, 0);
1159 return this.select(function(value
) {
1160 return !values
.include(value
);
1164 function reverse(inline
) {
1165 return (inline
=== false ? this.toArray() : this)._reverse();
1168 function uniq(sorted
) {
1169 return this.inject([], function(array
, value
, index
) {
1170 if (0 == index
|| (sorted
? array
.last() != value
: !array
.include(value
)))
1176 function intersect(array
) {
1177 return this.uniq().findAll(function(item
) {
1178 return array
.indexOf(item
) !== -1;
1184 return slice
.call(this, 0);
1191 function inspect() {
1192 return '[' + this.map(Object
.inspect
).join(', ') + ']';
1195 function indexOf(item
, i
) {
1196 if (this == null) throw new TypeError();
1198 var array
= Object(this), length
= array
.length
>>> 0;
1199 if (length
=== 0) return -1;
1204 } else if (i
!== 0 && isFinite(i
)) {
1205 i
= (i
> 0 ? 1 : -1) * Math
.floor(Math
.abs(i
));
1208 if (i
> length
) return -1;
1210 var k
= i
>= 0 ? i
: Math
.max(length
- Math
.abs(i
), 0);
1211 for (; k
< length
; k
++)
1212 if (k
in array
&& array
[k
] === item
) return k
;
1217 function lastIndexOf(item
, i
) {
1218 if (this == null) throw new TypeError();
1220 var array
= Object(this), length
= array
.length
>>> 0;
1221 if (length
=== 0) return -1;
1223 if (!Object
.isUndefined(i
)) {
1227 } else if (i
!== 0 && isFinite(i
)) {
1228 i
= (i
> 0 ? 1 : -1) * Math
.floor(Math
.abs(i
));
1234 var k
= i
>= 0 ? Math
.min(i
, length
- 1) :
1235 length
- Math
.abs(i
);
1238 if (k
in array
&& array
[k
] === item
) return k
;
1242 function concat(_
) {
1243 var array
= [], items
= slice
.call(arguments
, 0), item
, n
= 0;
1244 items
.unshift(this);
1245 for (var i
= 0, length
= items
.length
; i
< length
; i
++) {
1247 if (Object
.isArray(item
) && !('callee' in item
)) {
1248 for (var j
= 0, arrayLength
= item
.length
; j
< arrayLength
; j
++) {
1249 if (j
in item
) array
[n
] = item
[j
];
1261 function wrapNative(method
) {
1263 if (arguments
.length
=== 0) {
1264 return method
.call(this, Prototype
.K
);
1265 } else if (arguments
[0] === undefined) {
1266 var args
= slice
.call(arguments
, 1);
1267 args
.unshift(Prototype
.K
);
1268 return method
.apply(this, args
);
1270 return method
.apply(this, arguments
);
1276 function map(iterator
) {
1277 if (this == null) throw new TypeError();
1278 iterator
= iterator
|| Prototype
.K
;
1280 var object
= Object(this);
1281 var results
= [], context
= arguments
[1], n
= 0;
1283 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1285 results
[n
] = iterator
.call(context
, object
[i
], i
, object
);
1293 if (arrayProto
.map
) {
1294 map
= wrapNative(Array
.prototype.map
);
1297 function filter(iterator
) {
1298 if (this == null || !Object
.isFunction(iterator
))
1299 throw new TypeError();
1301 var object
= Object(this);
1302 var results
= [], context
= arguments
[1], value
;
1304 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1307 if (iterator
.call(context
, value
, i
, object
)) {
1308 results
.push(value
);
1315 if (arrayProto
.filter
) {
1316 filter
= Array
.prototype.filter
;
1319 function some(iterator
) {
1320 if (this == null) throw new TypeError();
1321 iterator
= iterator
|| Prototype
.K
;
1322 var context
= arguments
[1];
1324 var object
= Object(this);
1325 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1326 if (i
in object
&& iterator
.call(context
, object
[i
], i
, object
)) {
1334 if (arrayProto
.some
) {
1335 some
= wrapNative(Array
.prototype.some
);
1338 function every(iterator
) {
1339 if (this == null) throw new TypeError();
1340 iterator
= iterator
|| Prototype
.K
;
1341 var context
= arguments
[1];
1343 var object
= Object(this);
1344 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1345 if (i
in object
&& !iterator
.call(context
, object
[i
], i
, object
)) {
1353 if (arrayProto
.every
) {
1354 every
= wrapNative(Array
.prototype.every
);
1358 Object
.extend(arrayProto
, Enumerable
);
1360 if (arrayProto
.entries
=== Enumerable
.entries
) {
1361 delete arrayProto
.entries
;
1364 if (!arrayProto
._reverse
)
1365 arrayProto
._reverse
= arrayProto
.reverse
;
1367 Object
.extend(arrayProto
, {
1388 intersect
: intersect
,
1395 var CONCAT_ARGUMENTS_BUGGY
= (function() {
1396 return [].concat(arguments
)[0][0] !== 1;
1399 if (CONCAT_ARGUMENTS_BUGGY
) arrayProto
.concat
= concat
;
1401 if (!arrayProto
.indexOf
) arrayProto
.indexOf
= indexOf
;
1402 if (!arrayProto
.lastIndexOf
) arrayProto
.lastIndexOf
= lastIndexOf
;
1404 function $H(object
) {
1405 return new Hash(object
);
1408 var Hash
= Class
.create(Enumerable
, (function() {
1409 function initialize(object
) {
1410 this._object
= Object
.isHash(object
) ? object
.toObject() : Object
.clone(object
);
1414 function _each(iterator
, context
) {
1416 for (var key
in this._object
) {
1417 var value
= this._object
[key
], pair
= [key
, value
];
1420 iterator
.call(context
, pair
, i
);
1425 function set(key
, value
) {
1426 return this._object
[key
] = value
;
1430 if (this._object
[key
] !== Object
.prototype[key
])
1431 return this._object
[key
];
1434 function unset(key
) {
1435 var value
= this._object
[key
];
1436 delete this._object
[key
];
1440 function toObject() {
1441 return Object
.clone(this._object
);
1447 return this.pluck('key');
1451 return this.pluck('value');
1454 function index(value
) {
1455 var match
= this.detect(function(pair
) {
1456 return pair
.value
=== value
;
1458 return match
&& match
.key
;
1461 function merge(object
) {
1462 return this.clone().update(object
);
1465 function update(object
) {
1466 return new Hash(object
).inject(this, function(result
, pair
) {
1467 result
.set(pair
.key
, pair
.value
);
1472 function toQueryPair(key
, value
) {
1473 if (Object
.isUndefined(value
)) return key
;
1475 value
= String
.interpret(value
);
1477 value
= value
.gsub(/(\r)?\n/, '\r\n');
1478 value
= encodeURIComponent(value
);
1479 value
= value
.gsub(/%20/, '+');
1480 return key
+ '=' + value
;
1483 function toQueryString() {
1484 return this.inject([], function(results
, pair
) {
1485 var key
= encodeURIComponent(pair
.key
), values
= pair
.value
;
1487 if (values
&& typeof values
== 'object') {
1488 if (Object
.isArray(values
)) {
1489 var queryValues
= [];
1490 for (var i
= 0, len
= values
.length
, value
; i
< len
; i
++) {
1492 queryValues
.push(toQueryPair(key
, value
));
1494 return results
.concat(queryValues
);
1496 } else results
.push(toQueryPair(key
, values
));
1501 function inspect() {
1502 return '#<Hash:{' + this.map(function(pair
) {
1503 return pair
.map(Object
.inspect
).join(': ');
1504 }).join(', ') + '}>';
1508 return new Hash(this);
1512 initialize
: initialize
,
1518 toTemplateReplacements
: toObject
,
1524 toQueryString
: toQueryString
,
1532 Object
.extend(Number
.prototype, (function() {
1533 function toColorPart() {
1534 return this.toPaddedString(2, 16);
1541 function times(iterator
, context
) {
1542 $R(0, this, true).each(iterator
, context
);
1546 function toPaddedString(length
, radix
) {
1547 var string
= this.toString(radix
|| 10);
1548 return '0'.times(length
- string
.length
) + string
;
1552 return Math
.abs(this);
1556 return Math
.round(this);
1560 return Math
.ceil(this);
1564 return Math
.floor(this);
1568 toColorPart
: toColorPart
,
1571 toPaddedString
: toPaddedString
,
1579 function $R(start
, end
, exclusive
) {
1580 return new ObjectRange(start
, end
, exclusive
);
1583 var ObjectRange
= Class
.create(Enumerable
, (function() {
1584 function initialize(start
, end
, exclusive
) {
1587 this.exclusive
= exclusive
;
1590 function _each(iterator
, context
) {
1591 var value
= this.start
, i
;
1592 for (i
= 0; this.include(value
); i
++) {
1593 iterator
.call(context
, value
, i
);
1594 value
= value
.succ();
1598 function include(value
) {
1599 if (value
< this.start
)
1602 return value
< this.end
;
1603 return value
<= this.end
;
1607 initialize
: initialize
,
1622 for (var i
= 0, length
= arguments
.length
; i
< length
; i
++) {
1623 var lambda
= arguments
[i
];
1625 returnValue
= lambda();
1635 getTransport: function() {
1637 function() {return new XMLHttpRequest()},
1638 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1639 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1643 activeRequestCount
: 0
1649 _each: function(iterator
, context
) {
1650 this.responders
._each(iterator
, context
);
1653 register: function(responder
) {
1654 if (!this.include(responder
))
1655 this.responders
.push(responder
);
1658 unregister: function(responder
) {
1659 this.responders
= this.responders
.without(responder
);
1662 dispatch: function(callback
, request
, transport
, json
) {
1663 this.each(function(responder
) {
1664 if (Object
.isFunction(responder
[callback
])) {
1666 responder
[callback
].apply(responder
, [request
, transport
, json
]);
1673 Object
.extend(Ajax
.Responders
, Enumerable
);
1675 Ajax
.Responders
.register({
1676 onCreate: function() { Ajax
.activeRequestCount
++ },
1677 onComplete: function() { Ajax
.activeRequestCount
-- }
1679 Ajax
.Base
= Class
.create({
1680 initialize: function(options
) {
1684 contentType
: 'application/x-www-form-urlencoded',
1690 Object
.extend(this.options
, options
|| { });
1692 this.options
.method
= this.options
.method
.toLowerCase();
1694 if (Object
.isHash(this.options
.parameters
))
1695 this.options
.parameters
= this.options
.parameters
.toObject();
1698 Ajax
.Request
= Class
.create(Ajax
.Base
, {
1701 initialize: function($super, url
, options
) {
1703 this.transport
= Ajax
.getTransport();
1707 request: function(url
) {
1709 this.method
= this.options
.method
;
1710 var params
= Object
.isString(this.options
.parameters
) ?
1711 this.options
.parameters
:
1712 Object
.toQueryString(this.options
.parameters
);
1714 if (!['get', 'post'].include(this.method
)) {
1715 params
+= (params
? '&' : '') + "_method=" + this.method
;
1716 this.method
= 'post';
1719 if (params
&& this.method
=== 'get') {
1720 this.url
+= (this.url
.include('?') ? '&' : '?') + params
;
1723 this.parameters
= params
.toQueryParams();
1726 var response
= new Ajax
.Response(this);
1727 if (this.options
.onCreate
) this.options
.onCreate(response
);
1728 Ajax
.Responders
.dispatch('onCreate', this, response
);
1730 this.transport
.open(this.method
.toUpperCase(), this.url
,
1731 this.options
.asynchronous
);
1733 if (this.options
.asynchronous
) this.respondToReadyState
.bind(this).defer(1);
1735 this.transport
.onreadystatechange
= this.onStateChange
.bind(this);
1736 this.setRequestHeaders();
1738 this.body
= this.method
== 'post' ? (this.options
.postBody
|| params
) : null;
1739 this.transport
.send(this.body
);
1741 /* Force Firefox to handle ready state 4 for synchronous requests */
1742 if (!this.options
.asynchronous
&& this.transport
.overrideMimeType
)
1743 this.onStateChange();
1747 this.dispatchException(e
);
1751 onStateChange: function() {
1752 var readyState
= this.transport
.readyState
;
1753 if (readyState
> 1 && !((readyState
== 4) && this._complete
))
1754 this.respondToReadyState(this.transport
.readyState
);
1757 setRequestHeaders: function() {
1759 'X-Requested-With': 'XMLHttpRequest',
1760 'X-Prototype-Version': Prototype
.Version
,
1761 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1764 if (this.method
== 'post') {
1765 headers
['Content-type'] = this.options
.contentType
+
1766 (this.options
.encoding
? '; charset=' + this.options
.encoding
: '');
1768 /* Force "Connection: close" for older Mozilla browsers to work
1769 * around a bug where XMLHttpRequest sends an incorrect
1770 * Content-length header. See Mozilla Bugzilla #246651.
1772 if (this.transport
.overrideMimeType
&&
1773 (navigator
.userAgent
.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1774 headers
['Connection'] = 'close';
1777 if (typeof this.options
.requestHeaders
== 'object') {
1778 var extras
= this.options
.requestHeaders
;
1780 if (Object
.isFunction(extras
.push
))
1781 for (var i
= 0, length
= extras
.length
; i
< length
; i
+= 2)
1782 headers
[extras
[i
]] = extras
[i
+1];
1784 $H(extras
).each(function(pair
) { headers
[pair
.key
] = pair
.value
});
1787 for (var name
in headers
)
1788 if (headers
[name
] != null)
1789 this.transport
.setRequestHeader(name
, headers
[name
]);
1792 success: function() {
1793 var status
= this.getStatus();
1794 return !status
|| (status
>= 200 && status
< 300) || status
== 304;
1797 getStatus: function() {
1799 if (this.transport
.status
=== 1223) return 204;
1800 return this.transport
.status
|| 0;
1801 } catch (e
) { return 0 }
1804 respondToReadyState: function(readyState
) {
1805 var state
= Ajax
.Request
.Events
[readyState
], response
= new Ajax
.Response(this);
1807 if (state
== 'Complete') {
1809 this._complete
= true;
1810 (this.options
['on' + response
.status
]
1811 || this.options
['on' + (this.success() ? 'Success' : 'Failure')]
1812 || Prototype
.emptyFunction
)(response
, response
.headerJSON
);
1814 this.dispatchException(e
);
1817 var contentType
= response
.getHeader('Content-type');
1818 if (this.options
.evalJS
== 'force'
1819 || (this.options
.evalJS
&& this.isSameOrigin() && contentType
1820 && contentType
.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1821 this.evalResponse();
1825 (this.options
['on' + state
] || Prototype
.emptyFunction
)(response
, response
.headerJSON
);
1826 Ajax
.Responders
.dispatch('on' + state
, this, response
, response
.headerJSON
);
1828 this.dispatchException(e
);
1831 if (state
== 'Complete') {
1832 this.transport
.onreadystatechange
= Prototype
.emptyFunction
;
1836 isSameOrigin: function() {
1837 var m
= this.url
.match(/^\s*https?:\/\/[^\/]*/);
1838 return !m
|| (m
[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1839 protocol
: location
.protocol
,
1840 domain
: document
.domain
,
1841 port
: location
.port
? ':' + location
.port
: ''
1845 getHeader: function(name
) {
1847 return this.transport
.getResponseHeader(name
) || null;
1848 } catch (e
) { return null; }
1851 evalResponse: function() {
1853 return eval((this.transport
.responseText
|| '').unfilterJSON());
1855 this.dispatchException(e
);
1859 dispatchException: function(exception
) {
1860 (this.options
.onException
|| Prototype
.emptyFunction
)(this, exception
);
1861 Ajax
.Responders
.dispatch('onException', this, exception
);
1865 Ajax
.Request
.Events
=
1866 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1875 Ajax
.Response
= Class
.create({
1876 initialize: function(request
){
1877 this.request
= request
;
1878 var transport
= this.transport
= request
.transport
,
1879 readyState
= this.readyState
= transport
.readyState
;
1881 if ((readyState
> 2 && !Prototype
.Browser
.IE
) || readyState
== 4) {
1882 this.status
= this.getStatus();
1883 this.statusText
= this.getStatusText();
1884 this.responseText
= String
.interpret(transport
.responseText
);
1885 this.headerJSON
= this._getHeaderJSON();
1888 if (readyState
== 4) {
1889 var xml
= transport
.responseXML
;
1890 this.responseXML
= Object
.isUndefined(xml
) ? null : xml
;
1891 this.responseJSON
= this._getResponseJSON();
1899 getStatus
: Ajax
.Request
.prototype.getStatus
,
1901 getStatusText: function() {
1903 return this.transport
.statusText
|| '';
1904 } catch (e
) { return '' }
1907 getHeader
: Ajax
.Request
.prototype.getHeader
,
1909 getAllHeaders: function() {
1911 return this.getAllResponseHeaders();
1912 } catch (e
) { return null }
1915 getResponseHeader: function(name
) {
1916 return this.transport
.getResponseHeader(name
);
1919 getAllResponseHeaders: function() {
1920 return this.transport
.getAllResponseHeaders();
1923 _getHeaderJSON: function() {
1924 var json
= this.getHeader('X-JSON');
1925 if (!json
) return null;
1928 json
= decodeURIComponent(escape(json
));
1933 return json
.evalJSON(this.request
.options
.sanitizeJSON
||
1934 !this.request
.isSameOrigin());
1936 this.request
.dispatchException(e
);
1940 _getResponseJSON: function() {
1941 var options
= this.request
.options
;
1942 if (!options
.evalJSON
|| (options
.evalJSON
!= 'force' &&
1943 !(this.getHeader('Content-type') || '').include('application/json')) ||
1944 this.responseText
.blank())
1947 return this.responseText
.evalJSON(options
.sanitizeJSON
||
1948 !this.request
.isSameOrigin());
1950 this.request
.dispatchException(e
);
1955 Ajax
.Updater
= Class
.create(Ajax
.Request
, {
1956 initialize: function($super, container
, url
, options
) {
1958 success
: (container
.success
|| container
),
1959 failure
: (container
.failure
|| (container
.success
? null : container
))
1962 options
= Object
.clone(options
);
1963 var onComplete
= options
.onComplete
;
1964 options
.onComplete
= (function(response
, json
) {
1965 this.updateContent(response
.responseText
);
1966 if (Object
.isFunction(onComplete
)) onComplete(response
, json
);
1969 $super(url
, options
);
1972 updateContent: function(responseText
) {
1973 var receiver
= this.container
[this.success() ? 'success' : 'failure'],
1974 options
= this.options
;
1976 if (!options
.evalScripts
) responseText
= responseText
.stripScripts();
1978 if (receiver
= $(receiver
)) {
1979 if (options
.insertion
) {
1980 if (Object
.isString(options
.insertion
)) {
1981 var insertion
= { }; insertion
[options
.insertion
] = responseText
;
1982 receiver
.insert(insertion
);
1984 else options
.insertion(receiver
, responseText
);
1986 else receiver
.update(responseText
);
1991 Ajax
.PeriodicalUpdater
= Class
.create(Ajax
.Base
, {
1992 initialize: function($super, container
, url
, options
) {
1994 this.onComplete
= this.options
.onComplete
;
1996 this.frequency
= (this.options
.frequency
|| 2);
1997 this.decay
= (this.options
.decay
|| 1);
2000 this.container
= container
;
2007 this.options
.onComplete
= this.updateComplete
.bind(this);
2008 this.onTimerEvent();
2012 this.updater
.options
.onComplete
= undefined;
2013 clearTimeout(this.timer
);
2014 (this.onComplete
|| Prototype
.emptyFunction
).apply(this, arguments
);
2017 updateComplete: function(response
) {
2018 if (this.options
.decay
) {
2019 this.decay
= (response
.responseText
== this.lastText
?
2020 this.decay
* this.options
.decay
: 1);
2022 this.lastText
= response
.responseText
;
2024 this.timer
= this.onTimerEvent
.bind(this).delay(this.decay
* this.frequency
);
2027 onTimerEvent: function() {
2028 this.updater
= new Ajax
.Updater(this.container
, this.url
, this.options
);
2035 var SLICE
= Array
.prototype.slice
;
2037 var DIV
= document
.createElement('div');
2040 function $(element
) {
2041 if (arguments
.length
> 1) {
2042 for (var i
= 0, elements
= [], length
= arguments
.length
; i
< length
; i
++)
2043 elements
.push($(arguments
[i
]));
2047 if (Object
.isString(element
))
2048 element
= document
.getElementById(element
);
2049 return Element
.extend(element
);
2055 if (!GLOBAL
.Node
) GLOBAL
.Node
= {};
2057 if (!GLOBAL
.Node
.ELEMENT_NODE
) {
2058 Object
.extend(GLOBAL
.Node
, {
2062 CDATA_SECTION_NODE
: 4,
2063 ENTITY_REFERENCE_NODE
: 5,
2065 PROCESSING_INSTRUCTION_NODE
: 7,
2068 DOCUMENT_TYPE_NODE
: 10,
2069 DOCUMENT_FRAGMENT_NODE
: 11,
2074 var ELEMENT_CACHE
= {};
2076 function shouldUseCreationCache(tagName
, attributes
) {
2077 if (tagName
=== 'select') return false;
2078 if ('type' in attributes
) return false;
2082 var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
= (function(){
2084 var el
= document
.createElement('<input name="x">');
2085 return el
.tagName
.toLowerCase() === 'input' && el
.name
=== 'x';
2093 var oldElement
= GLOBAL
.Element
;
2094 function Element(tagName
, attributes
) {
2095 attributes
= attributes
|| {};
2096 tagName
= tagName
.toLowerCase();
2098 if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
&& attributes
.name
) {
2099 tagName
= '<' + tagName
+ ' name="' + attributes
.name
+ '">';
2100 delete attributes
.name
;
2101 return Element
.writeAttribute(document
.createElement(tagName
), attributes
);
2104 if (!ELEMENT_CACHE
[tagName
])
2105 ELEMENT_CACHE
[tagName
] = Element
.extend(document
.createElement(tagName
));
2107 var node
= shouldUseCreationCache(tagName
, attributes
) ?
2108 ELEMENT_CACHE
[tagName
].cloneNode(false) : document
.createElement(tagName
);
2110 return Element
.writeAttribute(node
, attributes
);
2113 GLOBAL
.Element
= Element
;
2115 Object
.extend(GLOBAL
.Element
, oldElement
|| {});
2116 if (oldElement
) GLOBAL
.Element
.prototype = oldElement
.prototype;
2118 Element
.Methods
= { ByTag
: {}, Simulated
: {} };
2122 var INSPECT_ATTRIBUTES
= { id
: 'id', className
: 'class' };
2123 function inspect(element
) {
2124 element
= $(element
);
2125 var result
= '<' + element
.tagName
.toLowerCase();
2127 var attribute
, value
;
2128 for (var property
in INSPECT_ATTRIBUTES
) {
2129 attribute
= INSPECT_ATTRIBUTES
[property
];
2130 value
= (element
[property
] || '').toString();
2131 if (value
) result
+= ' ' + attribute
+ '=' + value
.inspect(true);
2134 return result
+ '>';
2137 methods
.inspect
= inspect
;
2140 function visible(element
) {
2141 return $(element
).getStyle('display') !== 'none';
2144 function toggle(element
, bool
) {
2145 element
= $(element
);
2146 if (typeof bool
!== 'boolean')
2147 bool
= !Element
.visible(element
);
2148 Element
[bool
? 'show' : 'hide'](element
);
2153 function hide(element
) {
2154 element
= $(element
);
2155 element
.style
.display
= 'none';
2159 function show(element
) {
2160 element
= $(element
);
2161 element
.style
.display
= '';
2166 Object
.extend(methods
, {
2174 function remove(element
) {
2175 element
= $(element
);
2176 element
.parentNode
.removeChild(element
);
2180 var SELECT_ELEMENT_INNERHTML_BUGGY
= (function(){
2181 var el
= document
.createElement("select"),
2183 el
.innerHTML
= "<option value=\"test\">test</option>";
2184 if (el
.options
&& el
.options
[0]) {
2185 isBuggy
= el
.options
[0].nodeName
.toUpperCase() !== "OPTION";
2191 var TABLE_ELEMENT_INNERHTML_BUGGY
= (function(){
2193 var el
= document
.createElement("table");
2194 if (el
&& el
.tBodies
) {
2195 el
.innerHTML
= "<tbody><tr><td>test</td></tr></tbody>";
2196 var isBuggy
= typeof el
.tBodies
[0] == "undefined";
2205 var LINK_ELEMENT_INNERHTML_BUGGY
= (function() {
2207 var el
= document
.createElement('div');
2208 el
.innerHTML
= "<link />";
2209 var isBuggy
= (el
.childNodes
.length
=== 0);
2217 var ANY_INNERHTML_BUGGY
= SELECT_ELEMENT_INNERHTML_BUGGY
||
2218 TABLE_ELEMENT_INNERHTML_BUGGY
|| LINK_ELEMENT_INNERHTML_BUGGY
;
2220 var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING
= (function () {
2221 var s
= document
.createElement("script"),
2224 s
.appendChild(document
.createTextNode(""));
2225 isBuggy
= !s
.firstChild
||
2226 s
.firstChild
&& s
.firstChild
.nodeType
!== 3;
2234 function update(element
, content
) {
2235 element
= $(element
);
2237 var descendants
= element
.getElementsByTagName('*'),
2238 i
= descendants
.length
;
2239 while (i
--) purgeElement(descendants
[i
]);
2241 if (content
&& content
.toElement
)
2242 content
= content
.toElement();
2244 if (Object
.isElement(content
))
2245 return element
.update().insert(content
);
2248 content
= Object
.toHTML(content
);
2249 var tagName
= element
.tagName
.toUpperCase();
2251 if (tagName
=== 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING
) {
2252 element
.text
= content
;
2256 if (ANY_INNERHTML_BUGGY
) {
2257 if (tagName
in INSERTION_TRANSLATIONS
.tags
) {
2258 while (element
.firstChild
)
2259 element
.removeChild(element
.firstChild
);
2261 var nodes
= getContentFromAnonymousElement(tagName
, content
.stripScripts());
2262 for (var i
= 0, node
; node
= nodes
[i
]; i
++)
2263 element
.appendChild(node
);
2265 } else if (LINK_ELEMENT_INNERHTML_BUGGY
&& Object
.isString(content
) && content
.indexOf('<link') > -1) {
2266 while (element
.firstChild
)
2267 element
.removeChild(element
.firstChild
);
2269 var nodes
= getContentFromAnonymousElement(tagName
,
2270 content
.stripScripts(), true);
2272 for (var i
= 0, node
; node
= nodes
[i
]; i
++)
2273 element
.appendChild(node
);
2275 element
.innerHTML
= content
.stripScripts();
2278 element
.innerHTML
= content
.stripScripts();
2281 content
.evalScripts
.bind(content
).defer();
2285 function replace(element
, content
) {
2286 element
= $(element
);
2288 if (content
&& content
.toElement
) {
2289 content
= content
.toElement();
2290 } else if (!Object
.isElement(content
)) {
2291 content
= Object
.toHTML(content
);
2292 var range
= element
.ownerDocument
.createRange();
2293 range
.selectNode(element
);
2294 content
.evalScripts
.bind(content
).defer();
2295 content
= range
.createContextualFragment(content
.stripScripts());
2298 element
.parentNode
.replaceChild(content
, element
);
2302 var INSERTION_TRANSLATIONS
= {
2303 before: function(element
, node
) {
2304 element
.parentNode
.insertBefore(node
, element
);
2306 top: function(element
, node
) {
2307 element
.insertBefore(node
, element
.firstChild
);
2309 bottom: function(element
, node
) {
2310 element
.appendChild(node
);
2312 after: function(element
, node
) {
2313 element
.parentNode
.insertBefore(node
, element
.nextSibling
);
2317 TABLE
: ['<table>', '</table>', 1],
2318 TBODY
: ['<table><tbody>', '</tbody></table>', 2],
2319 TR
: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2320 TD
: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2321 SELECT
: ['<select>', '</select>', 1]
2325 var tags
= INSERTION_TRANSLATIONS
.tags
;
2327 Object
.extend(tags
, {
2333 function replace_IE(element
, content
) {
2334 element
= $(element
);
2335 if (content
&& content
.toElement
)
2336 content
= content
.toElement();
2337 if (Object
.isElement(content
)) {
2338 element
.parentNode
.replaceChild(content
, element
);
2342 content
= Object
.toHTML(content
);
2343 var parent
= element
.parentNode
, tagName
= parent
.tagName
.toUpperCase();
2345 if (tagName
in INSERTION_TRANSLATIONS
.tags
) {
2346 var nextSibling
= Element
.next(element
);
2347 var fragments
= getContentFromAnonymousElement(
2348 tagName
, content
.stripScripts());
2350 parent
.removeChild(element
);
2354 iterator = function(node
) { parent
.insertBefore(node
, nextSibling
) };
2356 iterator = function(node
) { parent
.appendChild(node
); }
2358 fragments
.each(iterator
);
2360 element
.outerHTML
= content
.stripScripts();
2363 content
.evalScripts
.bind(content
).defer();
2367 if ('outerHTML' in document
.documentElement
)
2368 replace
= replace_IE
;
2370 function isContent(content
) {
2371 if (Object
.isUndefined(content
) || content
=== null) return false;
2373 if (Object
.isString(content
) || Object
.isNumber(content
)) return true;
2374 if (Object
.isElement(content
)) return true;
2375 if (content
.toElement
|| content
.toHTML
) return true;
2380 function insertContentAt(element
, content
, position
) {
2381 position
= position
.toLowerCase();
2382 var method
= INSERTION_TRANSLATIONS
[position
];
2384 if (content
&& content
.toElement
) content
= content
.toElement();
2385 if (Object
.isElement(content
)) {
2386 method(element
, content
);
2390 content
= Object
.toHTML(content
);
2391 var tagName
= ((position
=== 'before' || position
=== 'after') ?
2392 element
.parentNode
: element
).tagName
.toUpperCase();
2394 var childNodes
= getContentFromAnonymousElement(tagName
, content
.stripScripts());
2396 if (position
=== 'top' || position
=== 'after') childNodes
.reverse();
2398 for (var i
= 0, node
; node
= childNodes
[i
]; i
++)
2399 method(element
, node
);
2401 content
.evalScripts
.bind(content
).defer();
2404 function insert(element
, insertions
) {
2405 element
= $(element
);
2407 if (isContent(insertions
))
2408 insertions
= { bottom
: insertions
};
2410 for (var position
in insertions
)
2411 insertContentAt(element
, insertions
[position
], position
);
2416 function wrap(element
, wrapper
, attributes
) {
2417 element
= $(element
);
2419 if (Object
.isElement(wrapper
)) {
2420 $(wrapper
).writeAttribute(attributes
|| {});
2421 } else if (Object
.isString(wrapper
)) {
2422 wrapper
= new Element(wrapper
, attributes
);
2424 wrapper
= new Element('div', wrapper
);
2427 if (element
.parentNode
)
2428 element
.parentNode
.replaceChild(wrapper
, element
);
2430 wrapper
.appendChild(element
);
2435 function cleanWhitespace(element
) {
2436 element
= $(element
);
2437 var node
= element
.firstChild
;
2440 var nextNode
= node
.nextSibling
;
2441 if (node
.nodeType
=== Node
.TEXT_NODE
&& !/\S/.test(node
.nodeValue
))
2442 element
.removeChild(node
);
2448 function empty(element
) {
2449 return $(element
).innerHTML
.blank();
2452 function getContentFromAnonymousElement(tagName
, html
, force
) {
2453 var t
= INSERTION_TRANSLATIONS
.tags
[tagName
], div
= DIV
;
2455 var workaround
= !!t
;
2456 if (!workaround
&& force
) {
2462 div
.innerHTML
= ' ' + t
[0] + html
+ t
[1];
2463 div
.removeChild(div
.firstChild
);
2464 for (var i
= t
[2]; i
--; )
2465 div
= div
.firstChild
;
2467 div
.innerHTML
= html
;
2470 return $A(div
.childNodes
);
2473 function clone(element
, deep
) {
2474 if (!(element
= $(element
))) return;
2475 var clone
= element
.cloneNode(deep
);
2476 if (!HAS_UNIQUE_ID_PROPERTY
) {
2477 clone
._prototypeUID
= UNDEFINED
;
2479 var descendants
= Element
.select(clone
, '*'),
2480 i
= descendants
.length
;
2482 descendants
[i
]._prototypeUID
= UNDEFINED
;
2485 return Element
.extend(clone
);
2488 function purgeElement(element
) {
2489 var uid
= getUniqueElementID(element
);
2491 Element
.stopObserving(element
);
2492 if (!HAS_UNIQUE_ID_PROPERTY
)
2493 element
._prototypeUID
= UNDEFINED
;
2494 delete Element
.Storage
[uid
];
2498 function purgeCollection(elements
) {
2499 var i
= elements
.length
;
2501 purgeElement(elements
[i
]);
2504 function purgeCollection_IE(elements
) {
2505 var i
= elements
.length
, element
, uid
;
2507 element
= elements
[i
];
2508 uid
= getUniqueElementID(element
);
2509 delete Element
.Storage
[uid
];
2510 delete Event
.cache
[uid
];
2514 if (HAS_UNIQUE_ID_PROPERTY
) {
2515 purgeCollection
= purgeCollection_IE
;
2519 function purge(element
) {
2520 if (!(element
= $(element
))) return;
2521 purgeElement(element
);
2523 var descendants
= element
.getElementsByTagName('*'),
2524 i
= descendants
.length
;
2526 while (i
--) purgeElement(descendants
[i
]);
2531 Object
.extend(methods
, {
2537 cleanWhitespace
: cleanWhitespace
,
2545 function recursivelyCollect(element
, property
, maximumLength
) {
2546 element
= $(element
);
2547 maximumLength
= maximumLength
|| -1;
2550 while (element
= element
[property
]) {
2551 if (element
.nodeType
=== Node
.ELEMENT_NODE
)
2552 elements
.push(Element
.extend(element
));
2554 if (elements
.length
=== maximumLength
) break;
2561 function ancestors(element
) {
2562 return recursivelyCollect(element
, 'parentNode');
2565 function descendants(element
) {
2566 return Element
.select(element
, '*');
2569 function firstDescendant(element
) {
2570 element
= $(element
).firstChild
;
2571 while (element
&& element
.nodeType
!== Node
.ELEMENT_NODE
)
2572 element
= element
.nextSibling
;
2577 function immediateDescendants(element
) {
2578 var results
= [], child
= $(element
).firstChild
;
2581 if (child
.nodeType
=== Node
.ELEMENT_NODE
)
2582 results
.push(Element
.extend(child
));
2584 child
= child
.nextSibling
;
2590 function previousSiblings(element
) {
2591 return recursivelyCollect(element
, 'previousSibling');
2594 function nextSiblings(element
) {
2595 return recursivelyCollect(element
, 'nextSibling');
2598 function siblings(element
) {
2599 element
= $(element
);
2600 var previous
= previousSiblings(element
),
2601 next
= nextSiblings(element
);
2602 return previous
.reverse().concat(next
);
2605 function match(element
, selector
) {
2606 element
= $(element
);
2608 if (Object
.isString(selector
))
2609 return Prototype
.Selector
.match(element
, selector
);
2611 return selector
.match(element
);
2615 function _recursivelyFind(element
, property
, expression
, index
) {
2616 element
= $(element
), expression
= expression
|| 0, index
= index
|| 0;
2617 if (Object
.isNumber(expression
)) {
2618 index
= expression
, expression
= null;
2621 while (element
= element
[property
]) {
2622 if (element
.nodeType
!== 1) continue;
2623 if (expression
&& !Prototype
.Selector
.match(element
, expression
))
2625 if (--index
>= 0) continue;
2627 return Element
.extend(element
);
2632 function up(element
, expression
, index
) {
2633 element
= $(element
);
2635 if (arguments
.length
=== 1) return $(element
.parentNode
);
2636 return _recursivelyFind(element
, 'parentNode', expression
, index
);
2639 function down(element
, expression
, index
) {
2640 if (arguments
.length
=== 1) return firstDescendant(element
);
2641 element
= $(element
), expression
= expression
|| 0, index
= index
|| 0;
2643 if (Object
.isNumber(expression
))
2644 index
= expression
, expression
= '*';
2646 var node
= Prototype
.Selector
.select(expression
, element
)[index
];
2647 return Element
.extend(node
);
2650 function previous(element
, expression
, index
) {
2651 return _recursivelyFind(element
, 'previousSibling', expression
, index
);
2654 function next(element
, expression
, index
) {
2655 return _recursivelyFind(element
, 'nextSibling', expression
, index
);
2658 function select(element
) {
2659 element
= $(element
);
2660 var expressions
= SLICE
.call(arguments
, 1).join(', ');
2661 return Prototype
.Selector
.select(expressions
, element
);
2664 function adjacent(element
) {
2665 element
= $(element
);
2666 var expressions
= SLICE
.call(arguments
, 1).join(', ');
2667 var siblings
= Element
.siblings(element
), results
= [];
2668 for (var i
= 0, sibling
; sibling
= siblings
[i
]; i
++) {
2669 if (Prototype
.Selector
.match(sibling
, expressions
))
2670 results
.push(sibling
);
2676 function descendantOf_DOM(element
, ancestor
) {
2677 element
= $(element
), ancestor
= $(ancestor
);
2678 if (!element
|| !ancestor
) return false;
2679 while (element
= element
.parentNode
)
2680 if (element
=== ancestor
) return true;
2684 function descendantOf_contains(element
, ancestor
) {
2685 element
= $(element
), ancestor
= $(ancestor
);
2686 if (!element
|| !ancestor
) return false;
2687 if (!ancestor
.contains
) return descendantOf_DOM(element
, ancestor
);
2688 return ancestor
.contains(element
) && ancestor
!== element
;
2691 function descendantOf_compareDocumentPosition(element
, ancestor
) {
2692 element
= $(element
), ancestor
= $(ancestor
);
2693 if (!element
|| !ancestor
) return false;
2694 return (element
.compareDocumentPosition(ancestor
) & 8) === 8;
2698 if (DIV
.compareDocumentPosition
) {
2699 descendantOf
= descendantOf_compareDocumentPosition
;
2700 } else if (DIV
.contains
) {
2701 descendantOf
= descendantOf_contains
;
2703 descendantOf
= descendantOf_DOM
;
2707 Object
.extend(methods
, {
2708 recursivelyCollect
: recursivelyCollect
,
2709 ancestors
: ancestors
,
2710 descendants
: descendants
,
2711 firstDescendant
: firstDescendant
,
2712 immediateDescendants
: immediateDescendants
,
2713 previousSiblings
: previousSiblings
,
2714 nextSiblings
: nextSiblings
,
2723 descendantOf
: descendantOf
,
2725 getElementsBySelector
: select
,
2727 childElements
: immediateDescendants
2732 function identify(element
) {
2733 element
= $(element
);
2734 var id
= Element
.readAttribute(element
, 'id');
2737 do { id
= 'anonymous_element_' + idCounter
++ } while ($(id
));
2739 Element
.writeAttribute(element
, 'id', id
);
2744 function readAttribute(element
, name
) {
2745 return $(element
).getAttribute(name
);
2748 function readAttribute_IE(element
, name
) {
2749 element
= $(element
);
2751 var table
= ATTRIBUTE_TRANSLATIONS
.read
;
2752 if (table
.values
[name
])
2753 return table
.values
[name
](element
, name
);
2755 if (table
.names
[name
]) name
= table
.names
[name
];
2757 if (name
.include(':')) {
2758 if (!element
.attributes
|| !element
.attributes
[name
]) return null;
2759 return element
.attributes
[name
].value
;
2762 return element
.getAttribute(name
);
2765 function readAttribute_Opera(element
, name
) {
2766 if (name
=== 'title') return element
.title
;
2767 return element
.getAttribute(name
);
2770 var PROBLEMATIC_ATTRIBUTE_READING
= (function() {
2771 DIV
.setAttribute('onclick', []);
2772 var value
= DIV
.getAttribute('onclick');
2773 var isFunction
= Object
.isArray(value
);
2774 DIV
.removeAttribute('onclick');
2778 if (PROBLEMATIC_ATTRIBUTE_READING
) {
2779 readAttribute
= readAttribute_IE
;
2780 } else if (Prototype
.Browser
.Opera
) {
2781 readAttribute
= readAttribute_Opera
;
2785 function writeAttribute(element
, name
, value
) {
2786 element
= $(element
);
2787 var attributes
= {}, table
= ATTRIBUTE_TRANSLATIONS
.write
;
2789 if (typeof name
=== 'object') {
2792 attributes
[name
] = Object
.isUndefined(value
) ? true : value
;
2795 for (var attr
in attributes
) {
2796 name
= table
.names
[attr
] || attr
;
2797 value
= attributes
[attr
];
2798 if (table
.values
[attr
]) {
2799 value
= table
.values
[attr
](element
, value
);
2800 if (Object
.isUndefined(value
)) continue;
2802 if (value
=== false || value
=== null)
2803 element
.removeAttribute(name
);
2804 else if (value
=== true)
2805 element
.setAttribute(name
, name
);
2806 else element
.setAttribute(name
, value
);
2812 var PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES
= (function () {
2813 if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
) {
2816 var checkbox
= document
.createElement('<input type="checkbox">');
2817 checkbox
.checked
= true;
2818 var node
= checkbox
.getAttributeNode('checked');
2819 return !node
|| !node
.specified
;
2822 function hasAttribute(element
, attribute
) {
2823 attribute
= ATTRIBUTE_TRANSLATIONS
.has
[attribute
] || attribute
;
2824 var node
= $(element
).getAttributeNode(attribute
);
2825 return !!(node
&& node
.specified
);
2828 function hasAttribute_IE(element
, attribute
) {
2829 if (attribute
=== 'checked') {
2830 return element
.checked
;
2832 return hasAttribute(element
, attribute
);
2835 GLOBAL
.Element
.Methods
.Simulated
.hasAttribute
=
2836 PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES
?
2837 hasAttribute_IE
: hasAttribute
;
2839 function classNames(element
) {
2840 return new Element
.ClassNames(element
);
2843 var regExpCache
= {};
2844 function getRegExpForClassName(className
) {
2845 if (regExpCache
[className
]) return regExpCache
[className
];
2847 var re
= new RegExp("(^|\\s+)" + className
+ "(\\s+|$)");
2848 regExpCache
[className
] = re
;
2852 function hasClassName(element
, className
) {
2853 if (!(element
= $(element
))) return;
2855 var elementClassName
= element
.className
;
2857 if (elementClassName
.length
=== 0) return false;
2858 if (elementClassName
=== className
) return true;
2860 return getRegExpForClassName(className
).test(elementClassName
);
2863 function addClassName(element
, className
) {
2864 if (!(element
= $(element
))) return;
2866 if (!hasClassName(element
, className
))
2867 element
.className
+= (element
.className
? ' ' : '') + className
;
2872 function removeClassName(element
, className
) {
2873 if (!(element
= $(element
))) return;
2875 element
.className
= element
.className
.replace(
2876 getRegExpForClassName(className
), ' ').strip();
2881 function toggleClassName(element
, className
, bool
) {
2882 if (!(element
= $(element
))) return;
2884 if (Object
.isUndefined(bool
))
2885 bool
= !hasClassName(element
, className
);
2887 var method
= Element
[bool
? 'addClassName' : 'removeClassName'];
2888 return method(element
, className
);
2891 var ATTRIBUTE_TRANSLATIONS
= {};
2893 var classProp
= 'className', forProp
= 'for';
2895 DIV
.setAttribute(classProp
, 'x');
2896 if (DIV
.className
!== 'x') {
2897 DIV
.setAttribute('class', 'x');
2898 if (DIV
.className
=== 'x')
2899 classProp
= 'class';
2902 var LABEL
= document
.createElement('label');
2903 LABEL
.setAttribute(forProp
, 'x');
2904 if (LABEL
.htmlFor
!== 'x') {
2905 LABEL
.setAttribute('htmlFor', 'x');
2906 if (LABEL
.htmlFor
=== 'x')
2907 forProp
= 'htmlFor';
2911 function _getAttr(element
, attribute
) {
2912 return element
.getAttribute(attribute
);
2915 function _getAttr2(element
, attribute
) {
2916 return element
.getAttribute(attribute
, 2);
2919 function _getAttrNode(element
, attribute
) {
2920 var node
= element
.getAttributeNode(attribute
);
2921 return node
? node
.value
: '';
2924 function _getFlag(element
, attribute
) {
2925 return $(element
).hasAttribute(attribute
) ? attribute
: null;
2928 DIV
.onclick
= Prototype
.emptyFunction
;
2929 var onclickValue
= DIV
.getAttribute('onclick');
2933 if (String(onclickValue
).indexOf('{') > -1) {
2934 _getEv = function(element
, attribute
) {
2935 var value
= element
.getAttribute(attribute
);
2936 if (!value
) return null;
2937 value
= value
.toString();
2938 value
= value
.split('{')[1];
2939 value
= value
.split('}')[0];
2940 return value
.strip();
2943 else if (onclickValue
=== '') {
2944 _getEv = function(element
, attribute
) {
2945 var value
= element
.getAttribute(attribute
);
2946 if (!value
) return null;
2947 return value
.strip();
2951 ATTRIBUTE_TRANSLATIONS
.read
= {
2954 'className': classProp
,
2960 style: function(element
) {
2961 return element
.style
.cssText
.toLowerCase();
2963 title: function(element
) {
2964 return element
.title
;
2969 ATTRIBUTE_TRANSLATIONS
.write
= {
2973 cellpadding
: 'cellPadding',
2974 cellspacing
: 'cellSpacing'
2978 checked: function(element
, value
) {
2980 element
.checked
= value
;
2981 return value
? 'checked' : null;
2984 style: function(element
, value
) {
2985 element
.style
.cssText
= value
? value
: '';
2990 ATTRIBUTE_TRANSLATIONS
.has
= { names
: {} };
2992 Object
.extend(ATTRIBUTE_TRANSLATIONS
.write
.names
,
2993 ATTRIBUTE_TRANSLATIONS
.read
.names
);
2995 var CAMEL_CASED_ATTRIBUTE_NAMES
= $w('colSpan rowSpan vAlign dateTime ' +
2996 'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
2998 for (var i
= 0, attr
; attr
= CAMEL_CASED_ATTRIBUTE_NAMES
[i
]; i
++) {
2999 ATTRIBUTE_TRANSLATIONS
.write
.names
[attr
.toLowerCase()] = attr
;
3000 ATTRIBUTE_TRANSLATIONS
.has
.names
[attr
.toLowerCase()] = attr
;
3003 Object
.extend(ATTRIBUTE_TRANSLATIONS
.read
.values
, {
3007 action
: _getAttrNode
,
3016 onmousedown
: _getEv
,
3018 onmouseover
: _getEv
,
3019 onmousemove
: _getEv
,
3033 Object
.extend(methods
, {
3035 readAttribute
: readAttribute
,
3036 writeAttribute
: writeAttribute
,
3037 classNames
: classNames
,
3038 hasClassName
: hasClassName
,
3039 addClassName
: addClassName
,
3040 removeClassName
: removeClassName
,
3041 toggleClassName
: toggleClassName
3045 function normalizeStyleName(style
) {
3046 if (style
=== 'float' || style
=== 'styleFloat')
3048 return style
.camelize();
3051 function normalizeStyleName_IE(style
) {
3052 if (style
=== 'float' || style
=== 'cssFloat')
3053 return 'styleFloat';
3054 return style
.camelize();
3057 function setStyle(element
, styles
) {
3058 element
= $(element
);
3059 var elementStyle
= element
.style
, match
;
3061 if (Object
.isString(styles
)) {
3062 elementStyle
.cssText
+= ';' + styles
;
3063 if (styles
.include('opacity')) {
3064 var opacity
= styles
.match(/opacity:\s*(\d?\.?\d*)/)[1];
3065 Element
.setOpacity(element
, opacity
);
3070 for (var property
in styles
) {
3071 if (property
=== 'opacity') {
3072 Element
.setOpacity(element
, styles
[property
]);
3074 var value
= styles
[property
];
3075 if (property
=== 'float' || property
=== 'cssFloat') {
3076 property
= Object
.isUndefined(elementStyle
.styleFloat
) ?
3077 'cssFloat' : 'styleFloat';
3079 elementStyle
[property
] = value
;
3087 function getStyle(element
, style
) {
3088 element
= $(element
);
3089 style
= normalizeStyleName(style
);
3091 var value
= element
.style
[style
];
3092 if (!value
|| value
=== 'auto') {
3093 var css
= document
.defaultView
.getComputedStyle(element
, null);
3094 value
= css
? css
[style
] : null;
3097 if (style
=== 'opacity') return value
? parseFloat(value
) : 1.0;
3098 return value
=== 'auto' ? null : value
;
3101 function getStyle_Opera(element
, style
) {
3103 case 'height': case 'width':
3104 if (!Element
.visible(element
)) return null;
3106 var dim
= parseInt(getStyle(element
, style
), 10);
3108 if (dim
!== element
['offset' + style
.capitalize()])
3111 return Element
.measure(element
, style
);
3113 default: return getStyle(element
, style
);
3117 function getStyle_IE(element
, style
) {
3118 element
= $(element
);
3119 style
= normalizeStyleName_IE(style
);
3121 var value
= element
.style
[style
];
3122 if (!value
&& element
.currentStyle
) {
3123 value
= element
.currentStyle
[style
];
3126 if (style
=== 'opacity') {
3127 if (!STANDARD_CSS_OPACITY_SUPPORTED
)
3128 return getOpacity_IE(element
);
3129 else return value
? parseFloat(value
) : 1.0;
3132 if (value
=== 'auto') {
3133 if ((style
=== 'width' || style
=== 'height') && Element
.visible(element
))
3134 return Element
.measure(element
, style
) + 'px';
3141 function stripAlphaFromFilter_IE(filter
) {
3142 return (filter
|| '').replace(/alpha\([^\)]*\)/gi, '');
3145 function hasLayout_IE(element
) {
3146 if (!element
.currentStyle
|| !element
.currentStyle
.hasLayout
)
3147 element
.style
.zoom
= 1;
3151 var STANDARD_CSS_OPACITY_SUPPORTED
= (function() {
3152 DIV
.style
.cssText
= "opacity:.55";
3153 return /^0.55/.test(DIV
.style
.opacity
);
3156 function setOpacity(element
, value
) {
3157 element
= $(element
);
3158 if (value
== 1 || value
=== '') value
= '';
3159 else if (value
< 0.00001) value
= 0;
3160 element
.style
.opacity
= value
;
3164 function setOpacity_IE(element
, value
) {
3165 if (STANDARD_CSS_OPACITY_SUPPORTED
)
3166 return setOpacity(element
, value
);
3168 element
= hasLayout_IE($(element
));
3169 var filter
= Element
.getStyle(element
, 'filter'),
3170 style
= element
.style
;
3172 if (value
== 1 || value
=== '') {
3173 filter
= stripAlphaFromFilter_IE(filter
);
3174 if (filter
) style
.filter
= filter
;
3175 else style
.removeAttribute('filter');
3179 if (value
< 0.00001) value
= 0;
3181 style
.filter
= stripAlphaFromFilter_IE(filter
) +
3182 ' alpha(opacity=' + (value
* 100) + ')';
3188 function getOpacity(element
) {
3189 return Element
.getStyle(element
, 'opacity');
3192 function getOpacity_IE(element
) {
3193 if (STANDARD_CSS_OPACITY_SUPPORTED
)
3194 return getOpacity(element
);
3196 var filter
= Element
.getStyle(element
, 'filter');
3197 if (filter
.length
=== 0) return 1.0;
3198 var match
= (filter
|| '').match(/alpha\(opacity=(.*)\)/i);
3199 if (match
&& match
[1]) return parseFloat(match
[1]) / 100;
3204 Object
.extend(methods
, {
3207 setOpacity
: setOpacity
,
3208 getOpacity
: getOpacity
3211 if ('styleFloat' in DIV
.style
) {
3212 methods
.getStyle
= getStyle_IE
;
3213 methods
.setOpacity
= setOpacity_IE
;
3214 methods
.getOpacity
= getOpacity_IE
;
3219 GLOBAL
.Element
.Storage
= { UID
: 1 };
3221 function getUniqueElementID(element
) {
3222 if (element
=== window
) return 0;
3224 if (typeof element
._prototypeUID
=== 'undefined')
3225 element
._prototypeUID
= Element
.Storage
.UID
++;
3226 return element
._prototypeUID
;
3229 function getUniqueElementID_IE(element
) {
3230 if (element
=== window
) return 0;
3231 if (element
== document
) return 1;
3232 return element
.uniqueID
;
3235 var HAS_UNIQUE_ID_PROPERTY
= ('uniqueID' in DIV
);
3236 if (HAS_UNIQUE_ID_PROPERTY
)
3237 getUniqueElementID
= getUniqueElementID_IE
;
3239 function getStorage(element
) {
3240 if (!(element
= $(element
))) return;
3242 var uid
= getUniqueElementID(element
);
3244 if (!Element
.Storage
[uid
])
3245 Element
.Storage
[uid
] = $H();
3247 return Element
.Storage
[uid
];
3250 function store(element
, key
, value
) {
3251 if (!(element
= $(element
))) return;
3252 var storage
= getStorage(element
);
3253 if (arguments
.length
=== 2) {
3254 storage
.update(key
);
3256 storage
.set(key
, value
);
3261 function retrieve(element
, key
, defaultValue
) {
3262 if (!(element
= $(element
))) return;
3263 var storage
= getStorage(element
), value
= storage
.get(key
);
3265 if (Object
.isUndefined(value
)) {
3266 storage
.set(key
, defaultValue
);
3267 value
= defaultValue
;
3274 Object
.extend(methods
, {
3275 getStorage
: getStorage
,
3281 var Methods
= {}, ByTag
= Element
.Methods
.ByTag
,
3282 F
= Prototype
.BrowserFeatures
;
3284 if (!F
.ElementExtensions
&& ('__proto__' in DIV
)) {
3285 GLOBAL
.HTMLElement
= {};
3286 GLOBAL
.HTMLElement
.prototype = DIV
['__proto__'];
3287 F
.ElementExtensions
= true;
3290 function checkElementPrototypeDeficiency(tagName
) {
3291 if (typeof window
.Element
=== 'undefined') return false;
3292 if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
) return false;
3293 var proto
= window
.Element
.prototype;
3295 var id
= '_' + (Math
.random() + '').slice(2),
3296 el
= document
.createElement(tagName
);
3298 var isBuggy
= (el
[id
] !== 'x');
3307 var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY
=
3308 checkElementPrototypeDeficiency('object');
3310 function extendElementWith(element
, methods
) {
3311 for (var property
in methods
) {
3312 var value
= methods
[property
];
3313 if (Object
.isFunction(value
) && !(property
in element
))
3314 element
[property
] = value
.methodize();
3319 function elementIsExtended(element
) {
3320 var uid
= getUniqueElementID(element
);
3321 return (uid
in EXTENDED
);
3324 function extend(element
) {
3325 if (!element
|| elementIsExtended(element
)) return element
;
3326 if (element
.nodeType
!== Node
.ELEMENT_NODE
|| element
== window
)
3329 var methods
= Object
.clone(Methods
),
3330 tagName
= element
.tagName
.toUpperCase();
3332 if (ByTag
[tagName
]) Object
.extend(methods
, ByTag
[tagName
]);
3334 extendElementWith(element
, methods
);
3335 EXTENDED
[getUniqueElementID(element
)] = true;
3339 function extend_IE8(element
) {
3340 if (!element
|| elementIsExtended(element
)) return element
;
3342 var t
= element
.tagName
;
3343 if (t
&& (/^(?:object|applet|embed)$/i.test(t
))) {
3344 extendElementWith(element
, Element
.Methods
);
3345 extendElementWith(element
, Element
.Methods
.Simulated
);
3346 extendElementWith(element
, Element
.Methods
.ByTag
[t
.toUpperCase()]);
3352 if (F
.SpecificElementExtensions
) {
3353 extend
= HTMLOBJECTELEMENT_PROTOTYPE_BUGGY
? extend_IE8
: Prototype
.K
;
3356 function addMethodsToTagName(tagName
, methods
) {
3357 tagName
= tagName
.toUpperCase();
3358 if (!ByTag
[tagName
]) ByTag
[tagName
] = {};
3359 Object
.extend(ByTag
[tagName
], methods
);
3362 function mergeMethods(destination
, methods
, onlyIfAbsent
) {
3363 if (Object
.isUndefined(onlyIfAbsent
)) onlyIfAbsent
= false;
3364 for (var property
in methods
) {
3365 var value
= methods
[property
];
3366 if (!Object
.isFunction(value
)) continue;
3367 if (!onlyIfAbsent
|| !(property
in destination
))
3368 destination
[property
] = value
.methodize();
3372 function findDOMClass(tagName
) {
3375 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3376 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3377 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3378 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3379 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3380 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3381 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3382 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3383 "FrameSet", "IFRAME": "IFrame"
3385 if (trans
[tagName
]) klass
= 'HTML' + trans
[tagName
] + 'Element';
3386 if (window
[klass
]) return window
[klass
];
3387 klass
= 'HTML' + tagName
+ 'Element';
3388 if (window
[klass
]) return window
[klass
];
3389 klass
= 'HTML' + tagName
.capitalize() + 'Element';
3390 if (window
[klass
]) return window
[klass
];
3392 var element
= document
.createElement(tagName
),
3393 proto
= element
['__proto__'] || element
.constructor.prototype;
3399 function addMethods(methods
) {
3400 if (arguments
.length
=== 0) addFormMethods();
3402 if (arguments
.length
=== 2) {
3403 var tagName
= methods
;
3404 methods
= arguments
[1];
3408 Object
.extend(Element
.Methods
, methods
|| {});
3410 if (Object
.isArray(tagName
)) {
3411 for (var i
= 0, tag
; tag
= tagName
[i
]; i
++)
3412 addMethodsToTagName(tag
, methods
);
3414 addMethodsToTagName(tagName
, methods
);
3418 var ELEMENT_PROTOTYPE
= window
.HTMLElement
? HTMLElement
.prototype :
3421 if (F
.ElementExtensions
) {
3422 mergeMethods(ELEMENT_PROTOTYPE
, Element
.Methods
);
3423 mergeMethods(ELEMENT_PROTOTYPE
, Element
.Methods
.Simulated
, true);
3426 if (F
.SpecificElementExtensions
) {
3427 for (var tag
in Element
.Methods
.ByTag
) {
3428 var klass
= findDOMClass(tag
);
3429 if (Object
.isUndefined(klass
)) continue;
3430 mergeMethods(klass
.prototype, ByTag
[tag
]);
3434 Object
.extend(Element
, Element
.Methods
);
3435 Object
.extend(Element
, Element
.Methods
.Simulated
);
3436 delete Element
.ByTag
;
3437 delete Element
.Simulated
;
3439 Element
.extend
.refresh();
3444 Object
.extend(GLOBAL
.Element
, {
3446 addMethods
: addMethods
3449 if (extend
=== Prototype
.K
) {
3450 GLOBAL
.Element
.extend
.refresh
= Prototype
.emptyFunction
;
3452 GLOBAL
.Element
.extend
.refresh = function() {
3453 if (Prototype
.BrowserFeatures
.ElementExtensions
) return;
3454 Object
.extend(Methods
, Element
.Methods
);
3455 Object
.extend(Methods
, Element
.Methods
.Simulated
);
3461 function addFormMethods() {
3462 Object
.extend(Form
, Form
.Methods
);
3463 Object
.extend(Form
.Element
, Form
.Element
.Methods
);
3464 Object
.extend(Element
.Methods
.ByTag
, {
3465 "FORM": Object
.clone(Form
.Methods
),
3466 "INPUT": Object
.clone(Form
.Element
.Methods
),
3467 "SELECT": Object
.clone(Form
.Element
.Methods
),
3468 "TEXTAREA": Object
.clone(Form
.Element
.Methods
),
3469 "BUTTON": Object
.clone(Form
.Element
.Methods
)
3473 Element
.addMethods(methods
);
3475 function destroyCache_IE() {
3477 ELEMENT_CACHE
= null;
3480 if (window
.attachEvent
)
3481 window
.attachEvent('onunload', destroyCache_IE
);
3486 function toDecimal(pctString
) {
3487 var match
= pctString
.match(/^(\d+)%?$/i);
3488 if (!match
) return null;
3489 return (Number(match
[1]) / 100);
3492 function getRawStyle(element
, style
) {
3493 element
= $(element
);
3495 var value
= element
.style
[style
];
3496 if (!value
|| value
=== 'auto') {
3497 var css
= document
.defaultView
.getComputedStyle(element
, null);
3498 value
= css
? css
[style
] : null;
3501 if (style
=== 'opacity') return value
? parseFloat(value
) : 1.0;
3502 return value
=== 'auto' ? null : value
;
3505 function getRawStyle_IE(element
, style
) {
3506 var value
= element
.style
[style
];
3507 if (!value
&& element
.currentStyle
) {
3508 value
= element
.currentStyle
[style
];
3513 function getContentWidth(element
, context
) {
3514 var boxWidth
= element
.offsetWidth
;
3516 var bl
= getPixelValue(element
, 'borderLeftWidth', context
) || 0;
3517 var br
= getPixelValue(element
, 'borderRightWidth', context
) || 0;
3518 var pl
= getPixelValue(element
, 'paddingLeft', context
) || 0;
3519 var pr
= getPixelValue(element
, 'paddingRight', context
) || 0;
3521 return boxWidth
- bl
- br
- pl
- pr
;
3524 if (!Object
.isUndefined(document
.documentElement
.currentStyle
) && !Prototype
.Browser
.Opera
) {
3525 getRawStyle
= getRawStyle_IE
;
3529 function getPixelValue(value
, property
, context
) {
3531 if (Object
.isElement(value
)) {
3533 value
= getRawStyle(element
, property
);
3536 if (value
=== null || Object
.isUndefined(value
)) {
3540 if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value
)) {
3541 return window
.parseFloat(value
);
3544 var isPercentage
= value
.include('%'), isViewport
= (context
=== document
.viewport
);
3546 if (/\d/.test(value
) && element
&& element
.runtimeStyle
&& !(isPercentage
&& isViewport
)) {
3547 var style
= element
.style
.left
, rStyle
= element
.runtimeStyle
.left
;
3548 element
.runtimeStyle
.left
= element
.currentStyle
.left
;
3549 element
.style
.left
= value
|| 0;
3550 value
= element
.style
.pixelLeft
;
3551 element
.style
.left
= style
;
3552 element
.runtimeStyle
.left
= rStyle
;
3557 if (element
&& isPercentage
) {
3558 context
= context
|| element
.parentNode
;
3559 var decimal = toDecimal(value
), whole
= null;
3561 var isHorizontal
= property
.include('left') || property
.include('right') ||
3562 property
.include('width');
3564 var isVertical
= property
.include('top') || property
.include('bottom') ||
3565 property
.include('height');
3567 if (context
=== document
.viewport
) {
3569 whole
= document
.viewport
.getWidth();
3570 } else if (isVertical
) {
3571 whole
= document
.viewport
.getHeight();
3575 whole
= $(context
).measure('width');
3576 } else if (isVertical
) {
3577 whole
= $(context
).measure('height');
3581 return (whole
=== null) ? 0 : whole
* decimal;
3587 function toCSSPixels(number
) {
3588 if (Object
.isString(number
) && number
.endsWith('px'))
3590 return number
+ 'px';
3593 function isDisplayed(element
) {
3594 while (element
&& element
.parentNode
) {
3595 var display
= element
.getStyle('display');
3596 if (display
=== 'none') {
3599 element
= $(element
.parentNode
);
3604 var hasLayout
= Prototype
.K
;
3605 if ('currentStyle' in document
.documentElement
) {
3606 hasLayout = function(element
) {
3607 if (!element
.currentStyle
.hasLayout
) {
3608 element
.style
.zoom
= 1;
3614 function cssNameFor(key
) {
3615 if (key
.include('border')) key
= key
+ '-width';
3616 return key
.camelize();
3619 Element
.Layout
= Class
.create(Hash
, {
3620 initialize: function($super, element
, preCompute
) {
3622 this.element
= $(element
);
3624 Element
.Layout
.PROPERTIES
.each( function(property
) {
3625 this._set(property
, null);
3629 this._preComputing
= true;
3631 Element
.Layout
.PROPERTIES
.each( this._compute
, this );
3633 this._preComputing
= false;
3637 _set: function(property
, value
) {
3638 return Hash
.prototype.set.call(this, property
, value
);
3641 set: function(property
, value
) {
3642 throw "Properties of Element.Layout are read-only.";
3645 get: function($super, property
) {
3646 var value
= $super(property
);
3647 return value
=== null ? this._compute(property
) : value
;
3650 _begin: function() {
3651 if (this._isPrepared()) return;
3653 var element
= this.element
;
3654 if (isDisplayed(element
)) {
3655 this._setPrepared(true);
3660 var originalStyles
= {
3661 position
: element
.style
.position
|| '',
3662 width
: element
.style
.width
|| '',
3663 visibility
: element
.style
.visibility
|| '',
3664 display
: element
.style
.display
|| ''
3667 element
.store('prototype_original_styles', originalStyles
);
3669 var position
= getRawStyle(element
, 'position'), width
= element
.offsetWidth
;
3671 if (width
=== 0 || width
=== null) {
3672 element
.style
.display
= 'block';
3673 width
= element
.offsetWidth
;
3676 var context
= (position
=== 'fixed') ? document
.viewport
:
3680 visibility
: 'hidden',
3684 if (position
!== 'fixed') tempStyles
.position
= 'absolute';
3686 element
.setStyle(tempStyles
);
3688 var positionedWidth
= element
.offsetWidth
, newWidth
;
3689 if (width
&& (positionedWidth
=== width
)) {
3690 newWidth
= getContentWidth(element
, context
);
3691 } else if (position
=== 'absolute' || position
=== 'fixed') {
3692 newWidth
= getContentWidth(element
, context
);
3694 var parent
= element
.parentNode
, pLayout
= $(parent
).getLayout();
3696 newWidth
= pLayout
.get('width') -
3697 this.get('margin-left') -
3698 this.get('border-left') -
3699 this.get('padding-left') -
3700 this.get('padding-right') -
3701 this.get('border-right') -
3702 this.get('margin-right');
3705 element
.setStyle({ width
: newWidth
+ 'px' });
3707 this._setPrepared(true);
3711 var element
= this.element
;
3712 var originalStyles
= element
.retrieve('prototype_original_styles');
3713 element
.store('prototype_original_styles', null);
3714 element
.setStyle(originalStyles
);
3715 this._setPrepared(false);
3718 _compute: function(property
) {
3719 var COMPUTATIONS
= Element
.Layout
.COMPUTATIONS
;
3720 if (!(property
in COMPUTATIONS
)) {
3721 throw "Property not found.";
3724 return this._set(property
, COMPUTATIONS
[property
].call(this, this.element
));
3727 _isPrepared: function() {
3728 return this.element
.retrieve('prototype_element_layout_prepared', false);
3731 _setPrepared: function(bool
) {
3732 return this.element
.store('prototype_element_layout_prepared', bool
);
3735 toObject: function() {
3736 var args
= $A(arguments
);
3737 var keys
= (args
.length
=== 0) ? Element
.Layout
.PROPERTIES
:
3738 args
.join(' ').split(' ');
3740 keys
.each( function(key
) {
3741 if (!Element
.Layout
.PROPERTIES
.include(key
)) return;
3742 var value
= this.get(key
);
3743 if (value
!= null) obj
[key
] = value
;
3748 toHash: function() {
3749 var obj
= this.toObject
.apply(this, arguments
);
3750 return new Hash(obj
);
3754 var args
= $A(arguments
);
3755 var keys
= (args
.length
=== 0) ? Element
.Layout
.PROPERTIES
:
3756 args
.join(' ').split(' ');
3759 keys
.each( function(key
) {
3760 if (!Element
.Layout
.PROPERTIES
.include(key
)) return;
3761 if (Element
.Layout
.COMPOSITE_PROPERTIES
.include(key
)) return;
3763 var value
= this.get(key
);
3764 if (value
!= null) css
[cssNameFor(key
)] = value
+ 'px';
3769 inspect: function() {
3770 return "#<Element.Layout>";
3774 Object
.extend(Element
.Layout
, {
3775 PROPERTIES
: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
3777 COMPOSITE_PROPERTIES
: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3780 'height': function(element
) {
3781 if (!this._preComputing
) this._begin();
3783 var bHeight
= this.get('border-box-height');
3785 if (!this._preComputing
) this._end();
3789 var bTop
= this.get('border-top'),
3790 bBottom
= this.get('border-bottom');
3792 var pTop
= this.get('padding-top'),
3793 pBottom
= this.get('padding-bottom');
3795 if (!this._preComputing
) this._end();
3797 return bHeight
- bTop
- bBottom
- pTop
- pBottom
;
3800 'width': function(element
) {
3801 if (!this._preComputing
) this._begin();
3803 var bWidth
= this.get('border-box-width');
3805 if (!this._preComputing
) this._end();
3809 var bLeft
= this.get('border-left'),
3810 bRight
= this.get('border-right');
3812 var pLeft
= this.get('padding-left'),
3813 pRight
= this.get('padding-right');
3815 if (!this._preComputing
) this._end();
3816 return bWidth
- bLeft
- bRight
- pLeft
- pRight
;
3819 'padding-box-height': function(element
) {
3820 var height
= this.get('height'),
3821 pTop
= this.get('padding-top'),
3822 pBottom
= this.get('padding-bottom');
3824 return height
+ pTop
+ pBottom
;
3827 'padding-box-width': function(element
) {
3828 var width
= this.get('width'),
3829 pLeft
= this.get('padding-left'),
3830 pRight
= this.get('padding-right');
3832 return width
+ pLeft
+ pRight
;
3835 'border-box-height': function(element
) {
3836 if (!this._preComputing
) this._begin();
3837 var height
= element
.offsetHeight
;
3838 if (!this._preComputing
) this._end();
3842 'border-box-width': function(element
) {
3843 if (!this._preComputing
) this._begin();
3844 var width
= element
.offsetWidth
;
3845 if (!this._preComputing
) this._end();
3849 'margin-box-height': function(element
) {
3850 var bHeight
= this.get('border-box-height'),
3851 mTop
= this.get('margin-top'),
3852 mBottom
= this.get('margin-bottom');
3854 if (bHeight
<= 0) return 0;
3856 return bHeight
+ mTop
+ mBottom
;
3859 'margin-box-width': function(element
) {
3860 var bWidth
= this.get('border-box-width'),
3861 mLeft
= this.get('margin-left'),
3862 mRight
= this.get('margin-right');
3864 if (bWidth
<= 0) return 0;
3866 return bWidth
+ mLeft
+ mRight
;
3869 'top': function(element
) {
3870 var offset
= element
.positionedOffset();
3874 'bottom': function(element
) {
3875 var offset
= element
.positionedOffset(),
3876 parent
= element
.getOffsetParent(),
3877 pHeight
= parent
.measure('height');
3879 var mHeight
= this.get('border-box-height');
3881 return pHeight
- mHeight
- offset
.top
;
3884 'left': function(element
) {
3885 var offset
= element
.positionedOffset();
3889 'right': function(element
) {
3890 var offset
= element
.positionedOffset(),
3891 parent
= element
.getOffsetParent(),
3892 pWidth
= parent
.measure('width');
3894 var mWidth
= this.get('border-box-width');
3896 return pWidth
- mWidth
- offset
.left
;
3899 'padding-top': function(element
) {
3900 return getPixelValue(element
, 'paddingTop');
3903 'padding-bottom': function(element
) {
3904 return getPixelValue(element
, 'paddingBottom');
3907 'padding-left': function(element
) {
3908 return getPixelValue(element
, 'paddingLeft');
3911 'padding-right': function(element
) {
3912 return getPixelValue(element
, 'paddingRight');
3915 'border-top': function(element
) {
3916 return getPixelValue(element
, 'borderTopWidth');
3919 'border-bottom': function(element
) {
3920 return getPixelValue(element
, 'borderBottomWidth');
3923 'border-left': function(element
) {
3924 return getPixelValue(element
, 'borderLeftWidth');
3927 'border-right': function(element
) {
3928 return getPixelValue(element
, 'borderRightWidth');
3931 'margin-top': function(element
) {
3932 return getPixelValue(element
, 'marginTop');
3935 'margin-bottom': function(element
) {
3936 return getPixelValue(element
, 'marginBottom');
3939 'margin-left': function(element
) {
3940 return getPixelValue(element
, 'marginLeft');
3943 'margin-right': function(element
) {
3944 return getPixelValue(element
, 'marginRight');
3949 if ('getBoundingClientRect' in document
.documentElement
) {
3950 Object
.extend(Element
.Layout
.COMPUTATIONS
, {
3951 'right': function(element
) {
3952 var parent
= hasLayout(element
.getOffsetParent());
3953 var rect
= element
.getBoundingClientRect(),
3954 pRect
= parent
.getBoundingClientRect();
3956 return (pRect
.right
- rect
.right
).round();
3959 'bottom': function(element
) {
3960 var parent
= hasLayout(element
.getOffsetParent());
3961 var rect
= element
.getBoundingClientRect(),
3962 pRect
= parent
.getBoundingClientRect();
3964 return (pRect
.bottom
- rect
.bottom
).round();
3969 Element
.Offset
= Class
.create({
3970 initialize: function(left
, top
) {
3971 this.left
= left
.round();
3972 this.top
= top
.round();
3974 this[0] = this.left
;
3978 relativeTo: function(offset
) {
3979 return new Element
.Offset(
3980 this.left
- offset
.left
,
3981 this.top
- offset
.top
3985 inspect: function() {
3986 return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3989 toString: function() {
3990 return "[#{left}, #{top}]".interpolate(this);
3993 toArray: function() {
3994 return [this.left
, this.top
];
3998 function getLayout(element
, preCompute
) {
3999 return new Element
.Layout(element
, preCompute
);
4002 function measure(element
, property
) {
4003 return $(element
).getLayout().get(property
);
4006 function getHeight(element
) {
4007 return Element
.getDimensions(element
).height
;
4010 function getWidth(element
) {
4011 return Element
.getDimensions(element
).width
;
4014 function getDimensions(element
) {
4015 element
= $(element
);
4016 var display
= Element
.getStyle(element
, 'display');
4018 if (display
&& display
!== 'none') {
4019 return { width
: element
.offsetWidth
, height
: element
.offsetHeight
};
4022 var style
= element
.style
;
4023 var originalStyles
= {
4024 visibility
: style
.visibility
,
4025 position
: style
.position
,
4026 display
: style
.display
4030 visibility
: 'hidden',
4034 if (originalStyles
.position
!== 'fixed')
4035 newStyles
.position
= 'absolute';
4037 Element
.setStyle(element
, newStyles
);
4040 width
: element
.offsetWidth
,
4041 height
: element
.offsetHeight
4044 Element
.setStyle(element
, originalStyles
);
4049 function getOffsetParent(element
) {
4050 element
= $(element
);
4052 function selfOrBody(element
) {
4053 return isHtml(element
) ? $(document
.body
) : $(element
);
4056 if (isDocument(element
) || isDetached(element
) || isBody(element
) || isHtml(element
))
4057 return $(document
.body
);
4059 var isInline
= (Element
.getStyle(element
, 'display') === 'inline');
4060 if (!isInline
&& element
.offsetParent
) return selfOrBody(element
.offsetParent
);
4062 while ((element
= element
.parentNode
) && element
!== document
.body
) {
4063 if (Element
.getStyle(element
, 'position') !== 'static') {
4064 return selfOrBody(element
);
4068 return $(document
.body
);
4072 function cumulativeOffset(element
) {
4073 element
= $(element
);
4074 var valueT
= 0, valueL
= 0;
4075 if (element
.parentNode
) {
4077 valueT
+= element
.offsetTop
|| 0;
4078 valueL
+= element
.offsetLeft
|| 0;
4079 element
= element
.offsetParent
;
4082 return new Element
.Offset(valueL
, valueT
);
4085 function positionedOffset(element
) {
4086 element
= $(element
);
4088 var layout
= element
.getLayout();
4090 var valueT
= 0, valueL
= 0;
4092 valueT
+= element
.offsetTop
|| 0;
4093 valueL
+= element
.offsetLeft
|| 0;
4094 element
= element
.offsetParent
;
4096 if (isBody(element
)) break;
4097 var p
= Element
.getStyle(element
, 'position');
4098 if (p
!== 'static') break;
4102 valueL
-= layout
.get('margin-left');
4103 valueT
-= layout
.get('margin-top');
4105 return new Element
.Offset(valueL
, valueT
);
4108 function cumulativeScrollOffset(element
) {
4109 var valueT
= 0, valueL
= 0;
4111 if (element
=== document
.body
) {
4112 var bodyScrollNode
= document
.documentElement
|| document
.body
.parentNode
|| document
.body
;
4113 valueT
+= !Object
.isUndefined(window
.pageYOffset
) ? window
.pageYOffset
: bodyScrollNode
.scrollTop
|| 0;
4114 valueL
+= !Object
.isUndefined(window
.pageXOffset
) ? window
.pageXOffset
: bodyScrollNode
.scrollLeft
|| 0;
4117 valueT
+= element
.scrollTop
|| 0;
4118 valueL
+= element
.scrollLeft
|| 0;
4119 element
= element
.parentNode
;
4122 return new Element
.Offset(valueL
, valueT
);
4125 function viewportOffset(forElement
) {
4126 var valueT
= 0, valueL
= 0, docBody
= document
.body
;
4128 forElement
= $(forElement
);
4129 var element
= forElement
;
4131 valueT
+= element
.offsetTop
|| 0;
4132 valueL
+= element
.offsetLeft
|| 0;
4133 if (element
.offsetParent
== docBody
&&
4134 Element
.getStyle(element
, 'position') == 'absolute') break;
4135 } while (element
= element
.offsetParent
);
4137 element
= forElement
;
4139 if (element
!= docBody
) {
4140 valueT
-= element
.scrollTop
|| 0;
4141 valueL
-= element
.scrollLeft
|| 0;
4143 } while (element
= element
.parentNode
);
4144 return new Element
.Offset(valueL
, valueT
);
4147 function absolutize(element
) {
4148 element
= $(element
);
4150 if (Element
.getStyle(element
, 'position') === 'absolute') {
4154 var offsetParent
= getOffsetParent(element
);
4155 var eOffset
= element
.viewportOffset(),
4156 pOffset
= offsetParent
.viewportOffset();
4158 var offset
= eOffset
.relativeTo(pOffset
);
4159 var layout
= element
.getLayout();
4161 element
.store('prototype_absolutize_original_styles', {
4162 position
: element
.getStyle('position'),
4163 left
: element
.getStyle('left'),
4164 top
: element
.getStyle('top'),
4165 width
: element
.getStyle('width'),
4166 height
: element
.getStyle('height')
4170 position
: 'absolute',
4171 top
: offset
.top
+ 'px',
4172 left
: offset
.left
+ 'px',
4173 width
: layout
.get('width') + 'px',
4174 height
: layout
.get('height') + 'px'
4180 function relativize(element
) {
4181 element
= $(element
);
4182 if (Element
.getStyle(element
, 'position') === 'relative') {
4186 var originalStyles
=
4187 element
.retrieve('prototype_absolutize_original_styles');
4189 if (originalStyles
) element
.setStyle(originalStyles
);
4194 function scrollTo(element
) {
4195 element
= $(element
);
4196 var pos
= Element
.cumulativeOffset(element
);
4197 window
.scrollTo(pos
.left
, pos
.top
);
4202 function makePositioned(element
) {
4203 element
= $(element
);
4204 var position
= Element
.getStyle(element
, 'position'), styles
= {};
4205 if (position
=== 'static' || !position
) {
4206 styles
.position
= 'relative';
4207 if (Prototype
.Browser
.Opera
) {
4211 Element
.setStyle(element
, styles
);
4212 Element
.store(element
, 'prototype_made_positioned', true);
4217 function undoPositioned(element
) {
4218 element
= $(element
);
4219 var storage
= Element
.getStorage(element
),
4220 madePositioned
= storage
.get('prototype_made_positioned');
4222 if (madePositioned
) {
4223 storage
.unset('prototype_made_positioned');
4224 Element
.setStyle(element
, {
4235 function makeClipping(element
) {
4236 element
= $(element
);
4238 var storage
= Element
.getStorage(element
),
4239 madeClipping
= storage
.get('prototype_made_clipping');
4241 if (Object
.isUndefined(madeClipping
)) {
4242 var overflow
= Element
.getStyle(element
, 'overflow');
4243 storage
.set('prototype_made_clipping', overflow
);
4244 if (overflow
!== 'hidden')
4245 element
.style
.overflow
= 'hidden';
4251 function undoClipping(element
) {
4252 element
= $(element
);
4253 var storage
= Element
.getStorage(element
),
4254 overflow
= storage
.get('prototype_made_clipping');
4256 if (!Object
.isUndefined(overflow
)) {
4257 storage
.unset('prototype_made_clipping');
4258 element
.style
.overflow
= overflow
|| '';
4264 function clonePosition(element
, source
, options
) {
4265 options
= Object
.extend({
4274 var docEl
= document
.documentElement
;
4277 element
= $(element
);
4278 var p
, delta
, layout
, styles
= {};
4280 if (options
.setLeft
|| options
.setTop
) {
4281 p
= Element
.viewportOffset(source
);
4283 if (Element
.getStyle(element
, 'position') === 'absolute') {
4284 var parent
= Element
.getOffsetParent(element
);
4285 if (parent
!== document
.body
) delta
= Element
.viewportOffset(parent
);
4289 function pageScrollXY() {
4291 if (Object
.isNumber(window
.pageXOffset
)) {
4292 x
= window
.pageXOffset
;
4293 y
= window
.pageYOffset
;
4294 } else if (document
.body
&& (document
.body
.scrollLeft
|| document
.body
.scrollTop
)) {
4295 x
= document
.body
.scrollLeft
;
4296 y
= document
.body
.scrollTop
;
4297 } else if (docEl
&& (docEl
.scrollLeft
|| docEl
.scrollTop
)) {
4298 x
= docEl
.scrollLeft
;
4299 y
= docEl
.scrollTop
;
4301 return { x
: x
, y
: y
};
4304 var pageXY
= pageScrollXY();
4307 if (options
.setWidth
|| options
.setHeight
) {
4308 layout
= Element
.getLayout(source
);
4311 if (options
.setLeft
)
4312 styles
.left
= (p
[0] + pageXY
.x
- delta
[0] + options
.offsetLeft
) + 'px';
4314 styles
.top
= (p
[1] + pageXY
.y
- delta
[1] + options
.offsetTop
) + 'px';
4316 var currentLayout
= element
.getLayout();
4318 if (options
.setWidth
) {
4319 styles
.width
= layout
.get('width') + 'px';
4321 if (options
.setHeight
) {
4322 styles
.height
= layout
.get('height') + 'px';
4325 return Element
.setStyle(element
, styles
);
4329 if (Prototype
.Browser
.IE
) {
4330 getOffsetParent
= getOffsetParent
.wrap(
4331 function(proceed
, element
) {
4332 element
= $(element
);
4334 if (isDocument(element
) || isDetached(element
) || isBody(element
) || isHtml(element
))
4335 return $(document
.body
);
4337 var position
= element
.getStyle('position');
4338 if (position
!== 'static') return proceed(element
);
4340 element
.setStyle({ position
: 'relative' });
4341 var value
= proceed(element
);
4342 element
.setStyle({ position
: position
});
4347 positionedOffset
= positionedOffset
.wrap(function(proceed
, element
) {
4348 element
= $(element
);
4349 if (!element
.parentNode
) return new Element
.Offset(0, 0);
4350 var position
= element
.getStyle('position');
4351 if (position
!== 'static') return proceed(element
);
4353 var offsetParent
= element
.getOffsetParent();
4354 if (offsetParent
&& offsetParent
.getStyle('position') === 'fixed')
4355 hasLayout(offsetParent
);
4357 element
.setStyle({ position
: 'relative' });
4358 var value
= proceed(element
);
4359 element
.setStyle({ position
: position
});
4362 } else if (Prototype
.Browser
.Webkit
) {
4363 cumulativeOffset = function(element
) {
4364 element
= $(element
);
4365 var valueT
= 0, valueL
= 0;
4367 valueT
+= element
.offsetTop
|| 0;
4368 valueL
+= element
.offsetLeft
|| 0;
4369 if (element
.offsetParent
== document
.body
) {
4370 if (Element
.getStyle(element
, 'position') == 'absolute') break;
4373 element
= element
.offsetParent
;
4376 return new Element
.Offset(valueL
, valueT
);
4381 Element
.addMethods({
4382 getLayout
: getLayout
,
4385 getHeight
: getHeight
,
4386 getDimensions
: getDimensions
,
4387 getOffsetParent
: getOffsetParent
,
4388 cumulativeOffset
: cumulativeOffset
,
4389 positionedOffset
: positionedOffset
,
4390 cumulativeScrollOffset
: cumulativeScrollOffset
,
4391 viewportOffset
: viewportOffset
,
4392 absolutize
: absolutize
,
4393 relativize
: relativize
,
4395 makePositioned
: makePositioned
,
4396 undoPositioned
: undoPositioned
,
4397 makeClipping
: makeClipping
,
4398 undoClipping
: undoClipping
,
4399 clonePosition
: clonePosition
4402 function isBody(element
) {
4403 return element
.nodeName
.toUpperCase() === 'BODY';
4406 function isHtml(element
) {
4407 return element
.nodeName
.toUpperCase() === 'HTML';
4410 function isDocument(element
) {
4411 return element
.nodeType
=== Node
.DOCUMENT_NODE
;
4414 function isDetached(element
) {
4415 return element
!== document
.body
&&
4416 !Element
.descendantOf(element
, document
.body
);
4419 if ('getBoundingClientRect' in document
.documentElement
) {
4420 Element
.addMethods({
4421 viewportOffset: function(element
) {
4422 element
= $(element
);
4423 if (isDetached(element
)) return new Element
.Offset(0, 0);
4425 var rect
= element
.getBoundingClientRect(),
4426 docEl
= document
.documentElement
;
4427 return new Element
.Offset(rect
.left
- docEl
.clientLeft
,
4428 rect
.top
- docEl
.clientTop
);
4438 var IS_OLD_OPERA
= Prototype
.Browser
.Opera
&&
4439 (window
.parseFloat(window
.opera
.version()) < 9.5);
4441 function getRootElement() {
4442 if (ROOT
) return ROOT
;
4443 ROOT
= IS_OLD_OPERA
? document
.body
: document
.documentElement
;
4447 function getDimensions() {
4448 return { width
: this.getWidth(), height
: this.getHeight() };
4451 function getWidth() {
4452 return getRootElement().clientWidth
;
4455 function getHeight() {
4456 return getRootElement().clientHeight
;
4459 function getScrollOffsets() {
4460 var x
= window
.pageXOffset
|| document
.documentElement
.scrollLeft
||
4461 document
.body
.scrollLeft
;
4462 var y
= window
.pageYOffset
|| document
.documentElement
.scrollTop
||
4463 document
.body
.scrollTop
;
4465 return new Element
.Offset(x
, y
);
4468 document
.viewport
= {
4469 getDimensions
: getDimensions
,
4471 getHeight
: getHeight
,
4472 getScrollOffsets
: getScrollOffsets
4476 window
.$$ = function() {
4477 var expression
= $A(arguments
).join(', ');
4478 return Prototype
.Selector
.select(expression
, document
);
4481 Prototype
.Selector
= (function() {
4484 throw new Error('Method "Prototype.Selector.select" must be defined.');
4488 throw new Error('Method "Prototype.Selector.match" must be defined.');
4491 function find(elements
, expression
, index
) {
4493 var match
= Prototype
.Selector
.match
, length
= elements
.length
, matchIndex
= 0, i
;
4495 for (i
= 0; i
< length
; i
++) {
4496 if (match(elements
[i
], expression
) && index
== matchIndex
++) {
4497 return Element
.extend(elements
[i
]);
4502 function extendElements(elements
) {
4503 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
4504 Element
.extend(elements
[i
]);
4510 var K
= Prototype
.K
;
4516 extendElements
: (Element
.extend
=== K
) ? K
: extendElements
,
4517 extendElement
: Element
.extend
4520 Prototype
._original_property
= window
.Sizzle
;
4523 function fakeDefine(fn
) {
4524 Prototype
._actual_sizzle
= fn();
4526 fakeDefine
.amd
= true;
4528 if (typeof define
!== 'undefined' && define
.amd
) {
4529 Prototype
._original_define
= define
;
4530 Prototype
._actual_sizzle
= null;
4531 window
.define
= fakeDefine
;
4536 * Sizzle CSS Selector Engine v1.10.18
4537 * http://sizzlejs.com/
4539 * Copyright 2013 jQuery Foundation, Inc. and other contributors
4540 * Released under the MIT license
4541 * http://jquery.org/license
4545 (function( window
) {
4567 expando
= "sizzle" + -(new Date()),
4568 preferredDoc
= window
.document
,
4571 classCache
= createCache(),
4572 tokenCache
= createCache(),
4573 compilerCache
= createCache(),
4574 sortOrder = function( a
, b
) {
4576 hasDuplicate
= true;
4581 strundefined
= typeof undefined,
4582 MAX_NEGATIVE
= 1 << 31,
4584 hasOwn
= ({}).hasOwnProperty
,
4587 push_native
= arr
.push
,
4590 indexOf
= arr
.indexOf
|| function( elem
) {
4593 for ( ; i
< len
; i
++ ) {
4594 if ( this[i
] === elem
) {
4601 booleans
= "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
4604 whitespace
= "[\\x20\\t\\r\\n\\f]",
4605 characterEncoding
= "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
4607 identifier
= characterEncoding
.replace( "w", "w#" ),
4609 attributes
= "\\[" + whitespace
+ "*(" + characterEncoding
+ ")" + whitespace
+
4610 "*(?:([*^$|!~]?=)" + whitespace
+ "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier
+ ")|)|)" + whitespace
+ "*\\]",
4612 pseudos
= ":(" + characterEncoding
+ ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes
.replace( 3, 8 ) + ")*)|.*)\\)|)",
4614 rtrim
= new RegExp( "^" + whitespace
+ "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace
+ "+$", "g" ),
4616 rcomma
= new RegExp( "^" + whitespace
+ "*," + whitespace
+ "*" ),
4617 rcombinators
= new RegExp( "^" + whitespace
+ "*([>+~]|" + whitespace
+ ")" + whitespace
+ "*" ),
4619 rattributeQuotes
= new RegExp( "=" + whitespace
+ "*([^\\]'\"]*?)" + whitespace
+ "*\\]", "g" ),
4621 rpseudo
= new RegExp( pseudos
),
4622 ridentifier
= new RegExp( "^" + identifier
+ "$" ),
4625 "ID": new RegExp( "^#(" + characterEncoding
+ ")" ),
4626 "CLASS": new RegExp( "^\\.(" + characterEncoding
+ ")" ),
4627 "TAG": new RegExp( "^(" + characterEncoding
.replace( "w", "w*" ) + ")" ),
4628 "ATTR": new RegExp( "^" + attributes
),
4629 "PSEUDO": new RegExp( "^" + pseudos
),
4630 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace
+
4631 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace
+ "*(?:([+-]|)" + whitespace
+
4632 "*(\\d+)|))" + whitespace
+ "*\\)|)", "i" ),
4633 "bool": new RegExp( "^(?:" + booleans
+ ")$", "i" ),
4634 "needsContext": new RegExp( "^" + whitespace
+ "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
4635 whitespace
+ "*((?:-\\d)?\\d*)" + whitespace
+ "*\\)|)(?=[^-]|$)", "i" )
4638 rinputs
= /^(?:input|select|textarea|button)$/i,
4641 rnative
= /^[^{]+\{\s*\[native \w/,
4643 rquickExpr
= /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
4648 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
4649 funescape = function( _, escaped, escapedWhitespace ) {
4650 var high = "0x" + escaped - 0x10000;
4651 return high !== high || escapedWhitespace ?
4654 String.fromCharCode( high + 0x10000 ) :
4655 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
4660 (arr = slice.call( preferredDoc.childNodes )),
4661 preferredDoc.childNodes
4663 arr[ preferredDoc.childNodes.length ].nodeType;
4665 push = { apply: arr.length ?
4667 function( target, els ) {
4668 push_native.apply( target, slice.call(els) );
4671 function( target, els ) {
4672 var j = target.length,
4674 while ( (target[j++] = els[i++]) ) {}
4675 target.length = j - 1;
4680 function Sizzle( selector, context, results, seed ) {
4681 var match, elem, m, nodeType,
4682 i, groups, old, nid, newContext, newSelector;
4684 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
4685 setDocument( context );
4688 context = context || document;
4689 results = results || [];
4691 if ( !selector || typeof selector !== "string" ) {
4695 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
4699 if ( documentIsHTML && !seed ) {
4701 if ( (match = rquickExpr.exec( selector )) ) {
4702 if ( (m = match[1]) ) {
4703 if ( nodeType === 9 ) {
4704 elem = context.getElementById( m );
4705 if ( elem && elem.parentNode ) {
4706 if ( elem.id === m ) {
4707 results.push( elem );
4714 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
4715 contains( context, elem ) && elem.id === m ) {
4716 results.push( elem );
4721 } else if ( match[2] ) {
4722 push.apply( results, context.getElementsByTagName( selector ) );
4725 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
4726 push.apply( results, context.getElementsByClassName( m ) );
4731 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
4732 nid = old = expando;
4733 newContext = context;
4734 newSelector = nodeType === 9 && selector;
4736 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
4737 groups = tokenize( selector );
4739 if ( (old = context.getAttribute("id")) ) {
4740 nid = old.replace( rescape, "\\$&" );
4742 context.setAttribute( "id", nid );
4744 nid = "[id='" + nid + "'] ";
4748 groups[i] = nid + toSelector( groups[i] );
4750 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
4751 newSelector = groups.join(",");
4754 if ( newSelector ) {
4756 push.apply( results,
4757 newContext.querySelectorAll( newSelector )
4763 context.removeAttribute("id");
4770 return select( selector.replace( rtrim, "$1" ), context, results, seed );
4774 * Create key-value caches of limited size
4775 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
4776 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
4777 * deleting the oldest entry
4779 function createCache() {
4782 function cache( key, value ) {
4783 if ( keys.push( key + " " ) > Expr.cacheLength ) {
4784 delete cache[ keys.shift() ];
4786 return (cache[ key + " " ] = value);
4792 * Mark a function for special use by Sizzle
4793 * @param {Function} fn The function to mark
4795 function markFunction( fn ) {
4796 fn[ expando ] = true;
4801 * Support testing using an element
4802 * @param {Function} fn Passed the created div and expects a boolean result
4804 function assert( fn ) {
4805 var div = document.createElement("div");
4812 if ( div.parentNode ) {
4813 div.parentNode.removeChild( div );
4820 * Adds the same handler for all of the specified attrs
4821 * @param {String} attrs Pipe-separated list of attributes
4822 * @param {Function} handler The method that will be applied
4824 function addHandle( attrs, handler ) {
4825 var arr = attrs.split("|"),
4829 Expr.attrHandle[ arr[i] ] = handler;
4834 * Checks document order of two siblings
4835 * @param {Element} a
4836 * @param {Element} b
4837 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
4839 function siblingCheck( a, b ) {
4841 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
4842 ( ~b.sourceIndex || MAX_NEGATIVE ) -
4843 ( ~a.sourceIndex || MAX_NEGATIVE );
4850 while ( (cur = cur.nextSibling) ) {
4861 * Returns a function to use in pseudos for input types
4862 * @param {String} type
4864 function createInputPseudo( type ) {
4865 return function( elem ) {
4866 var name = elem.nodeName.toLowerCase();
4867 return name === "input" && elem.type === type;
4872 * Returns a function to use in pseudos for buttons
4873 * @param {String} type
4875 function createButtonPseudo( type ) {
4876 return function( elem ) {
4877 var name = elem.nodeName.toLowerCase();
4878 return (name === "input" || name === "button") && elem.type === type;
4883 * Returns a function to use in pseudos for positionals
4884 * @param {Function} fn
4886 function createPositionalPseudo( fn ) {
4887 return markFunction(function( argument ) {
4888 argument = +argument;
4889 return markFunction(function( seed, matches ) {
4891 matchIndexes = fn( [], seed.length, argument ),
4892 i = matchIndexes.length;
4895 if ( seed[ (j = matchIndexes[i]) ] ) {
4896 seed[j] = !(matches[j] = seed[j]);
4904 * Checks a node for validity as a Sizzle context
4905 * @param {Element|Object=} context
4906 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
4908 function testContext( context ) {
4909 return context && typeof context.getElementsByTagName !== strundefined && context;
4912 support = Sizzle.support = {};
4916 * @param {Element|Object} elem An element or a document
4917 * @returns {Boolean} True iff elem is a non-HTML XML node
4919 isXML = Sizzle.isXML = function( elem ) {
4920 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4921 return documentElement ? documentElement.nodeName !== "HTML" : false;
4925 * Sets document-related variables once based on the current document
4926 * @param {Element|Object} [doc] An element or document object to use to set the document
4927 * @returns {Object} Returns the current document
4929 setDocument = Sizzle.setDocument = function( node ) {
4931 doc = node ? node.ownerDocument || node : preferredDoc,
4932 parent = doc.defaultView;
4934 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4939 docElem = doc.documentElement;
4941 documentIsHTML = !isXML( doc );
4943 if ( parent && parent !== parent.top ) {
4944 if ( parent.addEventListener ) {
4945 parent.addEventListener( "unload", function() {
4948 } else if ( parent.attachEvent ) {
4949 parent.attachEvent( "onunload", function() {
4956 ---------------------------------------------------------------------- */
4958 support.attributes = assert(function( div ) {
4959 div.className = "i";
4960 return !div.getAttribute("className");
4964 ---------------------------------------------------------------------- */
4966 support.getElementsByTagName = assert(function( div ) {
4967 div.appendChild( doc.createComment("") );
4968 return !div.getElementsByTagName("*").length;
4971 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
4972 div.innerHTML = "<div class='a
'></div><div class='a i
'></div>";
4974 div.firstChild.className = "i";
4975 return div.getElementsByClassName("i").length === 2;
4978 support.getById = assert(function( div ) {
4979 docElem.appendChild( div ).id = expando;
4980 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
4983 if ( support.getById ) {
4984 Expr.find["ID"] = function( id, context ) {
4985 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
4986 var m = context.getElementById( id );
4987 return m && m.parentNode ? [m] : [];
4990 Expr.filter["ID"] = function( id ) {
4991 var attrId = id.replace( runescape, funescape );
4992 return function( elem ) {
4993 return elem.getAttribute("id") === attrId;
4997 delete Expr.find["ID"];
4999 Expr.filter["ID"] = function( id ) {
5000 var attrId = id.replace( runescape, funescape );
5001 return function( elem ) {
5002 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
5003 return node && node.value === attrId;
5008 Expr.find["TAG"] = support.getElementsByTagName ?
5009 function( tag, context ) {
5010 if ( typeof context.getElementsByTagName !== strundefined ) {
5011 return context.getElementsByTagName( tag );
5014 function( tag, context ) {
5018 results = context.getElementsByTagName( tag );
5020 if ( tag === "*" ) {
5021 while ( (elem = results[i++]) ) {
5022 if ( elem.nodeType === 1 ) {
5032 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
5033 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
5034 return context.getElementsByClassName( className );
5038 /* QSA/matchesSelector
5039 ---------------------------------------------------------------------- */
5046 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
5047 assert(function( div ) {
5048 div.innerHTML = "<select t=''><option selected=''></option></select>";
5050 if ( div.querySelectorAll("[t^='']").length ) {
5051 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
5054 if ( !div.querySelectorAll("[selected]").length ) {
5055 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
5058 if ( !div.querySelectorAll(":checked").length ) {
5059 rbuggyQSA.push(":checked");
5063 assert(function( div ) {
5064 var input = doc.createElement("input");
5065 input.setAttribute( "type", "hidden" );
5066 div.appendChild( input ).setAttribute( "name", "D" );
5068 if ( div.querySelectorAll("[name=d]").length ) {
5069 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
5072 if ( !div.querySelectorAll(":enabled").length ) {
5073 rbuggyQSA.push( ":enabled", ":disabled" );
5076 div.querySelectorAll("*,:x");
5077 rbuggyQSA.push(",.*:");
5081 if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
5082 docElem.mozMatchesSelector ||
5083 docElem.oMatchesSelector ||
5084 docElem.msMatchesSelector) )) ) {
5086 assert(function( div ) {
5087 support.disconnectedMatch = matches.call( div, "div" );
5089 matches.call( div, "[s!='']:x" );
5090 rbuggyMatches.push( "!=", pseudos );
5094 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
5095 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
5098 ---------------------------------------------------------------------- */
5099 hasCompare = rnative.test( docElem.compareDocumentPosition );
5101 contains = hasCompare || rnative.test( docElem.contains ) ?
5103 var adown = a.nodeType === 9 ? a.documentElement : a,
5104 bup = b && b.parentNode;
5105 return a === bup || !!( bup && bup.nodeType === 1 && (
5107 adown.contains( bup ) :
5108 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
5113 while ( (b = b.parentNode) ) {
5123 ---------------------------------------------------------------------- */
5125 sortOrder = hasCompare ?
5129 hasDuplicate = true;
5133 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
5138 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
5139 a.compareDocumentPosition( b ) :
5144 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
5146 if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
5149 if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
5154 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5158 return compare & 4 ? -1 : 1;
5162 hasDuplicate = true;
5173 if ( !aup || !bup ) {
5174 return a === doc ? -1 :
5179 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5182 } else if ( aup === bup ) {
5183 return siblingCheck( a, b );
5187 while ( (cur = cur.parentNode) ) {
5191 while ( (cur = cur.parentNode) ) {
5195 while ( ap[i] === bp[i] ) {
5200 siblingCheck( ap[i], bp[i] ) :
5202 ap[i] === preferredDoc ? -1 :
5203 bp[i] === preferredDoc ? 1 :
5210 Sizzle.matches = function( expr, elements ) {
5211 return Sizzle( expr, null, null, elements );
5214 Sizzle.matchesSelector = function( elem, expr ) {
5215 if ( ( elem.ownerDocument || elem ) !== document ) {
5216 setDocument( elem );
5219 expr = expr.replace( rattributeQuotes, "='$1']" );
5221 if ( support.matchesSelector && documentIsHTML &&
5222 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
5223 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
5226 var ret = matches.call( elem, expr );
5228 if ( ret || support.disconnectedMatch ||
5229 elem.document && elem.document.nodeType !== 11 ) {
5235 return Sizzle( expr, document, null, [elem] ).length > 0;
5238 Sizzle.contains = function( context, elem ) {
5239 if ( ( context.ownerDocument || context ) !== document ) {
5240 setDocument( context );
5242 return contains( context, elem );
5245 Sizzle.attr = function( elem, name ) {
5246 if ( ( elem.ownerDocument || elem ) !== document ) {
5247 setDocument( elem );
5250 var fn = Expr.attrHandle[ name.toLowerCase() ],
5251 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
5252 fn( elem, name, !documentIsHTML ) :
5255 return val !== undefined ?
5257 support.attributes || !documentIsHTML ?
5258 elem.getAttribute( name ) :
5259 (val = elem.getAttributeNode(name)) && val.specified ?
5264 Sizzle.error = function( msg ) {
5265 throw new Error( "Syntax error, unrecognized expression: " + msg );
5269 * Document sorting and removing duplicates
5270 * @param {ArrayLike} results
5272 Sizzle.uniqueSort = function( results ) {
5278 hasDuplicate = !support.detectDuplicates;
5279 sortInput = !support.sortStable && results.slice( 0 );
5280 results.sort( sortOrder );
5282 if ( hasDuplicate ) {
5283 while ( (elem = results[i++]) ) {
5284 if ( elem === results[ i ] ) {
5285 j = duplicates.push( i );
5289 results.splice( duplicates[ j ], 1 );
5299 * Utility function for retrieving the text value of an array of DOM nodes
5300 * @param {Array|Element} elem
5302 getText = Sizzle.getText = function( elem ) {
5306 nodeType = elem.nodeType;
5309 while ( (node = elem[i++]) ) {
5310 ret += getText( node );
5312 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
5313 if ( typeof elem.textContent === "string" ) {
5314 return elem.textContent;
5316 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5317 ret += getText( elem );
5320 } else if ( nodeType === 3 || nodeType === 4 ) {
5321 return elem.nodeValue;
5327 Expr = Sizzle.selectors = {
5331 createPseudo: markFunction,
5340 ">": { dir: "parentNode", first: true },
5341 " ": { dir: "parentNode" },
5342 "+": { dir: "previousSibling", first: true },
5343 "~": { dir: "previousSibling" }
5347 "ATTR": function( match ) {
5348 match[1] = match[1].replace( runescape, funescape );
5350 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
5352 if ( match[2] === "~=" ) {
5353 match[3] = " " + match[3] + " ";
5356 return match.slice( 0, 4 );
5359 "CHILD": function( match ) {
5360 /* matches from matchExpr["CHILD"]
5361 1 type (only|nth|...)
5362 2 what (child|of-type)
5363 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
5364 4 xn-component of xn+y argument ([+-]?\d*n|)
5365 5 sign of xn-component
5367 7 sign of y-component
5370 match[1] = match[1].toLowerCase();
5372 if ( match[1].slice( 0, 3 ) === "nth" ) {
5374 Sizzle.error( match[0] );
5377 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
5378 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
5380 } else if ( match[3] ) {
5381 Sizzle.error( match[0] );
5387 "PSEUDO": function( match ) {
5389 unquoted = !match[5] && match[2];
5391 if ( matchExpr["CHILD"].test( match[0] ) ) {
5395 if ( match[3] && match[4] !== undefined ) {
5396 match[2] = match[4];
5398 } else if ( unquoted && rpseudo.test( unquoted ) &&
5399 (excess = tokenize( unquoted, true )) &&
5400 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
5402 match[0] = match[0].slice( 0, excess );
5403 match[2] = unquoted.slice( 0, excess );
5406 return match.slice( 0, 3 );
5412 "TAG": function( nodeNameSelector ) {
5413 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
5414 return nodeNameSelector === "*" ?
5415 function() { return true; } :
5417 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
5421 "CLASS": function( className ) {
5422 var pattern = classCache[ className + " " ];
5425 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
5426 classCache( className, function( elem ) {
5427 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
5431 "ATTR": function( name, operator, check ) {
5432 return function( elem ) {
5433 var result = Sizzle.attr( elem, name );
5435 if ( result == null ) {
5436 return operator === "!=";
5444 return operator === "=" ? result === check :
5445 operator === "!=" ? result !== check :
5446 operator === "^=" ? check && result.indexOf( check ) === 0 :
5447 operator === "*=" ? check && result.indexOf( check ) > -1 :
5448 operator === "$=" ? check && result.slice( -check.length ) === check :
5449 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
5450 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
5455 "CHILD": function( type, what, argument, first, last ) {
5456 var simple = type.slice( 0, 3 ) !== "nth",
5457 forward = type.slice( -4 ) !== "last",
5458 ofType = what === "of-type";
5460 return first === 1 && last === 0 ?
5463 return !!elem.parentNode;
5466 function( elem, context, xml ) {
5467 var cache, outerCache, node, diff, nodeIndex, start,
5468 dir = simple !== forward ? "nextSibling" : "previousSibling",
5469 parent = elem.parentNode,
5470 name = ofType && elem.nodeName.toLowerCase(),
5471 useCache = !xml && !ofType;
5478 while ( (node = node[ dir ]) ) {
5479 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
5483 start = dir = type === "only" && !start && "nextSibling";
5488 start = [ forward ? parent.firstChild : parent.lastChild ];
5490 if ( forward && useCache ) {
5491 outerCache = parent[ expando ] || (parent[ expando ] = {});
5492 cache = outerCache[ type ] || [];
5493 nodeIndex = cache[0] === dirruns && cache[1];
5494 diff = cache[0] === dirruns && cache[2];
5495 node = nodeIndex && parent.childNodes[ nodeIndex ];
5497 while ( (node = ++nodeIndex && node && node[ dir ] ||
5499 (diff = nodeIndex = 0) || start.pop()) ) {
5501 if ( node.nodeType === 1 && ++diff && node === elem ) {
5502 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
5507 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
5511 while ( (node = ++nodeIndex && node && node[ dir ] ||
5512 (diff = nodeIndex = 0) || start.pop()) ) {
5514 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
5516 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
5519 if ( node === elem ) {
5527 return diff === first || ( diff % first === 0 && diff / first >= 0 );
5532 "PSEUDO": function( pseudo, argument ) {
5534 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
5535 Sizzle.error( "unsupported pseudo: " + pseudo );
5537 if ( fn[ expando ] ) {
5538 return fn( argument );
5541 if ( fn.length > 1 ) {
5542 args = [ pseudo, pseudo, "", argument ];
5543 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
5544 markFunction(function( seed, matches ) {
5546 matched = fn( seed, argument ),
5549 idx = indexOf.call( seed, matched[i] );
5550 seed[ idx ] = !( matches[ idx ] = matched[i] );
5554 return fn( elem, 0, args );
5563 "not": markFunction(function( selector ) {
5566 matcher = compile( selector.replace( rtrim, "$1" ) );
5568 return matcher[ expando ] ?
5569 markFunction(function( seed, matches, context, xml ) {
5571 unmatched = matcher( seed, null, xml, [] ),
5575 if ( (elem = unmatched[i]) ) {
5576 seed[i] = !(matches[i] = elem);
5580 function( elem, context, xml ) {
5582 matcher( input, null, xml, results );
5583 return !results.pop();
5587 "has": markFunction(function( selector ) {
5588 return function( elem ) {
5589 return Sizzle( selector, elem ).length > 0;
5593 "contains": markFunction(function( text ) {
5594 return function( elem ) {
5595 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
5599 "lang": markFunction( function( lang ) {
5600 if ( !ridentifier.test(lang || "") ) {
5601 Sizzle.error( "unsupported lang: " + lang );
5603 lang = lang.replace( runescape, funescape ).toLowerCase();
5604 return function( elem ) {
5607 if ( (elemLang = documentIsHTML ?
5609 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
5611 elemLang = elemLang.toLowerCase();
5612 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
5614 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
5619 "target": function( elem ) {
5620 var hash = window.location && window.location.hash;
5621 return hash && hash.slice( 1 ) === elem.id;
5624 "root": function( elem ) {
5625 return elem === docElem;
5628 "focus": function( elem ) {
5629 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
5632 "enabled": function( elem ) {
5633 return elem.disabled === false;
5636 "disabled": function( elem ) {
5637 return elem.disabled === true;
5640 "checked": function( elem ) {
5641 var nodeName = elem.nodeName.toLowerCase();
5642 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
5645 "selected": function( elem ) {
5646 if ( elem.parentNode ) {
5647 elem.parentNode.selectedIndex;
5650 return elem.selected === true;
5653 "empty": function( elem ) {
5654 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5655 if ( elem.nodeType < 6 ) {
5662 "parent": function( elem ) {
5663 return !Expr.pseudos["empty"]( elem );
5666 "header": function( elem ) {
5667 return rheader.test( elem.nodeName );
5670 "input": function( elem ) {
5671 return rinputs.test( elem.nodeName );
5674 "button": function( elem ) {
5675 var name = elem.nodeName.toLowerCase();
5676 return name === "input" && elem.type === "button" || name === "button";
5679 "text": function( elem ) {
5681 return elem.nodeName.toLowerCase() === "input" &&
5682 elem.type === "text" &&
5684 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
5687 "first": createPositionalPseudo(function() {
5691 "last": createPositionalPseudo(function( matchIndexes, length ) {
5692 return [ length - 1 ];
5695 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
5696 return [ argument < 0 ? argument + length : argument ];
5699 "even": createPositionalPseudo(function( matchIndexes, length ) {
5701 for ( ; i < length; i += 2 ) {
5702 matchIndexes.push( i );
5704 return matchIndexes;
5707 "odd": createPositionalPseudo(function( matchIndexes, length ) {
5709 for ( ; i < length; i += 2 ) {
5710 matchIndexes.push( i );
5712 return matchIndexes;
5715 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5716 var i = argument < 0 ? argument + length : argument;
5717 for ( ; --i >= 0; ) {
5718 matchIndexes.push( i );
5720 return matchIndexes;
5723 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5724 var i = argument < 0 ? argument + length : argument;
5725 for ( ; ++i < length; ) {
5726 matchIndexes.push( i );
5728 return matchIndexes;
5733 Expr.pseudos["nth"] = Expr.pseudos["eq"];
5735 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5736 Expr.pseudos[ i ] = createInputPseudo( i );
5738 for ( i in { submit: true, reset: true } ) {
5739 Expr.pseudos[ i ] = createButtonPseudo( i );
5742 function setFilters() {}
5743 setFilters.prototype = Expr.filters = Expr.pseudos;
5744 Expr.setFilters = new setFilters();
5746 function tokenize( selector, parseOnly ) {
5747 var matched, match, tokens, type,
5748 soFar, groups, preFilters,
5749 cached = tokenCache[ selector + " " ];
5752 return parseOnly ? 0 : cached.slice( 0 );
5757 preFilters = Expr.preFilter;
5761 if ( !matched || (match = rcomma.exec( soFar )) ) {
5763 soFar = soFar.slice( match[0].length ) || soFar;
5765 groups.push( (tokens = []) );
5770 if ( (match = rcombinators.exec( soFar )) ) {
5771 matched = match.shift();
5774 type: match[0].replace( rtrim, " " )
5776 soFar = soFar.slice( matched.length );
5779 for ( type in Expr.filter ) {
5780 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5781 (match = preFilters[ type ]( match ))) ) {
5782 matched = match.shift();
5788 soFar = soFar.slice( matched.length );
5800 Sizzle.error( selector ) :
5801 tokenCache( selector, groups ).slice( 0 );
5804 function toSelector( tokens ) {
5806 len = tokens.length,
5808 for ( ; i < len; i++ ) {
5809 selector += tokens[i].value;
5814 function addCombinator( matcher, combinator, base ) {
5815 var dir = combinator.dir,
5816 checkNonElements = base && dir === "parentNode",
5819 return combinator.first ?
5820 function( elem, context, xml ) {
5821 while ( (elem = elem[ dir ]) ) {
5822 if ( elem.nodeType === 1 || checkNonElements ) {
5823 return matcher( elem, context, xml );
5828 function( elem, context, xml ) {
5829 var oldCache, outerCache,
5830 newCache = [ dirruns, doneName ];
5833 while ( (elem = elem[ dir ]) ) {
5834 if ( elem.nodeType === 1 || checkNonElements ) {
5835 if ( matcher( elem, context, xml ) ) {
5841 while ( (elem = elem[ dir ]) ) {
5842 if ( elem.nodeType === 1 || checkNonElements ) {
5843 outerCache = elem[ expando ] || (elem[ expando ] = {});
5844 if ( (oldCache = outerCache[ dir ]) &&
5845 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
5847 return (newCache[ 2 ] = oldCache[ 2 ]);
5849 outerCache[ dir ] = newCache;
5851 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
5861 function elementMatcher( matchers ) {
5862 return matchers.length > 1 ?
5863 function( elem, context, xml ) {
5864 var i = matchers.length;
5866 if ( !matchers[i]( elem, context, xml ) ) {
5875 function multipleContexts( selector, contexts, results ) {
5877 len = contexts.length;
5878 for ( ; i < len; i++ ) {
5879 Sizzle( selector, contexts[i], results );
5884 function condense( unmatched, map, filter, context, xml ) {
5888 len = unmatched.length,
5889 mapped = map != null;
5891 for ( ; i < len; i++ ) {
5892 if ( (elem = unmatched[i]) ) {
5893 if ( !filter || filter( elem, context, xml ) ) {
5894 newUnmatched.push( elem );
5902 return newUnmatched;
5905 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5906 if ( postFilter && !postFilter[ expando ] ) {
5907 postFilter = setMatcher( postFilter );
5909 if ( postFinder && !postFinder[ expando ] ) {
5910 postFinder = setMatcher( postFinder, postSelector );
5912 return markFunction(function( seed, results, context, xml ) {
5916 preexisting = results.length,
5918 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5920 matcherIn = preFilter && ( seed || !selector ) ?
5921 condense( elems, preMap, preFilter, context, xml ) :
5924 matcherOut = matcher ?
5925 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5933 matcher( matcherIn, matcherOut, context, xml );
5937 temp = condense( matcherOut, postMap );
5938 postFilter( temp, [], context, xml );
5942 if ( (elem = temp[i]) ) {
5943 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5949 if ( postFinder || preFilter ) {
5952 i = matcherOut.length;
5954 if ( (elem = matcherOut[i]) ) {
5955 temp.push( (matcherIn[i] = elem) );
5958 postFinder( null, (matcherOut = []), temp, xml );
5961 i = matcherOut.length;
5963 if ( (elem = matcherOut[i]) &&
5964 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5966 seed[temp] = !(results[temp] = elem);
5972 matcherOut = condense(
5973 matcherOut === results ?
5974 matcherOut.splice( preexisting, matcherOut.length ) :
5978 postFinder( null, results, matcherOut, xml );
5980 push.apply( results, matcherOut );
5986 function matcherFromTokens( tokens ) {
5987 var checkContext, matcher, j,
5988 len = tokens.length,
5989 leadingRelative = Expr.relative[ tokens[0].type ],
5990 implicitRelative = leadingRelative || Expr.relative[" "],
5991 i = leadingRelative ? 1 : 0,
5993 matchContext = addCombinator( function( elem ) {
5994 return elem === checkContext;
5995 }, implicitRelative, true ),
5996 matchAnyContext = addCombinator( function( elem ) {
5997 return indexOf.call( checkContext, elem ) > -1;
5998 }, implicitRelative, true ),
5999 matchers = [ function( elem, context, xml ) {
6000 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
6001 (checkContext = context).nodeType ?
6002 matchContext( elem, context, xml ) :
6003 matchAnyContext( elem, context, xml ) );
6006 for ( ; i < len; i++ ) {
6007 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
6008 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
6010 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
6012 if ( matcher[ expando ] ) {
6014 for ( ; j < len; j++ ) {
6015 if ( Expr.relative[ tokens[j].type ] ) {
6020 i > 1 && elementMatcher( matchers ),
6021 i > 1 && toSelector(
6022 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
6023 ).replace( rtrim, "$1" ),
6025 i < j && matcherFromTokens( tokens.slice( i, j ) ),
6026 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
6027 j < len && toSelector( tokens )
6030 matchers.push( matcher );
6034 return elementMatcher( matchers );
6037 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
6038 var bySet = setMatchers.length > 0,
6039 byElement = elementMatchers.length > 0,
6040 superMatcher = function( seed, context, xml, results, outermost ) {
6041 var elem, j, matcher,
6044 unmatched = seed && [],
6046 contextBackup = outermostContext,
6047 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
6048 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
6052 outermostContext = context !== document && context;
6055 for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
6056 if ( byElement && elem ) {
6058 while ( (matcher = elementMatchers[j++]) ) {
6059 if ( matcher( elem, context, xml ) ) {
6060 results.push( elem );
6065 dirruns = dirrunsUnique;
6070 if ( (elem = !matcher && elem) ) {
6075 unmatched.push( elem );
6081 if ( bySet && i !== matchedCount ) {
6083 while ( (matcher = setMatchers[j++]) ) {
6084 matcher( unmatched, setMatched, context, xml );
6088 if ( matchedCount > 0 ) {
6090 if ( !(unmatched[i] || setMatched[i]) ) {
6091 setMatched[i] = pop.call( results );
6096 setMatched = condense( setMatched );
6099 push.apply( results, setMatched );
6101 if ( outermost && !seed && setMatched.length > 0 &&
6102 ( matchedCount + setMatchers.length ) > 1 ) {
6104 Sizzle.uniqueSort( results );
6109 dirruns = dirrunsUnique;
6110 outermostContext = contextBackup;
6117 markFunction( superMatcher ) :
6121 compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
6124 elementMatchers = [],
6125 cached = compilerCache[ selector + " " ];
6129 match = tokenize( selector );
6133 cached = matcherFromTokens( match[i] );
6134 if ( cached[ expando ] ) {
6135 setMatchers.push( cached );
6137 elementMatchers.push( cached );
6141 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
6143 cached.selector = selector;
6149 * A low-level selection function that works with Sizzle's compiled
6150 * selector functions
6151 * @param
{String
|Function
} selector A selector or a pre
-compiled
6152 * selector
function built
with Sizzle
.compile
6153 * @param
{Element
} context
6154 * @param
{Array
} [results
]
6155 * @param
{Array
} [seed
] A
set of elements to match against
6157 select
= Sizzle
.select = function( selector
, context
, results
, seed
) {
6158 var i
, tokens
, token
, type
, find
,
6159 compiled
= typeof selector
=== "function" && selector
,
6160 match
= !seed
&& tokenize( (selector
= compiled
.selector
|| selector
) );
6162 results
= results
|| [];
6164 if ( match
.length
=== 1 ) {
6166 tokens
= match
[0] = match
[0].slice( 0 );
6167 if ( tokens
.length
> 2 && (token
= tokens
[0]).type
=== "ID" &&
6168 support
.getById
&& context
.nodeType
=== 9 && documentIsHTML
&&
6169 Expr
.relative
[ tokens
[1].type
] ) {
6171 context
= ( Expr
.find
["ID"]( token
.matches
[0].replace(runescape
, funescape
), context
) || [] )[0];
6175 } else if ( compiled
) {
6176 context
= context
.parentNode
;
6179 selector
= selector
.slice( tokens
.shift().value
.length
);
6182 i
= matchExpr
["needsContext"].test( selector
) ? 0 : tokens
.length
;
6186 if ( Expr
.relative
[ (type
= token
.type
) ] ) {
6189 if ( (find
= Expr
.find
[ type
]) ) {
6191 token
.matches
[0].replace( runescape
, funescape
),
6192 rsibling
.test( tokens
[0].type
) && testContext( context
.parentNode
) || context
6195 tokens
.splice( i
, 1 );
6196 selector
= seed
.length
&& toSelector( tokens
);
6198 push
.apply( results
, seed
);
6208 ( compiled
|| compile( selector
, match
) )(
6213 rsibling
.test( selector
) && testContext( context
.parentNode
) || context
6219 support
.sortStable
= expando
.split("").sort( sortOrder
).join("") === expando
;
6221 support
.detectDuplicates
= !!hasDuplicate
;
6225 support
.sortDetached
= assert(function( div1
) {
6226 return div1
.compareDocumentPosition( document
.createElement("div") ) & 1;
6229 if ( !assert(function( div
) {
6230 div
.innerHTML
= "<a href='#'></a>";
6231 return div
.firstChild
.getAttribute("href") === "#" ;
6233 addHandle( "type|href|height|width", function( elem
, name
, isXML
) {
6235 return elem
.getAttribute( name
, name
.toLowerCase() === "type" ? 1 : 2 );
6240 if ( !support
.attributes
|| !assert(function( div
) {
6241 div
.innerHTML
= "<input/>";
6242 div
.firstChild
.setAttribute( "value", "" );
6243 return div
.firstChild
.getAttribute( "value" ) === "";
6245 addHandle( "value", function( elem
, name
, isXML
) {
6246 if ( !isXML
&& elem
.nodeName
.toLowerCase() === "input" ) {
6247 return elem
.defaultValue
;
6252 if ( !assert(function( div
) {
6253 return div
.getAttribute("disabled") == null;
6255 addHandle( booleans
, function( elem
, name
, isXML
) {
6258 return elem
[ name
] === true ? name
.toLowerCase() :
6259 (val
= elem
.getAttributeNode( name
)) && val
.specified
?
6266 if ( typeof define
=== "function" && define
.amd
) {
6267 define(function() { return Sizzle
; });
6268 } else if ( typeof module
!== "undefined" && module
.exports
) {
6269 module
.exports
= Sizzle
;
6271 window
.Sizzle
= Sizzle
;
6277 if (typeof Sizzle
!== 'undefined') {
6281 if (typeof define
!== 'undefined' && define
.amd
) {
6282 window
.Sizzle
= Prototype
._actual_sizzle
;
6283 window
.define
= Prototype
._original_define
;
6284 delete Prototype
._actual_sizzle
;
6285 delete Prototype
._original_define
;
6286 } else if (typeof module
!== 'undefined' && module
.exports
) {
6287 window
.Sizzle
= module
.exports
;
6288 module
.exports
= {};
6292 ;(function(engine
) {
6293 var extendElements
= Prototype
.Selector
.extendElements
;
6295 function select(selector
, scope
) {
6296 return extendElements(engine(selector
, scope
|| document
));
6299 function match(element
, selector
) {
6300 return engine
.matches(selector
, [element
]).length
== 1;
6303 Prototype
.Selector
.engine
= engine
;
6304 Prototype
.Selector
.select
= select
;
6305 Prototype
.Selector
.match
= match
;
6308 window
.Sizzle
= Prototype
._original_property
;
6309 delete Prototype
._original_property
;
6312 reset: function(form
) {
6318 serializeElements: function(elements
, options
) {
6319 if (typeof options
!= 'object') options
= { hash
: !!options
};
6320 else if (Object
.isUndefined(options
.hash
)) options
.hash
= true;
6321 var key
, value
, submitted
= false, submit
= options
.submit
, accumulator
, initial
;
6325 accumulator = function(result
, key
, value
) {
6326 if (key
in result
) {
6327 if (!Object
.isArray(result
[key
])) result
[key
] = [result
[key
]];
6328 result
[key
] = result
[key
].concat(value
);
6329 } else result
[key
] = value
;
6334 accumulator = function(result
, key
, values
) {
6335 if (!Object
.isArray(values
)) {values
= [values
];}
6336 if (!values
.length
) {return result
;}
6337 var encodedKey
= encodeURIComponent(key
).gsub(/%20/, '+');
6338 return result
+ (result
? "&" : "") + values
.map(function (value
) {
6339 value
= value
.gsub(/(\r)?\n/, '\r\n');
6340 value
= encodeURIComponent(value
);
6341 value
= value
.gsub(/%20/, '+');
6342 return encodedKey
+ "=" + value
;
6347 return elements
.inject(initial
, function(result
, element
) {
6348 if (!element
.disabled
&& element
.name
) {
6349 key
= element
.name
; value
= $(element
).getValue();
6350 if (value
!= null && element
.type
!= 'file' && (element
.type
!= 'submit' || (!submitted
&&
6351 submit
!== false && (!submit
|| key
== submit
) && (submitted
= true)))) {
6352 result
= accumulator(result
, key
, value
);
6361 serialize: function(form
, options
) {
6362 return Form
.serializeElements(Form
.getElements(form
), options
);
6366 getElements: function(form
) {
6367 var elements
= $(form
).getElementsByTagName('*');
6368 var element
, results
= [], serializers
= Form
.Element
.Serializers
;
6370 for (var i
= 0; element
= elements
[i
]; i
++) {
6371 if (serializers
[element
.tagName
.toLowerCase()])
6372 results
.push(Element
.extend(element
));
6377 getInputs: function(form
, typeName
, name
) {
6379 var inputs
= form
.getElementsByTagName('input');
6381 if (!typeName
&& !name
) return $A(inputs
).map(Element
.extend
);
6383 for (var i
= 0, matchingInputs
= [], length
= inputs
.length
; i
< length
; i
++) {
6384 var input
= inputs
[i
];
6385 if ((typeName
&& input
.type
!= typeName
) || (name
&& input
.name
!= name
))
6387 matchingInputs
.push(Element
.extend(input
));
6390 return matchingInputs
;
6393 disable: function(form
) {
6395 Form
.getElements(form
).invoke('disable');
6399 enable: function(form
) {
6401 Form
.getElements(form
).invoke('enable');
6405 findFirstElement: function(form
) {
6406 var elements
= $(form
).getElements().findAll(function(element
) {
6407 return 'hidden' != element
.type
&& !element
.disabled
;
6409 var firstByIndex
= elements
.findAll(function(element
) {
6410 return element
.hasAttribute('tabIndex') && element
.tabIndex
>= 0;
6411 }).sortBy(function(element
) { return element
.tabIndex
}).first();
6413 return firstByIndex
? firstByIndex
: elements
.find(function(element
) {
6414 return /^(?:input|select|textarea)$/i.test(element
.tagName
);
6418 focusFirstElement: function(form
) {
6420 var element
= form
.findFirstElement();
6421 if (element
) element
.activate();
6425 request: function(form
, options
) {
6426 form
= $(form
), options
= Object
.clone(options
|| { });
6428 var params
= options
.parameters
, action
= form
.readAttribute('action') || '';
6429 if (action
.blank()) action
= window
.location
.href
;
6430 options
.parameters
= form
.serialize(true);
6433 if (Object
.isString(params
)) params
= params
.toQueryParams();
6434 Object
.extend(options
.parameters
, params
);
6437 if (form
.hasAttribute('method') && !options
.method
)
6438 options
.method
= form
.method
;
6440 return new Ajax
.Request(action
, options
);
6444 /*--------------------------------------------------------------------------*/
6448 focus: function(element
) {
6453 select: function(element
) {
6454 $(element
).select();
6459 Form
.Element
.Methods
= {
6461 serialize: function(element
) {
6462 element
= $(element
);
6463 if (!element
.disabled
&& element
.name
) {
6464 var value
= element
.getValue();
6465 if (value
!= undefined) {
6467 pair
[element
.name
] = value
;
6468 return Object
.toQueryString(pair
);
6474 getValue: function(element
) {
6475 element
= $(element
);
6476 var method
= element
.tagName
.toLowerCase();
6477 return Form
.Element
.Serializers
[method
](element
);
6480 setValue: function(element
, value
) {
6481 element
= $(element
);
6482 var method
= element
.tagName
.toLowerCase();
6483 Form
.Element
.Serializers
[method
](element
, value
);
6487 clear: function(element
) {
6488 $(element
).value
= '';
6492 present: function(element
) {
6493 return $(element
).value
!= '';
6496 activate: function(element
) {
6497 element
= $(element
);
6500 if (element
.select
&& (element
.tagName
.toLowerCase() != 'input' ||
6501 !(/^(?:button|reset|submit)$/i.test(element
.type
))))
6507 disable: function(element
) {
6508 element
= $(element
);
6509 element
.disabled
= true;
6513 enable: function(element
) {
6514 element
= $(element
);
6515 element
.disabled
= false;
6520 /*--------------------------------------------------------------------------*/
6522 var Field
= Form
.Element
;
6524 var $F
= Form
.Element
.Methods
.getValue
;
6526 /*--------------------------------------------------------------------------*/
6528 Form
.Element
.Serializers
= (function() {
6529 function input(element
, value
) {
6530 switch (element
.type
.toLowerCase()) {
6533 return inputSelector(element
, value
);
6535 return valueSelector(element
, value
);
6539 function inputSelector(element
, value
) {
6540 if (Object
.isUndefined(value
))
6541 return element
.checked
? element
.value
: null;
6542 else element
.checked
= !!value
;
6545 function valueSelector(element
, value
) {
6546 if (Object
.isUndefined(value
)) return element
.value
;
6547 else element
.value
= value
;
6550 function select(element
, value
) {
6551 if (Object
.isUndefined(value
))
6552 return (element
.type
=== 'select-one' ? selectOne
: selectMany
)(element
);
6554 var opt
, currentValue
, single
= !Object
.isArray(value
);
6555 for (var i
= 0, length
= element
.length
; i
< length
; i
++) {
6556 opt
= element
.options
[i
];
6557 currentValue
= this.optionValue(opt
);
6559 if (currentValue
== value
) {
6560 opt
.selected
= true;
6564 else opt
.selected
= value
.include(currentValue
);
6568 function selectOne(element
) {
6569 var index
= element
.selectedIndex
;
6570 return index
>= 0 ? optionValue(element
.options
[index
]) : null;
6573 function selectMany(element
) {
6574 var values
, length
= element
.length
;
6575 if (!length
) return null;
6577 for (var i
= 0, values
= []; i
< length
; i
++) {
6578 var opt
= element
.options
[i
];
6579 if (opt
.selected
) values
.push(optionValue(opt
));
6584 function optionValue(opt
) {
6585 return Element
.hasAttribute(opt
, 'value') ? opt
.value
: opt
.text
;
6590 inputSelector
: inputSelector
,
6591 textarea
: valueSelector
,
6593 selectOne
: selectOne
,
6594 selectMany
: selectMany
,
6595 optionValue
: optionValue
,
6596 button
: valueSelector
6600 /*--------------------------------------------------------------------------*/
6603 Abstract
.TimedObserver
= Class
.create(PeriodicalExecuter
, {
6604 initialize: function($super, element
, frequency
, callback
) {
6605 $super(callback
, frequency
);
6606 this.element
= $(element
);
6607 this.lastValue
= this.getValue();
6610 execute: function() {
6611 var value
= this.getValue();
6612 if (Object
.isString(this.lastValue
) && Object
.isString(value
) ?
6613 this.lastValue
!= value
: String(this.lastValue
) != String(value
)) {
6614 this.callback(this.element
, value
);
6615 this.lastValue
= value
;
6620 Form
.Element
.Observer
= Class
.create(Abstract
.TimedObserver
, {
6621 getValue: function() {
6622 return Form
.Element
.getValue(this.element
);
6626 Form
.Observer
= Class
.create(Abstract
.TimedObserver
, {
6627 getValue: function() {
6628 return Form
.serialize(this.element
);
6632 /*--------------------------------------------------------------------------*/
6634 Abstract
.EventObserver
= Class
.create({
6635 initialize: function(element
, callback
) {
6636 this.element
= $(element
);
6637 this.callback
= callback
;
6639 this.lastValue
= this.getValue();
6640 if (this.element
.tagName
.toLowerCase() == 'form')
6641 this.registerFormCallbacks();
6643 this.registerCallback(this.element
);
6646 onElementEvent: function() {
6647 var value
= this.getValue();
6648 if (this.lastValue
!= value
) {
6649 this.callback(this.element
, value
);
6650 this.lastValue
= value
;
6654 registerFormCallbacks: function() {
6655 Form
.getElements(this.element
).each(this.registerCallback
, this);
6658 registerCallback: function(element
) {
6660 switch (element
.type
.toLowerCase()) {
6663 Event
.observe(element
, 'click', this.onElementEvent
.bind(this));
6666 Event
.observe(element
, 'change', this.onElementEvent
.bind(this));
6673 Form
.Element
.EventObserver
= Class
.create(Abstract
.EventObserver
, {
6674 getValue: function() {
6675 return Form
.Element
.getValue(this.element
);
6679 Form
.EventObserver
= Class
.create(Abstract
.EventObserver
, {
6680 getValue: function() {
6681 return Form
.serialize(this.element
);
6685 var DIV
= document
.createElement('div');
6686 var docEl
= document
.documentElement
;
6687 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
= 'onmouseenter' in docEl
6688 && 'onmouseleave' in docEl
;
6708 var isIELegacyEvent = function(event
) { return false; };
6710 if (window
.attachEvent
) {
6711 if (window
.addEventListener
) {
6712 isIELegacyEvent = function(event
) {
6713 return !(event
instanceof window
.Event
);
6716 isIELegacyEvent = function(event
) { return true; };
6722 function _isButtonForDOMEvents(event
, code
) {
6723 return event
.which
? (event
.which
=== code
+ 1) : (event
.button
=== code
);
6726 var legacyButtonMap
= { 0: 1, 1: 4, 2: 2 };
6727 function _isButtonForLegacyEvents(event
, code
) {
6728 return event
.button
=== legacyButtonMap
[code
];
6731 function _isButtonForWebKit(event
, code
) {
6733 case 0: return event
.which
== 1 && !event
.metaKey
;
6734 case 1: return event
.which
== 2 || (event
.which
== 1 && event
.metaKey
);
6735 case 2: return event
.which
== 3;
6736 default: return false;
6740 if (window
.attachEvent
) {
6741 if (!window
.addEventListener
) {
6742 _isButton
= _isButtonForLegacyEvents
;
6744 _isButton = function(event
, code
) {
6745 return isIELegacyEvent(event
) ? _isButtonForLegacyEvents(event
, code
) :
6746 _isButtonForDOMEvents(event
, code
);
6749 } else if (Prototype
.Browser
.WebKit
) {
6750 _isButton
= _isButtonForWebKit
;
6752 _isButton
= _isButtonForDOMEvents
;
6755 function isLeftClick(event
) { return _isButton(event
, 0) }
6757 function isMiddleClick(event
) { return _isButton(event
, 1) }
6759 function isRightClick(event
) { return _isButton(event
, 2) }
6761 function element(event
) {
6762 return Element
.extend(_element(event
));
6765 function _element(event
) {
6766 event
= Event
.extend(event
);
6768 var node
= event
.target
, type
= event
.type
,
6769 currentTarget
= event
.currentTarget
;
6771 if (currentTarget
&& currentTarget
.tagName
) {
6772 if (type
=== 'load' || type
=== 'error' ||
6773 (type
=== 'click' && currentTarget
.tagName
.toLowerCase() === 'input'
6774 && currentTarget
.type
=== 'radio'))
6775 node
= currentTarget
;
6778 return node
.nodeType
== Node
.TEXT_NODE
? node
.parentNode
: node
;
6781 function findElement(event
, expression
) {
6782 var element
= _element(event
), selector
= Prototype
.Selector
;
6783 if (!expression
) return Element
.extend(element
);
6785 if (Object
.isElement(element
) && selector
.match(element
, expression
))
6786 return Element
.extend(element
);
6787 element
= element
.parentNode
;
6791 function pointer(event
) {
6792 return { x
: pointerX(event
), y
: pointerY(event
) };
6795 function pointerX(event
) {
6796 var docElement
= document
.documentElement
,
6797 body
= document
.body
|| { scrollLeft
: 0 };
6799 return event
.pageX
|| (event
.clientX
+
6800 (docElement
.scrollLeft
|| body
.scrollLeft
) -
6801 (docElement
.clientLeft
|| 0));
6804 function pointerY(event
) {
6805 var docElement
= document
.documentElement
,
6806 body
= document
.body
|| { scrollTop
: 0 };
6808 return event
.pageY
|| (event
.clientY
+
6809 (docElement
.scrollTop
|| body
.scrollTop
) -
6810 (docElement
.clientTop
|| 0));
6814 function stop(event
) {
6815 Event
.extend(event
);
6816 event
.preventDefault();
6817 event
.stopPropagation();
6819 event
.stopped
= true;
6824 isLeftClick
: isLeftClick
,
6825 isMiddleClick
: isMiddleClick
,
6826 isRightClick
: isRightClick
,
6829 findElement
: findElement
,
6838 var methods
= Object
.keys(Event
.Methods
).inject({ }, function(m
, name
) {
6839 m
[name
] = Event
.Methods
[name
].methodize();
6843 if (window
.attachEvent
) {
6844 function _relatedTarget(event
) {
6846 switch (event
.type
) {
6849 element
= event
.fromElement
;
6853 element
= event
.toElement
;
6858 return Element
.extend(element
);
6861 var additionalMethods
= {
6862 stopPropagation: function() { this.cancelBubble
= true },
6863 preventDefault: function() { this.returnValue
= false },
6864 inspect: function() { return '[object Event]' }
6867 Event
.extend = function(event
, element
) {
6868 if (!event
) return false;
6870 if (!isIELegacyEvent(event
)) return event
;
6872 if (event
._extendedByPrototype
) return event
;
6873 event
._extendedByPrototype
= Prototype
.emptyFunction
;
6875 var pointer
= Event
.pointer(event
);
6877 Object
.extend(event
, {
6878 target
: event
.srcElement
|| element
,
6879 relatedTarget
: _relatedTarget(event
),
6884 Object
.extend(event
, methods
);
6885 Object
.extend(event
, additionalMethods
);
6890 Event
.extend
= Prototype
.K
;
6893 if (window
.addEventListener
) {
6894 Event
.prototype = window
.Event
.prototype || document
.createEvent('HTMLEvents').__proto__
;
6895 Object
.extend(Event
.prototype, methods
);
6898 var EVENT_TRANSLATIONS
= {
6899 mouseenter
: 'mouseover',
6900 mouseleave
: 'mouseout'
6903 function getDOMEventName(eventName
) {
6904 return EVENT_TRANSLATIONS
[eventName
] || eventName
;
6907 if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
)
6908 getDOMEventName
= Prototype
.K
;
6910 function getUniqueElementID(element
) {
6911 if (element
=== window
) return 0;
6913 if (typeof element
._prototypeUID
=== 'undefined')
6914 element
._prototypeUID
= Element
.Storage
.UID
++;
6915 return element
._prototypeUID
;
6918 function getUniqueElementID_IE(element
) {
6919 if (element
=== window
) return 0;
6920 if (element
== document
) return 1;
6921 return element
.uniqueID
;
6924 if ('uniqueID' in DIV
)
6925 getUniqueElementID
= getUniqueElementID_IE
;
6927 function isCustomEvent(eventName
) {
6928 return eventName
.include(':');
6931 Event
._isCustomEvent
= isCustomEvent
;
6933 function getOrCreateRegistryFor(element
, uid
) {
6934 var CACHE
= GLOBAL
.Event
.cache
;
6935 if (Object
.isUndefined(uid
))
6936 uid
= getUniqueElementID(element
);
6937 if (!CACHE
[uid
]) CACHE
[uid
] = { element
: element
};
6941 function destroyRegistryForElement(element
, uid
) {
6942 if (Object
.isUndefined(uid
))
6943 uid
= getUniqueElementID(element
);
6944 delete GLOBAL
.Event
.cache
[uid
];
6948 function register(element
, eventName
, handler
) {
6949 var registry
= getOrCreateRegistryFor(element
);
6950 if (!registry
[eventName
]) registry
[eventName
] = [];
6951 var entries
= registry
[eventName
];
6953 var i
= entries
.length
;
6955 if (entries
[i
].handler
=== handler
) return null;
6957 var uid
= getUniqueElementID(element
);
6958 var responder
= GLOBAL
.Event
._createResponder(uid
, eventName
, handler
);
6960 responder
: responder
,
6964 entries
.push(entry
);
6968 function unregister(element
, eventName
, handler
) {
6969 var registry
= getOrCreateRegistryFor(element
);
6970 var entries
= registry
[eventName
] || [];
6972 var i
= entries
.length
, entry
;
6974 if (entries
[i
].handler
=== handler
) {
6981 var index
= entries
.indexOf(entry
);
6982 entries
.splice(index
, 1);
6985 if (entries
.length
=== 0) {
6986 delete registry
[eventName
];
6987 if (Object
.keys(registry
).length
=== 1 && ('element' in registry
))
6988 destroyRegistryForElement(element
);
6995 function observe(element
, eventName
, handler
) {
6996 element
= $(element
);
6997 var entry
= register(element
, eventName
, handler
);
6999 if (entry
=== null) return element
;
7001 var responder
= entry
.responder
;
7002 if (isCustomEvent(eventName
))
7003 observeCustomEvent(element
, eventName
, responder
);
7005 observeStandardEvent(element
, eventName
, responder
);
7010 function observeStandardEvent(element
, eventName
, responder
) {
7011 var actualEventName
= getDOMEventName(eventName
);
7012 if (element
.addEventListener
) {
7013 element
.addEventListener(actualEventName
, responder
, false);
7015 element
.attachEvent('on' + actualEventName
, responder
);
7019 function observeCustomEvent(element
, eventName
, responder
) {
7020 if (element
.addEventListener
) {
7021 element
.addEventListener('dataavailable', responder
, false);
7023 element
.attachEvent('ondataavailable', responder
);
7024 element
.attachEvent('onlosecapture', responder
);
7028 function stopObserving(element
, eventName
, handler
) {
7029 element
= $(element
);
7030 var handlerGiven
= !Object
.isUndefined(handler
),
7031 eventNameGiven
= !Object
.isUndefined(eventName
);
7033 if (!eventNameGiven
&& !handlerGiven
) {
7034 stopObservingElement(element
);
7038 if (!handlerGiven
) {
7039 stopObservingEventName(element
, eventName
);
7043 var entry
= unregister(element
, eventName
, handler
);
7045 if (!entry
) return element
;
7046 removeEvent(element
, eventName
, entry
.responder
);
7050 function stopObservingStandardEvent(element
, eventName
, responder
) {
7051 var actualEventName
= getDOMEventName(eventName
);
7052 if (element
.removeEventListener
) {
7053 element
.removeEventListener(actualEventName
, responder
, false);
7055 element
.detachEvent('on' + actualEventName
, responder
);
7059 function stopObservingCustomEvent(element
, eventName
, responder
) {
7060 if (element
.removeEventListener
) {
7061 element
.removeEventListener('dataavailable', responder
, false);
7063 element
.detachEvent('ondataavailable', responder
);
7064 element
.detachEvent('onlosecapture', responder
);
7070 function stopObservingElement(element
) {
7071 var uid
= getUniqueElementID(element
), registry
= GLOBAL
.Event
.cache
[uid
];
7072 if (!registry
) return;
7074 destroyRegistryForElement(element
, uid
);
7077 for (var eventName
in registry
) {
7078 if (eventName
=== 'element') continue;
7080 entries
= registry
[eventName
];
7083 removeEvent(element
, eventName
, entries
[i
].responder
);
7087 function stopObservingEventName(element
, eventName
) {
7088 var registry
= getOrCreateRegistryFor(element
);
7089 var entries
= registry
[eventName
];
7091 delete registry
[eventName
];
7094 entries
= entries
|| [];
7096 var i
= entries
.length
;
7098 removeEvent(element
, eventName
, entries
[i
].responder
);
7100 for (var name
in registry
) {
7101 if (name
=== 'element') continue;
7102 return; // There is another registered event
7105 destroyRegistryForElement(element
);
7109 function removeEvent(element
, eventName
, handler
) {
7110 if (isCustomEvent(eventName
))
7111 stopObservingCustomEvent(element
, eventName
, handler
);
7113 stopObservingStandardEvent(element
, eventName
, handler
);
7118 function getFireTarget(element
) {
7119 if (element
!== document
) return element
;
7120 if (document
.createEvent
&& !element
.dispatchEvent
)
7121 return document
.documentElement
;
7125 function fire(element
, eventName
, memo
, bubble
) {
7126 element
= getFireTarget($(element
));
7127 if (Object
.isUndefined(bubble
)) bubble
= true;
7130 var event
= fireEvent(element
, eventName
, memo
, bubble
);
7131 return Event
.extend(event
);
7134 function fireEvent_DOM(element
, eventName
, memo
, bubble
) {
7135 var event
= document
.createEvent('HTMLEvents');
7136 event
.initEvent('dataavailable', bubble
, true);
7138 event
.eventName
= eventName
;
7141 element
.dispatchEvent(event
);
7145 function fireEvent_IE(element
, eventName
, memo
, bubble
) {
7146 var event
= document
.createEventObject();
7147 event
.eventType
= bubble
? 'ondataavailable' : 'onlosecapture';
7149 event
.eventName
= eventName
;
7152 element
.fireEvent(event
.eventType
, event
);
7156 var fireEvent
= document
.createEvent
? fireEvent_DOM
: fireEvent_IE
;
7160 Event
.Handler
= Class
.create({
7161 initialize: function(element
, eventName
, selector
, callback
) {
7162 this.element
= $(element
);
7163 this.eventName
= eventName
;
7164 this.selector
= selector
;
7165 this.callback
= callback
;
7166 this.handler
= this.handleEvent
.bind(this);
7171 Event
.observe(this.element
, this.eventName
, this.handler
);
7176 Event
.stopObserving(this.element
, this.eventName
, this.handler
);
7180 handleEvent: function(event
) {
7181 var element
= Event
.findElement(event
, this.selector
);
7182 if (element
) this.callback
.call(this.element
, event
, element
);
7186 function on(element
, eventName
, selector
, callback
) {
7187 element
= $(element
);
7188 if (Object
.isFunction(selector
) && Object
.isUndefined(callback
)) {
7189 callback
= selector
, selector
= null;
7192 return new Event
.Handler(element
, eventName
, selector
, callback
).start();
7195 Object
.extend(Event
, Event
.Methods
);
7197 Object
.extend(Event
, {
7200 stopObserving
: stopObserving
,
7204 Element
.addMethods({
7209 stopObserving
: stopObserving
,
7214 Object
.extend(document
, {
7215 fire
: fire
.methodize(),
7217 observe
: observe
.methodize(),
7219 stopObserving
: stopObserving
.methodize(),
7226 if (GLOBAL
.Event
) Object
.extend(window
.Event
, Event
);
7227 else GLOBAL
.Event
= Event
;
7229 GLOBAL
.Event
.cache
= {};
7231 function destroyCache_IE() {
7232 GLOBAL
.Event
.cache
= null;
7235 if (window
.attachEvent
)
7236 window
.attachEvent('onunload', destroyCache_IE
);
7243 /* Code for creating leak-free event responders is based on work by
7244 John-David Dalton. */
7246 var docEl
= document
.documentElement
;
7247 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
= 'onmouseenter' in docEl
7248 && 'onmouseleave' in docEl
;
7250 function isSimulatedMouseEnterLeaveEvent(eventName
) {
7251 return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
&&
7252 (eventName
=== 'mouseenter' || eventName
=== 'mouseleave');
7255 function createResponder(uid
, eventName
, handler
) {
7256 if (Event
._isCustomEvent(eventName
))
7257 return createResponderForCustomEvent(uid
, eventName
, handler
);
7258 if (isSimulatedMouseEnterLeaveEvent(eventName
))
7259 return createMouseEnterLeaveResponder(uid
, eventName
, handler
);
7261 return function(event
) {
7262 if (!Event
.cache
) return;
7264 var element
= Event
.cache
[uid
].element
;
7265 Event
.extend(event
, element
);
7266 handler
.call(element
, event
);
7270 function createResponderForCustomEvent(uid
, eventName
, handler
) {
7271 return function(event
) {
7272 var cache
= Event
.cache
[uid
];
7273 var element
= cache
&& cache
.element
;
7275 if (Object
.isUndefined(event
.eventName
))
7278 if (event
.eventName
!== eventName
)
7281 Event
.extend(event
, element
);
7282 handler
.call(element
, event
);
7286 function createMouseEnterLeaveResponder(uid
, eventName
, handler
) {
7287 return function(event
) {
7288 var element
= Event
.cache
[uid
].element
;
7290 Event
.extend(event
, element
);
7291 var parent
= event
.relatedTarget
;
7293 while (parent
&& parent
!== element
) {
7294 try { parent
= parent
.parentNode
; }
7295 catch(e
) { parent
= element
; }
7298 if (parent
=== element
) return;
7299 handler
.call(element
, event
);
7303 GLOBAL
.Event
._createResponder
= createResponder
;
7308 /* Support for the DOMContentLoaded event is based on work by Dan Webb,
7309 Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
7313 function fireContentLoadedEvent() {
7314 if (document
.loaded
) return;
7315 if (TIMER
) window
.clearTimeout(TIMER
);
7316 document
.loaded
= true;
7317 document
.fire('dom:loaded');
7320 function checkReadyState() {
7321 if (document
.readyState
=== 'complete') {
7322 document
.detachEvent('onreadystatechange', checkReadyState
);
7323 fireContentLoadedEvent();
7327 function pollDoScroll() {
7329 document
.documentElement
.doScroll('left');
7331 TIMER
= pollDoScroll
.defer();
7335 fireContentLoadedEvent();
7339 if (document
.readyState
=== 'complete') {
7340 fireContentLoadedEvent();
7344 if (document
.addEventListener
) {
7345 document
.addEventListener('DOMContentLoaded', fireContentLoadedEvent
, false);
7347 document
.attachEvent('onreadystatechange', checkReadyState
);
7348 if (window
== top
) TIMER
= pollDoScroll
.defer();
7351 Event
.observe(window
, 'load', fireContentLoadedEvent
);
7355 Element
.addMethods();
7356 /*------------------------------- DEPRECATED -------------------------------*/
7358 Hash
.toQueryString
= Object
.toQueryString
;
7360 var Toggle
= { display
: Element
.toggle
};
7362 Element
.addMethods({
7363 childOf
: Element
.Methods
.descendantOf
7367 Before: function(element
, content
) {
7368 return Element
.insert(element
, {before
:content
});
7371 Top: function(element
, content
) {
7372 return Element
.insert(element
, {top
:content
});
7375 Bottom: function(element
, content
) {
7376 return Element
.insert(element
, {bottom
:content
});
7379 After: function(element
, content
) {
7380 return Element
.insert(element
, {after
:content
});
7384 var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
7387 includeScrollOffsets
: false,
7389 prepare: function() {
7390 this.deltaX
= window
.pageXOffset
7391 || document
.documentElement
.scrollLeft
7392 || document
.body
.scrollLeft
7394 this.deltaY
= window
.pageYOffset
7395 || document
.documentElement
.scrollTop
7396 || document
.body
.scrollTop
7400 within: function(element
, x
, y
) {
7401 if (this.includeScrollOffsets
)
7402 return this.withinIncludingScrolloffsets(element
, x
, y
);
7405 this.offset
= Element
.cumulativeOffset(element
);
7407 return (y
>= this.offset
[1] &&
7408 y
< this.offset
[1] + element
.offsetHeight
&&
7409 x
>= this.offset
[0] &&
7410 x
< this.offset
[0] + element
.offsetWidth
);
7413 withinIncludingScrolloffsets: function(element
, x
, y
) {
7414 var offsetcache
= Element
.cumulativeScrollOffset(element
);
7416 this.xcomp
= x
+ offsetcache
[0] - this.deltaX
;
7417 this.ycomp
= y
+ offsetcache
[1] - this.deltaY
;
7418 this.offset
= Element
.cumulativeOffset(element
);
7420 return (this.ycomp
>= this.offset
[1] &&
7421 this.ycomp
< this.offset
[1] + element
.offsetHeight
&&
7422 this.xcomp
>= this.offset
[0] &&
7423 this.xcomp
< this.offset
[0] + element
.offsetWidth
);
7426 overlap: function(mode
, element
) {
7427 if (!mode
) return 0;
7428 if (mode
== 'vertical')
7429 return ((this.offset
[1] + element
.offsetHeight
) - this.ycomp
) /
7430 element
.offsetHeight
;
7431 if (mode
== 'horizontal')
7432 return ((this.offset
[0] + element
.offsetWidth
) - this.xcomp
) /
7433 element
.offsetWidth
;
7437 cumulativeOffset
: Element
.Methods
.cumulativeOffset
,
7439 positionedOffset
: Element
.Methods
.positionedOffset
,
7441 absolutize: function(element
) {
7443 return Element
.absolutize(element
);
7446 relativize: function(element
) {
7448 return Element
.relativize(element
);
7451 realOffset
: Element
.Methods
.cumulativeScrollOffset
,
7453 offsetParent
: Element
.Methods
.getOffsetParent
,
7455 page
: Element
.Methods
.viewportOffset
,
7457 clone: function(source
, target
, options
) {
7458 options
= options
|| { };
7459 return Element
.clonePosition(target
, source
, options
);
7463 /*--------------------------------------------------------------------------*/
7465 if (!document
.getElementsByClassName
) document
.getElementsByClassName = function(instanceMethods
){
7466 function iter(name
) {
7467 return name
.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name
+ " ')]";
7470 instanceMethods
.getElementsByClassName
= Prototype
.BrowserFeatures
.XPath
?
7471 function(element
, className
) {
7472 className
= className
.toString().strip();
7473 var cond
= /\s/.test(className
) ? $w(className
).map(iter
).join('') : iter(className
);
7474 return cond
? document
._getElementsByXPath('.//*' + cond
, element
) : [];
7475 } : function(element
, className
) {
7476 className
= className
.toString().strip();
7477 var elements
= [], classNames
= (/\s/.test(className
) ? $w(className
) : null);
7478 if (!classNames
&& !className
) return elements
;
7480 var nodes
= $(element
).getElementsByTagName('*');
7481 className
= ' ' + className
+ ' ';
7483 for (var i
= 0, child
, cn
; child
= nodes
[i
]; i
++) {
7484 if (child
.className
&& (cn
= ' ' + child
.className
+ ' ') && (cn
.include(className
) ||
7485 (classNames
&& classNames
.all(function(name
) {
7486 return !name
.toString().blank() && cn
.include(' ' + name
+ ' ');
7488 elements
.push(Element
.extend(child
));
7493 return function(className
, parentElement
) {
7494 return $(parentElement
|| document
.body
).getElementsByClassName(className
);
7498 /*--------------------------------------------------------------------------*/
7500 Element
.ClassNames
= Class
.create();
7501 Element
.ClassNames
.prototype = {
7502 initialize: function(element
) {
7503 this.element
= $(element
);
7506 _each: function(iterator
, context
) {
7507 this.element
.className
.split(/\s+/).select(function(name
) {
7508 return name
.length
> 0;
7509 })._each(iterator
, context
);
7512 set: function(className
) {
7513 this.element
.className
= className
;
7516 add: function(classNameToAdd
) {
7517 if (this.include(classNameToAdd
)) return;
7518 this.set($A(this).concat(classNameToAdd
).join(' '));
7521 remove: function(classNameToRemove
) {
7522 if (!this.include(classNameToRemove
)) return;
7523 this.set($A(this).without(classNameToRemove
).join(' '));
7526 toString: function() {
7527 return $A(this).join(' ');
7531 Object
.extend(Element
.ClassNames
.prototype, Enumerable
);
7533 /*--------------------------------------------------------------------------*/
7536 window
.Selector
= Class
.create({
7537 initialize: function(expression
) {
7538 this.expression
= expression
.strip();
7541 findElements: function(rootElement
) {
7542 return Prototype
.Selector
.select(this.expression
, rootElement
);
7545 match: function(element
) {
7546 return Prototype
.Selector
.match(element
, this.expression
);
7549 toString: function() {
7550 return this.expression
;
7553 inspect: function() {
7554 return "#<Selector: " + this.expression
+ ">";
7558 Object
.extend(Selector
, {
7559 matchElements: function(elements
, expression
) {
7560 var match
= Prototype
.Selector
.match
,
7563 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
7564 var element
= elements
[i
];
7565 if (match(element
, expression
)) {
7566 results
.push(Element
.extend(element
));
7572 findElement: function(elements
, expression
, index
) {
7574 var matchIndex
= 0, element
;
7575 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
7576 element
= elements
[i
];
7577 if (Prototype
.Selector
.match(element
, expression
) && index
=== matchIndex
++) {
7578 return Element
.extend(element
);
7583 findChildElements: function(element
, expressions
) {
7584 var selector
= expressions
.toArray().join(', ');
7585 return Prototype
.Selector
.select(selector
, element
|| document
);