1 // Modified document.on() to modified.p_on() to fix compatibility with Dojo -fox
3 /* Prototype JavaScript framework, version 1.7.3
4 * (c) 2005-2010 Sam Stephenson
6 * Prototype is freely distributable under the terms of an MIT-style license.
7 * For details, see the Prototype web site: http://www.prototypejs.org/
9 *--------------------------------------------------------------------------*/
16 var ua
= navigator
.userAgent
;
17 var isOpera
= Object
.prototype.toString
.call(window
.opera
) == '[object Opera]';
19 IE
: !!window
.attachEvent
&& !isOpera
,
21 WebKit
: ua
.indexOf('AppleWebKit/') > -1,
22 Gecko
: ua
.indexOf('Gecko') > -1 && ua
.indexOf('KHTML') === -1,
23 MobileSafari
: /Apple.*Mobile/.test(ua
)
28 XPath
: !!document
.evaluate
,
30 SelectorsAPI
: !!document
.querySelector
,
32 ElementExtensions
: (function() {
33 var constructor = window
.Element
|| window
.HTMLElement
;
34 return !!(constructor && constructor.prototype);
36 SpecificElementExtensions
: (function() {
37 if (typeof window
.HTMLDivElement
!== 'undefined')
40 var div
= document
.createElement('div'),
41 form
= document
.createElement('form'),
44 if (div
['__proto__'] && (div
['__proto__'] !== form
['__proto__'])) {
54 ScriptFragment
: '<script[^>]*>([\\S\\s]*?)<\/script\\s*>',
55 JSONFilter
: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
57 emptyFunction: function() { },
59 K: function(x
) { return x
}
62 if (Prototype
.Browser
.MobileSafari
)
63 Prototype
.BrowserFeatures
.SpecificElementExtensions
= false;
64 /* Based on Alex Arnell's inheritance implementation. */
66 var Class
= (function() {
68 var IS_DONTENUM_BUGGY
= (function(){
69 for (var p
in { toString
: 1 }) {
70 if (p
=== 'toString') return false;
75 function subclass() {};
77 var parent
= null, properties
= $A(arguments
);
78 if (Object
.isFunction(properties
[0]))
79 parent
= properties
.shift();
82 this.initialize
.apply(this, arguments
);
85 Object
.extend(klass
, Class
.Methods
);
86 klass
.superclass
= parent
;
87 klass
.subclasses
= [];
90 subclass
.prototype = parent
.prototype;
91 klass
.prototype = new subclass
;
92 parent
.subclasses
.push(klass
);
95 for (var i
= 0, length
= properties
.length
; i
< length
; i
++)
96 klass
.addMethods(properties
[i
]);
98 if (!klass
.prototype.initialize
)
99 klass
.prototype.initialize
= Prototype
.emptyFunction
;
101 klass
.prototype.constructor = klass
;
105 function addMethods(source
) {
106 var ancestor
= this.superclass
&& this.superclass
.prototype,
107 properties
= Object
.keys(source
);
109 if (IS_DONTENUM_BUGGY
) {
110 if (source
.toString
!= Object
.prototype.toString
)
111 properties
.push("toString");
112 if (source
.valueOf
!= Object
.prototype.valueOf
)
113 properties
.push("valueOf");
116 for (var i
= 0, length
= properties
.length
; i
< length
; i
++) {
117 var property
= properties
[i
], value
= source
[property
];
118 if (ancestor
&& Object
.isFunction(value
) &&
119 value
.argumentNames()[0] == "$super") {
121 value
= (function(m
) {
122 return function() { return ancestor
[m
].apply(this, arguments
); };
123 })(property
).wrap(method
);
125 value
.valueOf
= (function(method
) {
126 return function() { return method
.valueOf
.call(method
); };
129 value
.toString
= (function(method
) {
130 return function() { return method
.toString
.call(method
); };
133 this.prototype[property
] = value
;
142 addMethods
: addMethods
148 var _toString
= Object
.prototype.toString
,
149 _hasOwnProperty
= Object
.prototype.hasOwnProperty
,
151 UNDEFINED_TYPE
= 'Undefined',
152 BOOLEAN_TYPE
= 'Boolean',
153 NUMBER_TYPE
= 'Number',
154 STRING_TYPE
= 'String',
155 OBJECT_TYPE
= 'Object',
156 FUNCTION_CLASS
= '[object Function]',
157 BOOLEAN_CLASS
= '[object Boolean]',
158 NUMBER_CLASS
= '[object Number]',
159 STRING_CLASS
= '[object String]',
160 ARRAY_CLASS
= '[object Array]',
161 DATE_CLASS
= '[object Date]',
162 NATIVE_JSON_STRINGIFY_SUPPORT
= window
.JSON
&&
163 typeof JSON
.stringify
=== 'function' &&
164 JSON
.stringify(0) === '0' &&
165 typeof JSON
.stringify(Prototype
.K
) === 'undefined';
169 var DONT_ENUMS
= ['toString', 'toLocaleString', 'valueOf',
170 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
172 var IS_DONTENUM_BUGGY
= (function(){
173 for (var p
in { toString
: 1 }) {
174 if (p
=== 'toString') return false;
181 case null: return NULL_TYPE
;
182 case (void 0): return UNDEFINED_TYPE
;
186 case 'boolean': return BOOLEAN_TYPE
;
187 case 'number': return NUMBER_TYPE
;
188 case 'string': return STRING_TYPE
;
193 function extend(destination
, source
) {
194 for (var property
in source
)
195 destination
[property
] = source
[property
];
199 function inspect(object
) {
201 if (isUndefined(object
)) return 'undefined';
202 if (object
=== null) return 'null';
203 return object
.inspect
? object
.inspect() : String(object
);
205 if (e
instanceof RangeError
) return '...';
210 function toJSON(value
) {
211 return Str('', { '': value
}, []);
214 function Str(key
, holder
, stack
) {
215 var value
= holder
[key
];
216 if (Type(value
) === OBJECT_TYPE
&& typeof value
.toJSON
=== 'function') {
217 value
= value
.toJSON(key
);
220 var _class
= _toString
.call(value
);
226 value
= value
.valueOf();
230 case null: return 'null';
231 case true: return 'true';
232 case false: return 'false';
235 var type
= typeof value
;
238 return value
.inspect(true);
240 return isFinite(value
) ? String(value
) : 'null';
243 for (var i
= 0, length
= stack
.length
; i
< length
; i
++) {
244 if (stack
[i
] === value
) {
245 throw new TypeError("Cyclic reference to '" + value
+ "' in object");
251 if (_class
=== ARRAY_CLASS
) {
252 for (var i
= 0, length
= value
.length
; i
< length
; i
++) {
253 var str
= Str(i
, value
, stack
);
254 partial
.push(typeof str
=== 'undefined' ? 'null' : str
);
256 partial
= '[' + partial
.join(',') + ']';
258 var keys
= Object
.keys(value
);
259 for (var i
= 0, length
= keys
.length
; i
< length
; i
++) {
260 var key
= keys
[i
], str
= Str(key
, value
, stack
);
261 if (typeof str
!== "undefined") {
262 partial
.push(key
.inspect(true)+ ':' + str
);
265 partial
= '{' + partial
.join(',') + '}';
272 function stringify(object
) {
273 return JSON
.stringify(object
);
276 function toQueryString(object
) {
277 return $H(object
).toQueryString();
280 function toHTML(object
) {
281 return object
&& object
.toHTML
? object
.toHTML() : String
.interpret(object
);
284 function keys(object
) {
285 if (Type(object
) !== OBJECT_TYPE
) { throw new TypeError(); }
287 for (var property
in object
) {
288 if (_hasOwnProperty
.call(object
, property
))
289 results
.push(property
);
292 if (IS_DONTENUM_BUGGY
) {
293 for (var i
= 0; property
= DONT_ENUMS
[i
]; i
++) {
294 if (_hasOwnProperty
.call(object
, property
))
295 results
.push(property
);
302 function values(object
) {
304 for (var property
in object
)
305 results
.push(object
[property
]);
309 function clone(object
) {
310 return extend({ }, object
);
313 function isElement(object
) {
314 return !!(object
&& object
.nodeType
== 1);
317 function isArray(object
) {
318 return _toString
.call(object
) === ARRAY_CLASS
;
321 var hasNativeIsArray
= (typeof Array
.isArray
== 'function')
322 && Array
.isArray([]) && !Array
.isArray({});
324 if (hasNativeIsArray
) {
325 isArray
= Array
.isArray
;
328 function isHash(object
) {
329 return object
instanceof Hash
;
332 function isFunction(object
) {
333 return _toString
.call(object
) === FUNCTION_CLASS
;
336 function isString(object
) {
337 return _toString
.call(object
) === STRING_CLASS
;
340 function isNumber(object
) {
341 return _toString
.call(object
) === NUMBER_CLASS
;
344 function isDate(object
) {
345 return _toString
.call(object
) === DATE_CLASS
;
348 function isUndefined(object
) {
349 return typeof object
=== "undefined";
355 toJSON
: NATIVE_JSON_STRINGIFY_SUPPORT
? stringify
: toJSON
,
356 toQueryString
: toQueryString
,
358 keys
: Object
.keys
|| keys
,
361 isElement
: isElement
,
364 isFunction
: isFunction
,
368 isUndefined
: isUndefined
371 Object
.extend(Function
.prototype, (function() {
372 var slice
= Array
.prototype.slice
;
374 function update(array
, args
) {
375 var arrayLength
= array
.length
, length
= args
.length
;
376 while (length
--) array
[arrayLength
+ length
] = args
[length
];
380 function merge(array
, args
) {
381 array
= slice
.call(array
, 0);
382 return update(array
, args
);
385 function argumentNames() {
386 var names
= this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
387 .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
388 .replace(/\s+/g, '').split(',');
389 return names
.length
== 1 && !names
[0] ? [] : names
;
393 function bind(context
) {
394 if (arguments
.length
< 2 && Object
.isUndefined(arguments
[0]))
397 if (!Object
.isFunction(this))
398 throw new TypeError("The object is not callable.");
400 var nop = function() {};
401 var __method
= this, args
= slice
.call(arguments
, 1);
403 var bound = function() {
404 var a
= merge(args
, arguments
);
405 var c
= this instanceof bound
? this : context
;
406 return __method
.apply(c
, a
);
409 nop
.prototype = this.prototype;
410 bound
.prototype = new nop();
415 function bindAsEventListener(context
) {
416 var __method
= this, args
= slice
.call(arguments
, 1);
417 return function(event
) {
418 var a
= update([event
|| window
.event
], args
);
419 return __method
.apply(context
, a
);
424 if (!arguments
.length
) return this;
425 var __method
= this, args
= slice
.call(arguments
, 0);
427 var a
= merge(args
, arguments
);
428 return __method
.apply(this, a
);
432 function delay(timeout
) {
433 var __method
= this, args
= slice
.call(arguments
, 1);
434 timeout
= timeout
* 1000;
435 return window
.setTimeout(function() {
436 return __method
.apply(__method
, args
);
441 var args
= update([0.01], arguments
);
442 return this.delay
.apply(this, args
);
445 function wrap(wrapper
) {
448 var a
= update([__method
.bind(this)], arguments
);
449 return wrapper
.apply(this, a
);
453 function methodize() {
454 if (this._methodized
) return this._methodized
;
456 return this._methodized = function() {
457 var a
= update([this], arguments
);
458 return __method
.apply(null, a
);
463 argumentNames
: argumentNames
,
464 bindAsEventListener
: bindAsEventListener
,
472 if (!Function
.prototype.bind
)
473 extensions
.bind
= bind
;
483 function toISOString() {
484 return this.getUTCFullYear() + '-' +
485 (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
486 this.getUTCDate().toPaddedString(2) + 'T' +
487 this.getUTCHours().toPaddedString(2) + ':' +
488 this.getUTCMinutes().toPaddedString(2) + ':' +
489 this.getUTCSeconds().toPaddedString(2) + 'Z';
494 return this.toISOString();
497 if (!proto
.toISOString
) proto
.toISOString
= toISOString
;
498 if (!proto
.toJSON
) proto
.toJSON
= toJSON
;
503 RegExp
.prototype.match
= RegExp
.prototype.test
;
505 RegExp
.escape = function(str
) {
506 return String(str
).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
508 var PeriodicalExecuter
= Class
.create({
509 initialize: function(callback
, frequency
) {
510 this.callback
= callback
;
511 this.frequency
= frequency
;
512 this.currentlyExecuting
= false;
514 this.registerCallback();
517 registerCallback: function() {
518 this.timer
= setInterval(this.onTimerEvent
.bind(this), this.frequency
* 1000);
521 execute: function() {
526 if (!this.timer
) return;
527 clearInterval(this.timer
);
531 onTimerEvent: function() {
532 if (!this.currentlyExecuting
) {
534 this.currentlyExecuting
= true;
536 this.currentlyExecuting
= false;
538 this.currentlyExecuting
= false;
544 Object
.extend(String
, {
545 interpret: function(value
) {
546 return value
== null ? '' : String(value
);
558 Object
.extend(String
.prototype, (function() {
559 var NATIVE_JSON_PARSE_SUPPORT
= window
.JSON
&&
560 typeof JSON
.parse
=== 'function' &&
561 JSON
.parse('{"test": true}').test
;
563 function prepareReplacement(replacement
) {
564 if (Object
.isFunction(replacement
)) return replacement
;
565 var template
= new Template(replacement
);
566 return function(match
) { return template
.evaluate(match
) };
569 function isNonEmptyRegExp(regexp
) {
570 return regexp
.source
&& regexp
.source
!== '(?:)';
574 function gsub(pattern
, replacement
) {
575 var result
= '', source
= this, match
;
576 replacement
= prepareReplacement(replacement
);
578 if (Object
.isString(pattern
))
579 pattern
= RegExp
.escape(pattern
);
581 if (!(pattern
.length
|| isNonEmptyRegExp(pattern
))) {
582 replacement
= replacement('');
583 return replacement
+ source
.split('').join(replacement
) + replacement
;
586 while (source
.length
> 0) {
587 match
= source
.match(pattern
)
588 if (match
&& match
[0].length
> 0) {
589 result
+= source
.slice(0, match
.index
);
590 result
+= String
.interpret(replacement(match
));
591 source
= source
.slice(match
.index
+ match
[0].length
);
593 result
+= source
, source
= '';
599 function sub(pattern
, replacement
, count
) {
600 replacement
= prepareReplacement(replacement
);
601 count
= Object
.isUndefined(count
) ? 1 : count
;
603 return this.gsub(pattern
, function(match
) {
604 if (--count
< 0) return match
[0];
605 return replacement(match
);
609 function scan(pattern
, iterator
) {
610 this.gsub(pattern
, iterator
);
614 function truncate(length
, truncation
) {
615 length
= length
|| 30;
616 truncation
= Object
.isUndefined(truncation
) ? '...' : truncation
;
617 return this.length
> length
?
618 this.slice(0, length
- truncation
.length
) + truncation
: String(this);
622 return this.replace(/^\s+/, '').replace(/\s+$/, '');
625 function stripTags() {
626 return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?(\/)?>|<\/\w+>/gi, '');
629 function stripScripts() {
630 return this.replace(new RegExp(Prototype
.ScriptFragment
, 'img'), '');
633 function extractScripts() {
634 var matchAll
= new RegExp(Prototype
.ScriptFragment
, 'img'),
635 matchOne
= new RegExp(Prototype
.ScriptFragment
, 'im');
636 return (this.match(matchAll
) || []).map(function(scriptTag
) {
637 return (scriptTag
.match(matchOne
) || ['', ''])[1];
641 function evalScripts() {
642 return this.extractScripts().map(function(script
) { return eval(script
); });
645 function escapeHTML() {
646 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g
,'>');
649 function unescapeHTML() {
650 return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
654 function toQueryParams(separator
) {
655 var match
= this.strip().match(/([^?#]*)(#.*)?$/);
656 if (!match
) return { };
658 return match
[1].split(separator
|| '&').inject({ }, function(hash
, pair
) {
659 if ((pair
= pair
.split('='))[0]) {
660 var key
= decodeURIComponent(pair
.shift()),
661 value
= pair
.length
> 1 ? pair
.join('=') : pair
[0];
663 if (value
!= undefined) {
664 value
= value
.gsub('+', ' ');
665 value
= decodeURIComponent(value
);
669 if (!Object
.isArray(hash
[key
])) hash
[key
] = [hash
[key
]];
670 hash
[key
].push(value
);
672 else hash
[key
] = value
;
679 return this.split('');
683 return this.slice(0, this.length
- 1) +
684 String
.fromCharCode(this.charCodeAt(this.length
- 1) + 1);
687 function times(count
) {
688 return count
< 1 ? '' : new Array(count
+ 1).join(this);
691 function camelize() {
692 return this.replace(/-+(.)?/g, function(match
, chr
) {
693 return chr
? chr
.toUpperCase() : '';
697 function capitalize() {
698 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
701 function underscore() {
702 return this.replace(/::/g, '/')
703 .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
704 .replace(/([a-z\d])([A-Z])/g, '$1_$2')
709 function dasherize() {
710 return this.replace(/_
/g
, '-');
713 function inspect(useDoubleQuotes
) {
714 var escapedString
= this.replace(/[\x00-\x1f\\]/g, function(character
) {
715 if (character
in String
.specialChar
) {
716 return String
.specialChar
[character
];
718 return '\\u00' + character
.charCodeAt().toPaddedString(2, 16);
720 if (useDoubleQuotes
) return '"' + escapedString
.replace(/"/g, '\\"') + '"';
721 return "'" + escapedString.replace(/'/g
, '\\\'') + "'";
724 function unfilterJSON(filter
) {
725 return this.replace(filter
|| Prototype
.JSONFilter
, '$1');
730 if (str
.blank()) return false;
731 str
= str
.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
732 str
= str
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
733 str
= str
.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
734 return (/^[\],:{}\s]*$/).test(str
);
737 function evalJSON(sanitize
) {
738 var json
= this.unfilterJSON(),
739 cx
= /[\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff\u0000]/g;
741 json
= json
.replace(cx
, function (a
) {
742 return '\\u' + ('0000' + a
.charCodeAt(0).toString(16)).slice(-4);
746 if (!sanitize
|| json
.isJSON()) return eval('(' + json
+ ')');
748 throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
751 function parseJSON() {
752 var json
= this.unfilterJSON();
753 return JSON
.parse(json
);
756 function include(pattern
) {
757 return this.indexOf(pattern
) > -1;
760 function startsWith(pattern
, position
) {
761 position
= Object
.isNumber(position
) ? position
: 0;
762 return this.lastIndexOf(pattern
, position
) === position
;
765 function endsWith(pattern
, position
) {
766 pattern
= String(pattern
);
767 position
= Object
.isNumber(position
) ? position
: this.length
;
768 if (position
< 0) position
= 0;
769 if (position
> this.length
) position
= this.length
;
770 var d
= position
- pattern
.length
;
771 return d
>= 0 && this.indexOf(pattern
, d
) === d
;
779 return /^\s*$/.test(this);
782 function interpolate(object
, pattern
) {
783 return new Template(this, pattern
).evaluate(object
);
791 strip
: String
.prototype.trim
|| strip
,
792 stripTags
: stripTags
,
793 stripScripts
: stripScripts
,
794 extractScripts
: extractScripts
,
795 evalScripts
: evalScripts
,
796 escapeHTML
: escapeHTML
,
797 unescapeHTML
: unescapeHTML
,
798 toQueryParams
: toQueryParams
,
799 parseQuery
: toQueryParams
,
804 capitalize
: capitalize
,
805 underscore
: underscore
,
806 dasherize
: dasherize
,
808 unfilterJSON
: unfilterJSON
,
810 evalJSON
: NATIVE_JSON_PARSE_SUPPORT
? parseJSON
: evalJSON
,
812 startsWith
: String
.prototype.startsWith
|| startsWith
,
813 endsWith
: String
.prototype.endsWith
|| endsWith
,
816 interpolate
: interpolate
820 var Template
= Class
.create({
821 initialize: function(template
, pattern
) {
822 this.template
= template
.toString();
823 this.pattern
= pattern
|| Template
.Pattern
;
826 evaluate: function(object
) {
827 if (object
&& Object
.isFunction(object
.toTemplateReplacements
))
828 object
= object
.toTemplateReplacements();
830 return this.template
.gsub(this.pattern
, function(match
) {
831 if (object
== null) return (match
[1] + '');
833 var before
= match
[1] || '';
834 if (before
== '\\') return match
[2];
836 var ctx
= object
, expr
= match
[3],
837 pattern
= /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
839 match
= pattern
.exec(expr
);
840 if (match
== null) return before
;
842 while (match
!= null) {
843 var comp
= match
[1].startsWith('[') ? match
[2].replace(/\\\\]/g, ']') : match
[1];
845 if (null == ctx
|| '' == match
[3]) break;
846 expr
= expr
.substring('[' == match
[3] ? match
[1].length
: match
[0].length
);
847 match
= pattern
.exec(expr
);
850 return before
+ String
.interpret(ctx
);
854 Template
.Pattern
= /(^|.|\r|\n)(#\{(.*?)\})/;
858 var Enumerable
= (function() {
859 function each(iterator
, context
) {
861 this._each(iterator
, context
);
863 if (e
!= $break) throw e
;
868 function eachSlice(number
, iterator
, context
) {
869 var index
= -number
, slices
= [], array
= this.toArray();
870 if (number
< 1) return array
;
871 while ((index
+= number
) < array
.length
)
872 slices
.push(array
.slice(index
, index
+number
));
873 return slices
.collect(iterator
, context
);
876 function all(iterator
, context
) {
877 iterator
= iterator
|| Prototype
.K
;
879 this.each(function(value
, index
) {
880 result
= result
&& !!iterator
.call(context
, value
, index
, this);
881 if (!result
) throw $break;
886 function any(iterator
, context
) {
887 iterator
= iterator
|| Prototype
.K
;
889 this.each(function(value
, index
) {
890 if (result
= !!iterator
.call(context
, value
, index
, this))
896 function collect(iterator
, context
) {
897 iterator
= iterator
|| Prototype
.K
;
899 this.each(function(value
, index
) {
900 results
.push(iterator
.call(context
, value
, index
, this));
905 function detect(iterator
, context
) {
907 this.each(function(value
, index
) {
908 if (iterator
.call(context
, value
, index
, this)) {
916 function findAll(iterator
, context
) {
918 this.each(function(value
, index
) {
919 if (iterator
.call(context
, value
, index
, this))
925 function grep(filter
, iterator
, context
) {
926 iterator
= iterator
|| Prototype
.K
;
929 if (Object
.isString(filter
))
930 filter
= new RegExp(RegExp
.escape(filter
));
932 this.each(function(value
, index
) {
933 if (filter
.match(value
))
934 results
.push(iterator
.call(context
, value
, index
, this));
939 function include(object
) {
940 if (Object
.isFunction(this.indexOf
) && this.indexOf(object
) != -1)
944 this.each(function(value
) {
945 if (value
== object
) {
953 function inGroupsOf(number
, fillWith
) {
954 fillWith
= Object
.isUndefined(fillWith
) ? null : fillWith
;
955 return this.eachSlice(number
, function(slice
) {
956 while(slice
.length
< number
) slice
.push(fillWith
);
961 function inject(memo
, iterator
, context
) {
962 this.each(function(value
, index
) {
963 memo
= iterator
.call(context
, memo
, value
, index
, this);
968 function invoke(method
) {
969 var args
= $A(arguments
).slice(1);
970 return this.map(function(value
) {
971 return value
[method
].apply(value
, args
);
975 function max(iterator
, context
) {
976 iterator
= iterator
|| Prototype
.K
;
978 this.each(function(value
, index
) {
979 value
= iterator
.call(context
, value
, index
, this);
980 if (result
== null || value
>= result
)
986 function min(iterator
, context
) {
987 iterator
= iterator
|| Prototype
.K
;
989 this.each(function(value
, index
) {
990 value
= iterator
.call(context
, value
, index
, this);
991 if (result
== null || value
< result
)
997 function partition(iterator
, context
) {
998 iterator
= iterator
|| Prototype
.K
;
999 var trues
= [], falses
= [];
1000 this.each(function(value
, index
) {
1001 (iterator
.call(context
, value
, index
, this) ?
1002 trues
: falses
).push(value
);
1004 return [trues
, falses
];
1007 function pluck(property
) {
1009 this.each(function(value
) {
1010 results
.push(value
[property
]);
1015 function reject(iterator
, context
) {
1017 this.each(function(value
, index
) {
1018 if (!iterator
.call(context
, value
, index
, this))
1019 results
.push(value
);
1024 function sortBy(iterator
, context
) {
1025 return this.map(function(value
, index
) {
1028 criteria
: iterator
.call(context
, value
, index
, this)
1030 }, this).sort(function(left
, right
) {
1031 var a
= left
.criteria
, b
= right
.criteria
;
1032 return a
< b
? -1 : a
> b
? 1 : 0;
1036 function toArray() {
1041 var iterator
= Prototype
.K
, args
= $A(arguments
);
1042 if (Object
.isFunction(args
.last()))
1043 iterator
= args
.pop();
1045 var collections
= [this].concat(args
).map($A
);
1046 return this.map(function(value
, index
) {
1047 return iterator(collections
.pluck(index
));
1052 return this.toArray().length
;
1055 function inspect() {
1056 return '#<Enumerable:' + this.toArray().inspect() + '>';
1069 eachSlice
: eachSlice
,
1083 inGroupsOf
: inGroupsOf
,
1088 partition
: partition
,
1101 function $A(iterable
) {
1102 if (!iterable
) return [];
1103 if ('toArray' in Object(iterable
)) return iterable
.toArray();
1104 var length
= iterable
.length
|| 0, results
= new Array(length
);
1105 while (length
--) results
[length
] = iterable
[length
];
1110 function $w(string
) {
1111 if (!Object
.isString(string
)) return [];
1112 string
= string
.strip();
1113 return string
? string
.split(/\s+/) : [];
1120 var arrayProto
= Array
.prototype,
1121 slice
= arrayProto
.slice
,
1122 _each
= arrayProto
.forEach
; // use native browser JS 1.6 implementation if available
1124 function each(iterator
, context
) {
1125 for (var i
= 0, length
= this.length
>>> 0; i
< length
; i
++) {
1126 if (i
in this) iterator
.call(context
, this[i
], i
, this);
1129 if (!_each
) _each
= each
;
1141 return this[this.length
- 1];
1144 function compact() {
1145 return this.select(function(value
) {
1146 return value
!= null;
1150 function flatten() {
1151 return this.inject([], function(array
, value
) {
1152 if (Object
.isArray(value
))
1153 return array
.concat(value
.flatten());
1159 function without() {
1160 var values
= slice
.call(arguments
, 0);
1161 return this.select(function(value
) {
1162 return !values
.include(value
);
1166 function reverse(inline
) {
1167 return (inline
=== false ? this.toArray() : this)._reverse();
1170 function uniq(sorted
) {
1171 return this.inject([], function(array
, value
, index
) {
1172 if (0 == index
|| (sorted
? array
.last() != value
: !array
.include(value
)))
1178 function intersect(array
) {
1179 return this.uniq().findAll(function(item
) {
1180 return array
.indexOf(item
) !== -1;
1186 return slice
.call(this, 0);
1193 function inspect() {
1194 return '[' + this.map(Object
.inspect
).join(', ') + ']';
1197 function indexOf(item
, i
) {
1198 if (this == null) throw new TypeError();
1200 var array
= Object(this), length
= array
.length
>>> 0;
1201 if (length
=== 0) return -1;
1206 } else if (i
!== 0 && isFinite(i
)) {
1207 i
= (i
> 0 ? 1 : -1) * Math
.floor(Math
.abs(i
));
1210 if (i
> length
) return -1;
1212 var k
= i
>= 0 ? i
: Math
.max(length
- Math
.abs(i
), 0);
1213 for (; k
< length
; k
++)
1214 if (k
in array
&& array
[k
] === item
) return k
;
1219 function lastIndexOf(item
, i
) {
1220 if (this == null) throw new TypeError();
1222 var array
= Object(this), length
= array
.length
>>> 0;
1223 if (length
=== 0) return -1;
1225 if (!Object
.isUndefined(i
)) {
1229 } else if (i
!== 0 && isFinite(i
)) {
1230 i
= (i
> 0 ? 1 : -1) * Math
.floor(Math
.abs(i
));
1236 var k
= i
>= 0 ? Math
.min(i
, length
- 1) :
1237 length
- Math
.abs(i
);
1240 if (k
in array
&& array
[k
] === item
) return k
;
1244 function concat(_
) {
1245 var array
= [], items
= slice
.call(arguments
, 0), item
, n
= 0;
1246 items
.unshift(this);
1247 for (var i
= 0, length
= items
.length
; i
< length
; i
++) {
1249 if (Object
.isArray(item
) && !('callee' in item
)) {
1250 for (var j
= 0, arrayLength
= item
.length
; j
< arrayLength
; j
++) {
1251 if (j
in item
) array
[n
] = item
[j
];
1263 function wrapNative(method
) {
1265 if (arguments
.length
=== 0) {
1266 return method
.call(this, Prototype
.K
);
1267 } else if (arguments
[0] === undefined) {
1268 var args
= slice
.call(arguments
, 1);
1269 args
.unshift(Prototype
.K
);
1270 return method
.apply(this, args
);
1272 return method
.apply(this, arguments
);
1278 function map(iterator
) {
1279 if (this == null) throw new TypeError();
1280 iterator
= iterator
|| Prototype
.K
;
1282 var object
= Object(this);
1283 var results
= [], context
= arguments
[1], n
= 0;
1285 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1287 results
[n
] = iterator
.call(context
, object
[i
], i
, object
);
1295 if (arrayProto
.map
) {
1296 map
= wrapNative(Array
.prototype.map
);
1299 function filter(iterator
) {
1300 if (this == null || !Object
.isFunction(iterator
))
1301 throw new TypeError();
1303 var object
= Object(this);
1304 var results
= [], context
= arguments
[1], value
;
1306 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1309 if (iterator
.call(context
, value
, i
, object
)) {
1310 results
.push(value
);
1317 if (arrayProto
.filter
) {
1318 filter
= Array
.prototype.filter
;
1321 function some(iterator
) {
1322 if (this == null) throw new TypeError();
1323 iterator
= iterator
|| Prototype
.K
;
1324 var context
= arguments
[1];
1326 var object
= Object(this);
1327 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1328 if (i
in object
&& iterator
.call(context
, object
[i
], i
, object
)) {
1336 if (arrayProto
.some
) {
1337 some
= wrapNative(Array
.prototype.some
);
1340 function every(iterator
) {
1341 if (this == null) throw new TypeError();
1342 iterator
= iterator
|| Prototype
.K
;
1343 var context
= arguments
[1];
1345 var object
= Object(this);
1346 for (var i
= 0, length
= object
.length
>>> 0; i
< length
; i
++) {
1347 if (i
in object
&& !iterator
.call(context
, object
[i
], i
, object
)) {
1355 if (arrayProto
.every
) {
1356 every
= wrapNative(Array
.prototype.every
);
1360 Object
.extend(arrayProto
, Enumerable
);
1362 if (arrayProto
.entries
=== Enumerable
.entries
) {
1363 delete arrayProto
.entries
;
1366 if (!arrayProto
._reverse
)
1367 arrayProto
._reverse
= arrayProto
.reverse
;
1369 Object
.extend(arrayProto
, {
1390 intersect
: intersect
,
1397 var CONCAT_ARGUMENTS_BUGGY
= (function() {
1398 return [].concat(arguments
)[0][0] !== 1;
1401 if (CONCAT_ARGUMENTS_BUGGY
) arrayProto
.concat
= concat
;
1403 if (!arrayProto
.indexOf
) arrayProto
.indexOf
= indexOf
;
1404 if (!arrayProto
.lastIndexOf
) arrayProto
.lastIndexOf
= lastIndexOf
;
1406 function $H(object
) {
1407 return new Hash(object
);
1410 var Hash
= Class
.create(Enumerable
, (function() {
1411 function initialize(object
) {
1412 this._object
= Object
.isHash(object
) ? object
.toObject() : Object
.clone(object
);
1416 function _each(iterator
, context
) {
1418 for (var key
in this._object
) {
1419 var value
= this._object
[key
], pair
= [key
, value
];
1422 iterator
.call(context
, pair
, i
);
1427 function set(key
, value
) {
1428 return this._object
[key
] = value
;
1432 if (this._object
[key
] !== Object
.prototype[key
])
1433 return this._object
[key
];
1436 function unset(key
) {
1437 var value
= this._object
[key
];
1438 delete this._object
[key
];
1442 function toObject() {
1443 return Object
.clone(this._object
);
1449 return this.pluck('key');
1453 return this.pluck('value');
1456 function index(value
) {
1457 var match
= this.detect(function(pair
) {
1458 return pair
.value
=== value
;
1460 return match
&& match
.key
;
1463 function merge(object
) {
1464 return this.clone().update(object
);
1467 function update(object
) {
1468 return new Hash(object
).inject(this, function(result
, pair
) {
1469 result
.set(pair
.key
, pair
.value
);
1474 function toQueryPair(key
, value
) {
1475 if (Object
.isUndefined(value
)) return key
;
1477 value
= String
.interpret(value
);
1479 value
= value
.gsub(/(\r)?\n/, '\r\n');
1480 value
= encodeURIComponent(value
);
1481 value
= value
.gsub(/%20/, '+');
1482 return key
+ '=' + value
;
1485 function toQueryString() {
1486 return this.inject([], function(results
, pair
) {
1487 var key
= encodeURIComponent(pair
.key
), values
= pair
.value
;
1489 if (values
&& typeof values
== 'object') {
1490 if (Object
.isArray(values
)) {
1491 var queryValues
= [];
1492 for (var i
= 0, len
= values
.length
, value
; i
< len
; i
++) {
1494 queryValues
.push(toQueryPair(key
, value
));
1496 return results
.concat(queryValues
);
1498 } else results
.push(toQueryPair(key
, values
));
1503 function inspect() {
1504 return '#<Hash:{' + this.map(function(pair
) {
1505 return pair
.map(Object
.inspect
).join(': ');
1506 }).join(', ') + '}>';
1510 return new Hash(this);
1514 initialize
: initialize
,
1520 toTemplateReplacements
: toObject
,
1526 toQueryString
: toQueryString
,
1534 Object
.extend(Number
.prototype, (function() {
1535 function toColorPart() {
1536 return this.toPaddedString(2, 16);
1543 function times(iterator
, context
) {
1544 $R(0, this, true).each(iterator
, context
);
1548 function toPaddedString(length
, radix
) {
1549 var string
= this.toString(radix
|| 10);
1550 return '0'.times(length
- string
.length
) + string
;
1554 return Math
.abs(this);
1558 return Math
.round(this);
1562 return Math
.ceil(this);
1566 return Math
.floor(this);
1570 toColorPart
: toColorPart
,
1573 toPaddedString
: toPaddedString
,
1581 function $R(start
, end
, exclusive
) {
1582 return new ObjectRange(start
, end
, exclusive
);
1585 var ObjectRange
= Class
.create(Enumerable
, (function() {
1586 function initialize(start
, end
, exclusive
) {
1589 this.exclusive
= exclusive
;
1592 function _each(iterator
, context
) {
1593 var value
= this.start
, i
;
1594 for (i
= 0; this.include(value
); i
++) {
1595 iterator
.call(context
, value
, i
);
1596 value
= value
.succ();
1600 function include(value
) {
1601 if (value
< this.start
)
1604 return value
< this.end
;
1605 return value
<= this.end
;
1609 initialize
: initialize
,
1624 for (var i
= 0, length
= arguments
.length
; i
< length
; i
++) {
1625 var lambda
= arguments
[i
];
1627 returnValue
= lambda();
1637 getTransport: function() {
1639 function() {return new XMLHttpRequest()},
1640 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1641 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1645 activeRequestCount
: 0
1651 _each: function(iterator
, context
) {
1652 this.responders
._each(iterator
, context
);
1655 register: function(responder
) {
1656 if (!this.include(responder
))
1657 this.responders
.push(responder
);
1660 unregister: function(responder
) {
1661 this.responders
= this.responders
.without(responder
);
1664 dispatch: function(callback
, request
, transport
, json
) {
1665 this.each(function(responder
) {
1666 if (Object
.isFunction(responder
[callback
])) {
1668 responder
[callback
].apply(responder
, [request
, transport
, json
]);
1675 Object
.extend(Ajax
.Responders
, Enumerable
);
1677 Ajax
.Responders
.register({
1678 onCreate: function() { Ajax
.activeRequestCount
++ },
1679 onComplete: function() { Ajax
.activeRequestCount
-- }
1681 Ajax
.Base
= Class
.create({
1682 initialize: function(options
) {
1686 contentType
: 'application/x-www-form-urlencoded',
1692 Object
.extend(this.options
, options
|| { });
1694 this.options
.method
= this.options
.method
.toLowerCase();
1696 if (Object
.isHash(this.options
.parameters
))
1697 this.options
.parameters
= this.options
.parameters
.toObject();
1700 Ajax
.Request
= Class
.create(Ajax
.Base
, {
1703 initialize: function($super, url
, options
) {
1705 this.transport
= Ajax
.getTransport();
1709 request: function(url
) {
1711 this.method
= this.options
.method
;
1712 var params
= Object
.isString(this.options
.parameters
) ?
1713 this.options
.parameters
:
1714 Object
.toQueryString(this.options
.parameters
);
1716 if (!['get', 'post'].include(this.method
)) {
1717 params
+= (params
? '&' : '') + "_method=" + this.method
;
1718 this.method
= 'post';
1721 if (params
&& this.method
=== 'get') {
1722 this.url
+= (this.url
.include('?') ? '&' : '?') + params
;
1725 this.parameters
= params
.toQueryParams();
1728 var response
= new Ajax
.Response(this);
1729 if (this.options
.onCreate
) this.options
.onCreate(response
);
1730 Ajax
.Responders
.dispatch('onCreate', this, response
);
1732 this.transport
.open(this.method
.toUpperCase(), this.url
,
1733 this.options
.asynchronous
);
1735 if (this.options
.asynchronous
) this.respondToReadyState
.bind(this).defer(1);
1737 this.transport
.onreadystatechange
= this.onStateChange
.bind(this);
1738 this.setRequestHeaders();
1740 this.body
= this.method
== 'post' ? (this.options
.postBody
|| params
) : null;
1741 this.transport
.send(this.body
);
1743 /* Force Firefox to handle ready state 4 for synchronous requests */
1744 if (!this.options
.asynchronous
&& this.transport
.overrideMimeType
)
1745 this.onStateChange();
1749 this.dispatchException(e
);
1753 onStateChange: function() {
1754 var readyState
= this.transport
.readyState
;
1755 if (readyState
> 1 && !((readyState
== 4) && this._complete
))
1756 this.respondToReadyState(this.transport
.readyState
);
1759 setRequestHeaders: function() {
1761 'X-Requested-With': 'XMLHttpRequest',
1762 'X-Prototype-Version': Prototype
.Version
,
1763 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1766 if (this.method
== 'post') {
1767 headers
['Content-type'] = this.options
.contentType
+
1768 (this.options
.encoding
? '; charset=' + this.options
.encoding
: '');
1770 /* Force "Connection: close" for older Mozilla browsers to work
1771 * around a bug where XMLHttpRequest sends an incorrect
1772 * Content-length header. See Mozilla Bugzilla #246651.
1774 if (this.transport
.overrideMimeType
&&
1775 (navigator
.userAgent
.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1776 headers
['Connection'] = 'close';
1779 if (typeof this.options
.requestHeaders
== 'object') {
1780 var extras
= this.options
.requestHeaders
;
1782 if (Object
.isFunction(extras
.push
))
1783 for (var i
= 0, length
= extras
.length
; i
< length
; i
+= 2)
1784 headers
[extras
[i
]] = extras
[i
+1];
1786 $H(extras
).each(function(pair
) { headers
[pair
.key
] = pair
.value
});
1789 for (var name
in headers
)
1790 if (headers
[name
] != null)
1791 this.transport
.setRequestHeader(name
, headers
[name
]);
1794 success: function() {
1795 var status
= this.getStatus();
1796 return !status
|| (status
>= 200 && status
< 300) || status
== 304;
1799 getStatus: function() {
1801 if (this.transport
.status
=== 1223) return 204;
1802 return this.transport
.status
|| 0;
1803 } catch (e
) { return 0 }
1806 respondToReadyState: function(readyState
) {
1807 var state
= Ajax
.Request
.Events
[readyState
], response
= new Ajax
.Response(this);
1809 if (state
== 'Complete') {
1811 this._complete
= true;
1812 (this.options
['on' + response
.status
]
1813 || this.options
['on' + (this.success() ? 'Success' : 'Failure')]
1814 || Prototype
.emptyFunction
)(response
, response
.headerJSON
);
1816 this.dispatchException(e
);
1819 var contentType
= response
.getHeader('Content-type');
1820 if (this.options
.evalJS
== 'force'
1821 || (this.options
.evalJS
&& this.isSameOrigin() && contentType
1822 && contentType
.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1823 this.evalResponse();
1827 (this.options
['on' + state
] || Prototype
.emptyFunction
)(response
, response
.headerJSON
);
1828 Ajax
.Responders
.dispatch('on' + state
, this, response
, response
.headerJSON
);
1830 this.dispatchException(e
);
1833 if (state
== 'Complete') {
1834 this.transport
.onreadystatechange
= Prototype
.emptyFunction
;
1838 isSameOrigin: function() {
1839 var m
= this.url
.match(/^\s*https?:\/\/[^\/]*/);
1840 return !m
|| (m
[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1841 protocol
: location
.protocol
,
1842 domain
: document
.domain
,
1843 port
: location
.port
? ':' + location
.port
: ''
1847 getHeader: function(name
) {
1849 return this.transport
.getResponseHeader(name
) || null;
1850 } catch (e
) { return null; }
1853 evalResponse: function() {
1855 return eval((this.transport
.responseText
|| '').unfilterJSON());
1857 this.dispatchException(e
);
1861 dispatchException: function(exception
) {
1862 (this.options
.onException
|| Prototype
.emptyFunction
)(this, exception
);
1863 Ajax
.Responders
.dispatch('onException', this, exception
);
1867 Ajax
.Request
.Events
=
1868 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1877 Ajax
.Response
= Class
.create({
1878 initialize: function(request
){
1879 this.request
= request
;
1880 var transport
= this.transport
= request
.transport
,
1881 readyState
= this.readyState
= transport
.readyState
;
1883 if ((readyState
> 2 && !Prototype
.Browser
.IE
) || readyState
== 4) {
1884 this.status
= this.getStatus();
1885 this.statusText
= this.getStatusText();
1886 this.responseText
= String
.interpret(transport
.responseText
);
1887 this.headerJSON
= this._getHeaderJSON();
1890 if (readyState
== 4) {
1891 var xml
= transport
.responseXML
;
1892 this.responseXML
= Object
.isUndefined(xml
) ? null : xml
;
1893 this.responseJSON
= this._getResponseJSON();
1901 getStatus
: Ajax
.Request
.prototype.getStatus
,
1903 getStatusText: function() {
1905 return this.transport
.statusText
|| '';
1906 } catch (e
) { return '' }
1909 getHeader
: Ajax
.Request
.prototype.getHeader
,
1911 getAllHeaders: function() {
1913 return this.getAllResponseHeaders();
1914 } catch (e
) { return null }
1917 getResponseHeader: function(name
) {
1918 return this.transport
.getResponseHeader(name
);
1921 getAllResponseHeaders: function() {
1922 return this.transport
.getAllResponseHeaders();
1925 _getHeaderJSON: function() {
1926 var json
= this.getHeader('X-JSON');
1927 if (!json
) return null;
1930 json
= decodeURIComponent(escape(json
));
1935 return json
.evalJSON(this.request
.options
.sanitizeJSON
||
1936 !this.request
.isSameOrigin());
1938 this.request
.dispatchException(e
);
1942 _getResponseJSON: function() {
1943 var options
= this.request
.options
;
1944 if (!options
.evalJSON
|| (options
.evalJSON
!= 'force' &&
1945 !(this.getHeader('Content-type') || '').include('application/json')) ||
1946 this.responseText
.blank())
1949 return this.responseText
.evalJSON(options
.sanitizeJSON
||
1950 !this.request
.isSameOrigin());
1952 this.request
.dispatchException(e
);
1957 Ajax
.Updater
= Class
.create(Ajax
.Request
, {
1958 initialize: function($super, container
, url
, options
) {
1960 success
: (container
.success
|| container
),
1961 failure
: (container
.failure
|| (container
.success
? null : container
))
1964 options
= Object
.clone(options
);
1965 var onComplete
= options
.onComplete
;
1966 options
.onComplete
= (function(response
, json
) {
1967 this.updateContent(response
.responseText
);
1968 if (Object
.isFunction(onComplete
)) onComplete(response
, json
);
1971 $super(url
, options
);
1974 updateContent: function(responseText
) {
1975 var receiver
= this.container
[this.success() ? 'success' : 'failure'],
1976 options
= this.options
;
1978 if (!options
.evalScripts
) responseText
= responseText
.stripScripts();
1980 if (receiver
= $(receiver
)) {
1981 if (options
.insertion
) {
1982 if (Object
.isString(options
.insertion
)) {
1983 var insertion
= { }; insertion
[options
.insertion
] = responseText
;
1984 receiver
.insert(insertion
);
1986 else options
.insertion(receiver
, responseText
);
1988 else receiver
.update(responseText
);
1993 Ajax
.PeriodicalUpdater
= Class
.create(Ajax
.Base
, {
1994 initialize: function($super, container
, url
, options
) {
1996 this.onComplete
= this.options
.onComplete
;
1998 this.frequency
= (this.options
.frequency
|| 2);
1999 this.decay
= (this.options
.decay
|| 1);
2002 this.container
= container
;
2009 this.options
.onComplete
= this.updateComplete
.bind(this);
2010 this.onTimerEvent();
2014 this.updater
.options
.onComplete
= undefined;
2015 clearTimeout(this.timer
);
2016 (this.onComplete
|| Prototype
.emptyFunction
).apply(this, arguments
);
2019 updateComplete: function(response
) {
2020 if (this.options
.decay
) {
2021 this.decay
= (response
.responseText
== this.lastText
?
2022 this.decay
* this.options
.decay
: 1);
2024 this.lastText
= response
.responseText
;
2026 this.timer
= this.onTimerEvent
.bind(this).delay(this.decay
* this.frequency
);
2029 onTimerEvent: function() {
2030 this.updater
= new Ajax
.Updater(this.container
, this.url
, this.options
);
2037 var SLICE
= Array
.prototype.slice
;
2039 var DIV
= document
.createElement('div');
2042 function $(element
) {
2043 if (arguments
.length
> 1) {
2044 for (var i
= 0, elements
= [], length
= arguments
.length
; i
< length
; i
++)
2045 elements
.push($(arguments
[i
]));
2049 if (Object
.isString(element
))
2050 element
= document
.getElementById(element
);
2051 return Element
.extend(element
);
2057 if (!GLOBAL
.Node
) GLOBAL
.Node
= {};
2059 if (!GLOBAL
.Node
.ELEMENT_NODE
) {
2060 Object
.extend(GLOBAL
.Node
, {
2064 CDATA_SECTION_NODE
: 4,
2065 ENTITY_REFERENCE_NODE
: 5,
2067 PROCESSING_INSTRUCTION_NODE
: 7,
2070 DOCUMENT_TYPE_NODE
: 10,
2071 DOCUMENT_FRAGMENT_NODE
: 11,
2076 var ELEMENT_CACHE
= {};
2078 function shouldUseCreationCache(tagName
, attributes
) {
2079 if (tagName
=== 'select') return false;
2080 if ('type' in attributes
) return false;
2084 var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
= (function(){
2086 var el
= document
.createElement('<input name="x">');
2087 return el
.tagName
.toLowerCase() === 'input' && el
.name
=== 'x';
2095 var oldElement
= GLOBAL
.Element
;
2096 function Element(tagName
, attributes
) {
2097 attributes
= attributes
|| {};
2098 tagName
= tagName
.toLowerCase();
2100 if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
&& attributes
.name
) {
2101 tagName
= '<' + tagName
+ ' name="' + attributes
.name
+ '">';
2102 delete attributes
.name
;
2103 return Element
.writeAttribute(document
.createElement(tagName
), attributes
);
2106 if (!ELEMENT_CACHE
[tagName
])
2107 ELEMENT_CACHE
[tagName
] = Element
.extend(document
.createElement(tagName
));
2109 var node
= shouldUseCreationCache(tagName
, attributes
) ?
2110 ELEMENT_CACHE
[tagName
].cloneNode(false) : document
.createElement(tagName
);
2112 return Element
.writeAttribute(node
, attributes
);
2115 GLOBAL
.Element
= Element
;
2117 Object
.extend(GLOBAL
.Element
, oldElement
|| {});
2118 if (oldElement
) GLOBAL
.Element
.prototype = oldElement
.prototype;
2120 Element
.Methods
= { ByTag
: {}, Simulated
: {} };
2124 var INSPECT_ATTRIBUTES
= { id
: 'id', className
: 'class' };
2125 function inspect(element
) {
2126 element
= $(element
);
2127 var result
= '<' + element
.tagName
.toLowerCase();
2129 var attribute
, value
;
2130 for (var property
in INSPECT_ATTRIBUTES
) {
2131 attribute
= INSPECT_ATTRIBUTES
[property
];
2132 value
= (element
[property
] || '').toString();
2133 if (value
) result
+= ' ' + attribute
+ '=' + value
.inspect(true);
2136 return result
+ '>';
2139 methods
.inspect
= inspect
;
2142 function visible(element
) {
2143 return $(element
).getStyle('display') !== 'none';
2146 function toggle(element
, bool
) {
2147 element
= $(element
);
2148 if (typeof bool
!== 'boolean')
2149 bool
= !Element
.visible(element
);
2150 Element
[bool
? 'show' : 'hide'](element
);
2155 function hide(element
) {
2156 element
= $(element
);
2157 element
.style
.display
= 'none';
2161 function show(element
) {
2162 element
= $(element
);
2163 element
.style
.display
= '';
2168 Object
.extend(methods
, {
2176 function remove(element
) {
2177 element
= $(element
);
2178 element
.parentNode
.removeChild(element
);
2182 var SELECT_ELEMENT_INNERHTML_BUGGY
= (function(){
2183 var el
= document
.createElement("select"),
2185 el
.innerHTML
= "<option value=\"test\">test</option>";
2186 if (el
.options
&& el
.options
[0]) {
2187 isBuggy
= el
.options
[0].nodeName
.toUpperCase() !== "OPTION";
2193 var TABLE_ELEMENT_INNERHTML_BUGGY
= (function(){
2195 var el
= document
.createElement("table");
2196 if (el
&& el
.tBodies
) {
2197 el
.innerHTML
= "<tbody><tr><td>test</td></tr></tbody>";
2198 var isBuggy
= typeof el
.tBodies
[0] == "undefined";
2207 var LINK_ELEMENT_INNERHTML_BUGGY
= (function() {
2209 var el
= document
.createElement('div');
2210 el
.innerHTML
= "<link />";
2211 var isBuggy
= (el
.childNodes
.length
=== 0);
2219 var ANY_INNERHTML_BUGGY
= SELECT_ELEMENT_INNERHTML_BUGGY
||
2220 TABLE_ELEMENT_INNERHTML_BUGGY
|| LINK_ELEMENT_INNERHTML_BUGGY
;
2222 var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING
= (function () {
2223 var s
= document
.createElement("script"),
2226 s
.appendChild(document
.createTextNode(""));
2227 isBuggy
= !s
.firstChild
||
2228 s
.firstChild
&& s
.firstChild
.nodeType
!== 3;
2236 function update(element
, content
) {
2237 element
= $(element
);
2239 var descendants
= element
.getElementsByTagName('*'),
2240 i
= descendants
.length
;
2241 while (i
--) purgeElement(descendants
[i
]);
2243 if (content
&& content
.toElement
)
2244 content
= content
.toElement();
2246 if (Object
.isElement(content
))
2247 return element
.update().insert(content
);
2250 content
= Object
.toHTML(content
);
2251 var tagName
= element
.tagName
.toUpperCase();
2253 if (tagName
=== 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING
) {
2254 element
.text
= content
;
2258 if (ANY_INNERHTML_BUGGY
) {
2259 if (tagName
in INSERTION_TRANSLATIONS
.tags
) {
2260 while (element
.firstChild
)
2261 element
.removeChild(element
.firstChild
);
2263 var nodes
= getContentFromAnonymousElement(tagName
, content
.stripScripts());
2264 for (var i
= 0, node
; node
= nodes
[i
]; i
++)
2265 element
.appendChild(node
);
2267 } else if (LINK_ELEMENT_INNERHTML_BUGGY
&& Object
.isString(content
) && content
.indexOf('<link') > -1) {
2268 while (element
.firstChild
)
2269 element
.removeChild(element
.firstChild
);
2271 var nodes
= getContentFromAnonymousElement(tagName
,
2272 content
.stripScripts(), true);
2274 for (var i
= 0, node
; node
= nodes
[i
]; i
++)
2275 element
.appendChild(node
);
2277 element
.innerHTML
= content
.stripScripts();
2280 element
.innerHTML
= content
.stripScripts();
2283 content
.evalScripts
.bind(content
).defer();
2287 function replace(element
, content
) {
2288 element
= $(element
);
2290 if (content
&& content
.toElement
) {
2291 content
= content
.toElement();
2292 } else if (!Object
.isElement(content
)) {
2293 content
= Object
.toHTML(content
);
2294 var range
= element
.ownerDocument
.createRange();
2295 range
.selectNode(element
);
2296 content
.evalScripts
.bind(content
).defer();
2297 content
= range
.createContextualFragment(content
.stripScripts());
2300 element
.parentNode
.replaceChild(content
, element
);
2304 var INSERTION_TRANSLATIONS
= {
2305 before: function(element
, node
) {
2306 element
.parentNode
.insertBefore(node
, element
);
2308 top: function(element
, node
) {
2309 element
.insertBefore(node
, element
.firstChild
);
2311 bottom: function(element
, node
) {
2312 element
.appendChild(node
);
2314 after: function(element
, node
) {
2315 element
.parentNode
.insertBefore(node
, element
.nextSibling
);
2319 TABLE
: ['<table>', '</table>', 1],
2320 TBODY
: ['<table><tbody>', '</tbody></table>', 2],
2321 TR
: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2322 TD
: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2323 SELECT
: ['<select>', '</select>', 1]
2327 var tags
= INSERTION_TRANSLATIONS
.tags
;
2329 Object
.extend(tags
, {
2335 function replace_IE(element
, content
) {
2336 element
= $(element
);
2337 if (content
&& content
.toElement
)
2338 content
= content
.toElement();
2339 if (Object
.isElement(content
)) {
2340 element
.parentNode
.replaceChild(content
, element
);
2344 content
= Object
.toHTML(content
);
2345 var parent
= element
.parentNode
, tagName
= parent
.tagName
.toUpperCase();
2347 if (tagName
in INSERTION_TRANSLATIONS
.tags
) {
2348 var nextSibling
= Element
.next(element
);
2349 var fragments
= getContentFromAnonymousElement(
2350 tagName
, content
.stripScripts());
2352 parent
.removeChild(element
);
2356 iterator = function(node
) { parent
.insertBefore(node
, nextSibling
) };
2358 iterator = function(node
) { parent
.appendChild(node
); }
2360 fragments
.each(iterator
);
2362 element
.outerHTML
= content
.stripScripts();
2365 content
.evalScripts
.bind(content
).defer();
2369 if ('outerHTML' in document
.documentElement
)
2370 replace
= replace_IE
;
2372 function isContent(content
) {
2373 if (Object
.isUndefined(content
) || content
=== null) return false;
2375 if (Object
.isString(content
) || Object
.isNumber(content
)) return true;
2376 if (Object
.isElement(content
)) return true;
2377 if (content
.toElement
|| content
.toHTML
) return true;
2382 function insertContentAt(element
, content
, position
) {
2383 position
= position
.toLowerCase();
2384 var method
= INSERTION_TRANSLATIONS
[position
];
2386 if (content
&& content
.toElement
) content
= content
.toElement();
2387 if (Object
.isElement(content
)) {
2388 method(element
, content
);
2392 content
= Object
.toHTML(content
);
2393 var tagName
= ((position
=== 'before' || position
=== 'after') ?
2394 element
.parentNode
: element
).tagName
.toUpperCase();
2396 var childNodes
= getContentFromAnonymousElement(tagName
, content
.stripScripts());
2398 if (position
=== 'top' || position
=== 'after') childNodes
.reverse();
2400 for (var i
= 0, node
; node
= childNodes
[i
]; i
++)
2401 method(element
, node
);
2403 content
.evalScripts
.bind(content
).defer();
2406 function insert(element
, insertions
) {
2407 element
= $(element
);
2409 if (isContent(insertions
))
2410 insertions
= { bottom
: insertions
};
2412 for (var position
in insertions
)
2413 insertContentAt(element
, insertions
[position
], position
);
2418 function wrap(element
, wrapper
, attributes
) {
2419 element
= $(element
);
2421 if (Object
.isElement(wrapper
)) {
2422 $(wrapper
).writeAttribute(attributes
|| {});
2423 } else if (Object
.isString(wrapper
)) {
2424 wrapper
= new Element(wrapper
, attributes
);
2426 wrapper
= new Element('div', wrapper
);
2429 if (element
.parentNode
)
2430 element
.parentNode
.replaceChild(wrapper
, element
);
2432 wrapper
.appendChild(element
);
2437 function cleanWhitespace(element
) {
2438 element
= $(element
);
2439 var node
= element
.firstChild
;
2442 var nextNode
= node
.nextSibling
;
2443 if (node
.nodeType
=== Node
.TEXT_NODE
&& !/\S/.test(node
.nodeValue
))
2444 element
.removeChild(node
);
2450 function empty(element
) {
2451 return $(element
).innerHTML
.blank();
2454 function getContentFromAnonymousElement(tagName
, html
, force
) {
2455 var t
= INSERTION_TRANSLATIONS
.tags
[tagName
], div
= DIV
;
2457 var workaround
= !!t
;
2458 if (!workaround
&& force
) {
2464 div
.innerHTML
= ' ' + t
[0] + html
+ t
[1];
2465 div
.removeChild(div
.firstChild
);
2466 for (var i
= t
[2]; i
--; )
2467 div
= div
.firstChild
;
2469 div
.innerHTML
= html
;
2472 return $A(div
.childNodes
);
2475 function clone(element
, deep
) {
2476 if (!(element
= $(element
))) return;
2477 var clone
= element
.cloneNode(deep
);
2478 if (!HAS_UNIQUE_ID_PROPERTY
) {
2479 clone
._prototypeUID
= UNDEFINED
;
2481 var descendants
= Element
.select(clone
, '*'),
2482 i
= descendants
.length
;
2484 descendants
[i
]._prototypeUID
= UNDEFINED
;
2487 return Element
.extend(clone
);
2490 function purgeElement(element
) {
2491 var uid
= getUniqueElementID(element
);
2493 Element
.stopObserving(element
);
2494 if (!HAS_UNIQUE_ID_PROPERTY
)
2495 element
._prototypeUID
= UNDEFINED
;
2496 delete Element
.Storage
[uid
];
2500 function purgeCollection(elements
) {
2501 var i
= elements
.length
;
2503 purgeElement(elements
[i
]);
2506 function purgeCollection_IE(elements
) {
2507 var i
= elements
.length
, element
, uid
;
2509 element
= elements
[i
];
2510 uid
= getUniqueElementID(element
);
2511 delete Element
.Storage
[uid
];
2512 delete Event
.cache
[uid
];
2516 if (HAS_UNIQUE_ID_PROPERTY
) {
2517 purgeCollection
= purgeCollection_IE
;
2521 function purge(element
) {
2522 if (!(element
= $(element
))) return;
2523 purgeElement(element
);
2525 var descendants
= element
.getElementsByTagName('*'),
2526 i
= descendants
.length
;
2528 while (i
--) purgeElement(descendants
[i
]);
2533 Object
.extend(methods
, {
2539 cleanWhitespace
: cleanWhitespace
,
2547 function recursivelyCollect(element
, property
, maximumLength
) {
2548 element
= $(element
);
2549 maximumLength
= maximumLength
|| -1;
2552 while (element
= element
[property
]) {
2553 if (element
.nodeType
=== Node
.ELEMENT_NODE
)
2554 elements
.push(Element
.extend(element
));
2556 if (elements
.length
=== maximumLength
) break;
2563 function ancestors(element
) {
2564 return recursivelyCollect(element
, 'parentNode');
2567 function descendants(element
) {
2568 return Element
.select(element
, '*');
2571 function firstDescendant(element
) {
2572 element
= $(element
).firstChild
;
2573 while (element
&& element
.nodeType
!== Node
.ELEMENT_NODE
)
2574 element
= element
.nextSibling
;
2579 function immediateDescendants(element
) {
2580 var results
= [], child
= $(element
).firstChild
;
2583 if (child
.nodeType
=== Node
.ELEMENT_NODE
)
2584 results
.push(Element
.extend(child
));
2586 child
= child
.nextSibling
;
2592 function previousSiblings(element
) {
2593 return recursivelyCollect(element
, 'previousSibling');
2596 function nextSiblings(element
) {
2597 return recursivelyCollect(element
, 'nextSibling');
2600 function siblings(element
) {
2601 element
= $(element
);
2602 var previous
= previousSiblings(element
),
2603 next
= nextSiblings(element
);
2604 return previous
.reverse().concat(next
);
2607 function match(element
, selector
) {
2608 element
= $(element
);
2610 if (Object
.isString(selector
))
2611 return Prototype
.Selector
.match(element
, selector
);
2613 return selector
.match(element
);
2617 function _recursivelyFind(element
, property
, expression
, index
) {
2618 element
= $(element
), expression
= expression
|| 0, index
= index
|| 0;
2619 if (Object
.isNumber(expression
)) {
2620 index
= expression
, expression
= null;
2623 while (element
= element
[property
]) {
2624 if (element
.nodeType
!== 1) continue;
2625 if (expression
&& !Prototype
.Selector
.match(element
, expression
))
2627 if (--index
>= 0) continue;
2629 return Element
.extend(element
);
2634 function up(element
, expression
, index
) {
2635 element
= $(element
);
2637 if (arguments
.length
=== 1) return $(element
.parentNode
);
2638 return _recursivelyFind(element
, 'parentNode', expression
, index
);
2641 function down(element
, expression
, index
) {
2642 if (arguments
.length
=== 1) return firstDescendant(element
);
2643 element
= $(element
), expression
= expression
|| 0, index
= index
|| 0;
2645 if (Object
.isNumber(expression
))
2646 index
= expression
, expression
= '*';
2648 var node
= Prototype
.Selector
.select(expression
, element
)[index
];
2649 return Element
.extend(node
);
2652 function previous(element
, expression
, index
) {
2653 return _recursivelyFind(element
, 'previousSibling', expression
, index
);
2656 function next(element
, expression
, index
) {
2657 return _recursivelyFind(element
, 'nextSibling', expression
, index
);
2660 function select(element
) {
2661 element
= $(element
);
2662 var expressions
= SLICE
.call(arguments
, 1).join(', ');
2663 return Prototype
.Selector
.select(expressions
, element
);
2666 function adjacent(element
) {
2667 element
= $(element
);
2668 var expressions
= SLICE
.call(arguments
, 1).join(', ');
2669 var siblings
= Element
.siblings(element
), results
= [];
2670 for (var i
= 0, sibling
; sibling
= siblings
[i
]; i
++) {
2671 if (Prototype
.Selector
.match(sibling
, expressions
))
2672 results
.push(sibling
);
2678 function descendantOf_DOM(element
, ancestor
) {
2679 element
= $(element
), ancestor
= $(ancestor
);
2680 if (!element
|| !ancestor
) return false;
2681 while (element
= element
.parentNode
)
2682 if (element
=== ancestor
) return true;
2686 function descendantOf_contains(element
, ancestor
) {
2687 element
= $(element
), ancestor
= $(ancestor
);
2688 if (!element
|| !ancestor
) return false;
2689 if (!ancestor
.contains
) return descendantOf_DOM(element
, ancestor
);
2690 return ancestor
.contains(element
) && ancestor
!== element
;
2693 function descendantOf_compareDocumentPosition(element
, ancestor
) {
2694 element
= $(element
), ancestor
= $(ancestor
);
2695 if (!element
|| !ancestor
) return false;
2696 return (element
.compareDocumentPosition(ancestor
) & 8) === 8;
2700 if (DIV
.compareDocumentPosition
) {
2701 descendantOf
= descendantOf_compareDocumentPosition
;
2702 } else if (DIV
.contains
) {
2703 descendantOf
= descendantOf_contains
;
2705 descendantOf
= descendantOf_DOM
;
2709 Object
.extend(methods
, {
2710 recursivelyCollect
: recursivelyCollect
,
2711 ancestors
: ancestors
,
2712 descendants
: descendants
,
2713 firstDescendant
: firstDescendant
,
2714 immediateDescendants
: immediateDescendants
,
2715 previousSiblings
: previousSiblings
,
2716 nextSiblings
: nextSiblings
,
2725 descendantOf
: descendantOf
,
2727 getElementsBySelector
: select
,
2729 childElements
: immediateDescendants
2734 function identify(element
) {
2735 element
= $(element
);
2736 var id
= Element
.readAttribute(element
, 'id');
2739 do { id
= 'anonymous_element_' + idCounter
++ } while ($(id
));
2741 Element
.writeAttribute(element
, 'id', id
);
2746 function readAttribute(element
, name
) {
2747 return $(element
).getAttribute(name
);
2750 function readAttribute_IE(element
, name
) {
2751 element
= $(element
);
2753 var table
= ATTRIBUTE_TRANSLATIONS
.read
;
2754 if (table
.values
[name
])
2755 return table
.values
[name
](element
, name
);
2757 if (table
.names
[name
]) name
= table
.names
[name
];
2759 if (name
.include(':')) {
2760 if (!element
.attributes
|| !element
.attributes
[name
]) return null;
2761 return element
.attributes
[name
].value
;
2764 return element
.getAttribute(name
);
2767 function readAttribute_Opera(element
, name
) {
2768 if (name
=== 'title') return element
.title
;
2769 return element
.getAttribute(name
);
2772 var PROBLEMATIC_ATTRIBUTE_READING
= (function() {
2773 DIV
.setAttribute('onclick', []);
2774 var value
= DIV
.getAttribute('onclick');
2775 var isFunction
= Object
.isArray(value
);
2776 DIV
.removeAttribute('onclick');
2780 if (PROBLEMATIC_ATTRIBUTE_READING
) {
2781 readAttribute
= readAttribute_IE
;
2782 } else if (Prototype
.Browser
.Opera
) {
2783 readAttribute
= readAttribute_Opera
;
2787 function writeAttribute(element
, name
, value
) {
2788 element
= $(element
);
2789 var attributes
= {}, table
= ATTRIBUTE_TRANSLATIONS
.write
;
2791 if (typeof name
=== 'object') {
2794 attributes
[name
] = Object
.isUndefined(value
) ? true : value
;
2797 for (var attr
in attributes
) {
2798 name
= table
.names
[attr
] || attr
;
2799 value
= attributes
[attr
];
2800 if (table
.values
[attr
]) {
2801 value
= table
.values
[attr
](element
, value
);
2802 if (Object
.isUndefined(value
)) continue;
2804 if (value
=== false || value
=== null)
2805 element
.removeAttribute(name
);
2806 else if (value
=== true)
2807 element
.setAttribute(name
, name
);
2808 else element
.setAttribute(name
, value
);
2814 var PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES
= (function () {
2815 if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
) {
2818 var checkbox
= document
.createElement('<input type="checkbox">');
2819 checkbox
.checked
= true;
2820 var node
= checkbox
.getAttributeNode('checked');
2821 return !node
|| !node
.specified
;
2824 function hasAttribute(element
, attribute
) {
2825 attribute
= ATTRIBUTE_TRANSLATIONS
.has
[attribute
] || attribute
;
2826 var node
= $(element
).getAttributeNode(attribute
);
2827 return !!(node
&& node
.specified
);
2830 function hasAttribute_IE(element
, attribute
) {
2831 if (attribute
=== 'checked') {
2832 return element
.checked
;
2834 return hasAttribute(element
, attribute
);
2837 GLOBAL
.Element
.Methods
.Simulated
.hasAttribute
=
2838 PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES
?
2839 hasAttribute_IE
: hasAttribute
;
2841 function classNames(element
) {
2842 return new Element
.ClassNames(element
);
2845 var regExpCache
= {};
2846 function getRegExpForClassName(className
) {
2847 if (regExpCache
[className
]) return regExpCache
[className
];
2849 var re
= new RegExp("(^|\\s+)" + className
+ "(\\s+|$)");
2850 regExpCache
[className
] = re
;
2854 function hasClassName(element
, className
) {
2855 if (!(element
= $(element
))) return;
2857 var elementClassName
= element
.className
;
2859 if (elementClassName
.length
=== 0) return false;
2860 if (elementClassName
=== className
) return true;
2862 return getRegExpForClassName(className
).test(elementClassName
);
2865 function addClassName(element
, className
) {
2866 if (!(element
= $(element
))) return;
2868 if (!hasClassName(element
, className
))
2869 element
.className
+= (element
.className
? ' ' : '') + className
;
2874 function removeClassName(element
, className
) {
2875 if (!(element
= $(element
))) return;
2877 element
.className
= element
.className
.replace(
2878 getRegExpForClassName(className
), ' ').strip();
2883 function toggleClassName(element
, className
, bool
) {
2884 if (!(element
= $(element
))) return;
2886 if (Object
.isUndefined(bool
))
2887 bool
= !hasClassName(element
, className
);
2889 var method
= Element
[bool
? 'addClassName' : 'removeClassName'];
2890 return method(element
, className
);
2893 var ATTRIBUTE_TRANSLATIONS
= {};
2895 var classProp
= 'className', forProp
= 'for';
2897 DIV
.setAttribute(classProp
, 'x');
2898 if (DIV
.className
!== 'x') {
2899 DIV
.setAttribute('class', 'x');
2900 if (DIV
.className
=== 'x')
2901 classProp
= 'class';
2904 var LABEL
= document
.createElement('label');
2905 LABEL
.setAttribute(forProp
, 'x');
2906 if (LABEL
.htmlFor
!== 'x') {
2907 LABEL
.setAttribute('htmlFor', 'x');
2908 if (LABEL
.htmlFor
=== 'x')
2909 forProp
= 'htmlFor';
2913 function _getAttr(element
, attribute
) {
2914 return element
.getAttribute(attribute
);
2917 function _getAttr2(element
, attribute
) {
2918 return element
.getAttribute(attribute
, 2);
2921 function _getAttrNode(element
, attribute
) {
2922 var node
= element
.getAttributeNode(attribute
);
2923 return node
? node
.value
: '';
2926 function _getFlag(element
, attribute
) {
2927 return $(element
).hasAttribute(attribute
) ? attribute
: null;
2930 DIV
.onclick
= Prototype
.emptyFunction
;
2931 var onclickValue
= DIV
.getAttribute('onclick');
2935 if (String(onclickValue
).indexOf('{') > -1) {
2936 _getEv = function(element
, attribute
) {
2937 var value
= element
.getAttribute(attribute
);
2938 if (!value
) return null;
2939 value
= value
.toString();
2940 value
= value
.split('{')[1];
2941 value
= value
.split('}')[0];
2942 return value
.strip();
2945 else if (onclickValue
=== '') {
2946 _getEv = function(element
, attribute
) {
2947 var value
= element
.getAttribute(attribute
);
2948 if (!value
) return null;
2949 return value
.strip();
2953 ATTRIBUTE_TRANSLATIONS
.read
= {
2956 'className': classProp
,
2962 style: function(element
) {
2963 return element
.style
.cssText
.toLowerCase();
2965 title: function(element
) {
2966 return element
.title
;
2971 ATTRIBUTE_TRANSLATIONS
.write
= {
2975 cellpadding
: 'cellPadding',
2976 cellspacing
: 'cellSpacing'
2980 checked: function(element
, value
) {
2982 element
.checked
= value
;
2983 return value
? 'checked' : null;
2986 style: function(element
, value
) {
2987 element
.style
.cssText
= value
? value
: '';
2992 ATTRIBUTE_TRANSLATIONS
.has
= { names
: {} };
2994 Object
.extend(ATTRIBUTE_TRANSLATIONS
.write
.names
,
2995 ATTRIBUTE_TRANSLATIONS
.read
.names
);
2997 var CAMEL_CASED_ATTRIBUTE_NAMES
= $w('colSpan rowSpan vAlign dateTime ' +
2998 'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
3000 for (var i
= 0, attr
; attr
= CAMEL_CASED_ATTRIBUTE_NAMES
[i
]; i
++) {
3001 ATTRIBUTE_TRANSLATIONS
.write
.names
[attr
.toLowerCase()] = attr
;
3002 ATTRIBUTE_TRANSLATIONS
.has
.names
[attr
.toLowerCase()] = attr
;
3005 Object
.extend(ATTRIBUTE_TRANSLATIONS
.read
.values
, {
3009 action
: _getAttrNode
,
3018 onmousedown
: _getEv
,
3020 onmouseover
: _getEv
,
3021 onmousemove
: _getEv
,
3035 Object
.extend(methods
, {
3037 readAttribute
: readAttribute
,
3038 writeAttribute
: writeAttribute
,
3039 classNames
: classNames
,
3040 hasClassName
: hasClassName
,
3041 addClassName
: addClassName
,
3042 removeClassName
: removeClassName
,
3043 toggleClassName
: toggleClassName
3047 function normalizeStyleName(style
) {
3048 if (style
=== 'float' || style
=== 'styleFloat')
3050 return style
.camelize();
3053 function normalizeStyleName_IE(style
) {
3054 if (style
=== 'float' || style
=== 'cssFloat')
3055 return 'styleFloat';
3056 return style
.camelize();
3059 function setStyle(element
, styles
) {
3060 element
= $(element
);
3061 var elementStyle
= element
.style
, match
;
3063 if (Object
.isString(styles
)) {
3064 elementStyle
.cssText
+= ';' + styles
;
3065 if (styles
.include('opacity')) {
3066 var opacity
= styles
.match(/opacity:\s*(\d?\.?\d*)/)[1];
3067 Element
.setOpacity(element
, opacity
);
3072 for (var property
in styles
) {
3073 if (property
=== 'opacity') {
3074 Element
.setOpacity(element
, styles
[property
]);
3076 var value
= styles
[property
];
3077 if (property
=== 'float' || property
=== 'cssFloat') {
3078 property
= Object
.isUndefined(elementStyle
.styleFloat
) ?
3079 'cssFloat' : 'styleFloat';
3081 elementStyle
[property
] = value
;
3089 function getStyle(element
, style
) {
3090 element
= $(element
);
3091 style
= normalizeStyleName(style
);
3093 var value
= element
.style
[style
];
3094 if (!value
|| value
=== 'auto') {
3095 var css
= document
.defaultView
.getComputedStyle(element
, null);
3096 value
= css
? css
[style
] : null;
3099 if (style
=== 'opacity') return value
? parseFloat(value
) : 1.0;
3100 return value
=== 'auto' ? null : value
;
3103 function getStyle_Opera(element
, style
) {
3105 case 'height': case 'width':
3106 if (!Element
.visible(element
)) return null;
3108 var dim
= parseInt(getStyle(element
, style
), 10);
3110 if (dim
!== element
['offset' + style
.capitalize()])
3113 return Element
.measure(element
, style
);
3115 default: return getStyle(element
, style
);
3119 function getStyle_IE(element
, style
) {
3120 element
= $(element
);
3121 style
= normalizeStyleName_IE(style
);
3123 var value
= element
.style
[style
];
3124 if (!value
&& element
.currentStyle
) {
3125 value
= element
.currentStyle
[style
];
3128 if (style
=== 'opacity') {
3129 if (!STANDARD_CSS_OPACITY_SUPPORTED
)
3130 return getOpacity_IE(element
);
3131 else return value
? parseFloat(value
) : 1.0;
3134 if (value
=== 'auto') {
3135 if ((style
=== 'width' || style
=== 'height') && Element
.visible(element
))
3136 return Element
.measure(element
, style
) + 'px';
3143 function stripAlphaFromFilter_IE(filter
) {
3144 return (filter
|| '').replace(/alpha\([^\)]*\)/gi, '');
3147 function hasLayout_IE(element
) {
3148 if (!element
.currentStyle
|| !element
.currentStyle
.hasLayout
)
3149 element
.style
.zoom
= 1;
3153 var STANDARD_CSS_OPACITY_SUPPORTED
= (function() {
3154 DIV
.style
.cssText
= "opacity:.55";
3155 return /^0.55/.test(DIV
.style
.opacity
);
3158 function setOpacity(element
, value
) {
3159 element
= $(element
);
3160 if (value
== 1 || value
=== '') value
= '';
3161 else if (value
< 0.00001) value
= 0;
3162 element
.style
.opacity
= value
;
3166 function setOpacity_IE(element
, value
) {
3167 if (STANDARD_CSS_OPACITY_SUPPORTED
)
3168 return setOpacity(element
, value
);
3170 element
= hasLayout_IE($(element
));
3171 var filter
= Element
.getStyle(element
, 'filter'),
3172 style
= element
.style
;
3174 if (value
== 1 || value
=== '') {
3175 filter
= stripAlphaFromFilter_IE(filter
);
3176 if (filter
) style
.filter
= filter
;
3177 else style
.removeAttribute('filter');
3181 if (value
< 0.00001) value
= 0;
3183 style
.filter
= stripAlphaFromFilter_IE(filter
) +
3184 ' alpha(opacity=' + (value
* 100) + ')';
3190 function getOpacity(element
) {
3191 return Element
.getStyle(element
, 'opacity');
3194 function getOpacity_IE(element
) {
3195 if (STANDARD_CSS_OPACITY_SUPPORTED
)
3196 return getOpacity(element
);
3198 var filter
= Element
.getStyle(element
, 'filter');
3199 if (filter
.length
=== 0) return 1.0;
3200 var match
= (filter
|| '').match(/alpha\(opacity=(.*)\)/i);
3201 if (match
&& match
[1]) return parseFloat(match
[1]) / 100;
3206 Object
.extend(methods
, {
3209 setOpacity
: setOpacity
,
3210 getOpacity
: getOpacity
3213 if ('styleFloat' in DIV
.style
) {
3214 methods
.getStyle
= getStyle_IE
;
3215 methods
.setOpacity
= setOpacity_IE
;
3216 methods
.getOpacity
= getOpacity_IE
;
3221 GLOBAL
.Element
.Storage
= { UID
: 1 };
3223 function getUniqueElementID(element
) {
3224 if (element
=== window
) return 0;
3226 if (typeof element
._prototypeUID
=== 'undefined')
3227 element
._prototypeUID
= Element
.Storage
.UID
++;
3228 return element
._prototypeUID
;
3231 function getUniqueElementID_IE(element
) {
3232 if (element
=== window
) return 0;
3233 if (element
== document
) return 1;
3234 return element
.uniqueID
;
3237 var HAS_UNIQUE_ID_PROPERTY
= ('uniqueID' in DIV
);
3238 if (HAS_UNIQUE_ID_PROPERTY
)
3239 getUniqueElementID
= getUniqueElementID_IE
;
3241 function getStorage(element
) {
3242 if (!(element
= $(element
))) return;
3244 var uid
= getUniqueElementID(element
);
3246 if (!Element
.Storage
[uid
])
3247 Element
.Storage
[uid
] = $H();
3249 return Element
.Storage
[uid
];
3252 function store(element
, key
, value
) {
3253 if (!(element
= $(element
))) return;
3254 var storage
= getStorage(element
);
3255 if (arguments
.length
=== 2) {
3256 storage
.update(key
);
3258 storage
.set(key
, value
);
3263 function retrieve(element
, key
, defaultValue
) {
3264 if (!(element
= $(element
))) return;
3265 var storage
= getStorage(element
), value
= storage
.get(key
);
3267 if (Object
.isUndefined(value
)) {
3268 storage
.set(key
, defaultValue
);
3269 value
= defaultValue
;
3276 Object
.extend(methods
, {
3277 getStorage
: getStorage
,
3283 var Methods
= {}, ByTag
= Element
.Methods
.ByTag
,
3284 F
= Prototype
.BrowserFeatures
;
3286 if (!F
.ElementExtensions
&& ('__proto__' in DIV
)) {
3287 GLOBAL
.HTMLElement
= {};
3288 GLOBAL
.HTMLElement
.prototype = DIV
['__proto__'];
3289 F
.ElementExtensions
= true;
3292 function checkElementPrototypeDeficiency(tagName
) {
3293 if (typeof window
.Element
=== 'undefined') return false;
3294 if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
) return false;
3295 var proto
= window
.Element
.prototype;
3297 var id
= '_' + (Math
.random() + '').slice(2),
3298 el
= document
.createElement(tagName
);
3300 var isBuggy
= (el
[id
] !== 'x');
3309 var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY
=
3310 checkElementPrototypeDeficiency('object');
3312 function extendElementWith(element
, methods
) {
3313 for (var property
in methods
) {
3314 var value
= methods
[property
];
3315 if (Object
.isFunction(value
) && !(property
in element
))
3316 element
[property
] = value
.methodize();
3321 function elementIsExtended(element
) {
3322 var uid
= getUniqueElementID(element
);
3323 return (uid
in EXTENDED
);
3326 function extend(element
) {
3327 if (!element
|| elementIsExtended(element
)) return element
;
3328 if (element
.nodeType
!== Node
.ELEMENT_NODE
|| element
== window
)
3331 var methods
= Object
.clone(Methods
),
3332 tagName
= element
.tagName
.toUpperCase();
3334 if (ByTag
[tagName
]) Object
.extend(methods
, ByTag
[tagName
]);
3336 extendElementWith(element
, methods
);
3337 EXTENDED
[getUniqueElementID(element
)] = true;
3341 function extend_IE8(element
) {
3342 if (!element
|| elementIsExtended(element
)) return element
;
3344 var t
= element
.tagName
;
3345 if (t
&& (/^(?:object|applet|embed)$/i.test(t
))) {
3346 extendElementWith(element
, Element
.Methods
);
3347 extendElementWith(element
, Element
.Methods
.Simulated
);
3348 extendElementWith(element
, Element
.Methods
.ByTag
[t
.toUpperCase()]);
3354 if (F
.SpecificElementExtensions
) {
3355 extend
= HTMLOBJECTELEMENT_PROTOTYPE_BUGGY
? extend_IE8
: Prototype
.K
;
3358 function addMethodsToTagName(tagName
, methods
) {
3359 tagName
= tagName
.toUpperCase();
3360 if (!ByTag
[tagName
]) ByTag
[tagName
] = {};
3361 Object
.extend(ByTag
[tagName
], methods
);
3364 function mergeMethods(destination
, methods
, onlyIfAbsent
) {
3365 if (Object
.isUndefined(onlyIfAbsent
)) onlyIfAbsent
= false;
3366 for (var property
in methods
) {
3367 var value
= methods
[property
];
3368 if (!Object
.isFunction(value
)) continue;
3369 if (!onlyIfAbsent
|| !(property
in destination
))
3370 destination
[property
] = value
.methodize();
3374 function findDOMClass(tagName
) {
3377 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3378 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3379 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3380 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3381 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3382 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3383 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3384 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3385 "FrameSet", "IFRAME": "IFrame"
3387 if (trans
[tagName
]) klass
= 'HTML' + trans
[tagName
] + 'Element';
3388 if (window
[klass
]) return window
[klass
];
3389 klass
= 'HTML' + tagName
+ 'Element';
3390 if (window
[klass
]) return window
[klass
];
3391 klass
= 'HTML' + tagName
.capitalize() + 'Element';
3392 if (window
[klass
]) return window
[klass
];
3394 var element
= document
.createElement(tagName
),
3395 proto
= element
['__proto__'] || element
.constructor.prototype;
3401 function addMethods(methods
) {
3402 if (arguments
.length
=== 0) addFormMethods();
3404 if (arguments
.length
=== 2) {
3405 var tagName
= methods
;
3406 methods
= arguments
[1];
3410 Object
.extend(Element
.Methods
, methods
|| {});
3412 if (Object
.isArray(tagName
)) {
3413 for (var i
= 0, tag
; tag
= tagName
[i
]; i
++)
3414 addMethodsToTagName(tag
, methods
);
3416 addMethodsToTagName(tagName
, methods
);
3420 var ELEMENT_PROTOTYPE
= window
.HTMLElement
? HTMLElement
.prototype :
3423 if (F
.ElementExtensions
) {
3424 mergeMethods(ELEMENT_PROTOTYPE
, Element
.Methods
);
3425 mergeMethods(ELEMENT_PROTOTYPE
, Element
.Methods
.Simulated
, true);
3428 if (F
.SpecificElementExtensions
) {
3429 for (var tag
in Element
.Methods
.ByTag
) {
3430 var klass
= findDOMClass(tag
);
3431 if (Object
.isUndefined(klass
)) continue;
3432 mergeMethods(klass
.prototype, ByTag
[tag
]);
3436 Object
.extend(Element
, Element
.Methods
);
3437 Object
.extend(Element
, Element
.Methods
.Simulated
);
3438 delete Element
.ByTag
;
3439 delete Element
.Simulated
;
3441 Element
.extend
.refresh();
3446 Object
.extend(GLOBAL
.Element
, {
3448 addMethods
: addMethods
3451 if (extend
=== Prototype
.K
) {
3452 GLOBAL
.Element
.extend
.refresh
= Prototype
.emptyFunction
;
3454 GLOBAL
.Element
.extend
.refresh = function() {
3455 if (Prototype
.BrowserFeatures
.ElementExtensions
) return;
3456 Object
.extend(Methods
, Element
.Methods
);
3457 Object
.extend(Methods
, Element
.Methods
.Simulated
);
3463 function addFormMethods() {
3464 Object
.extend(Form
, Form
.Methods
);
3465 Object
.extend(Form
.Element
, Form
.Element
.Methods
);
3466 Object
.extend(Element
.Methods
.ByTag
, {
3467 "FORM": Object
.clone(Form
.Methods
),
3468 "INPUT": Object
.clone(Form
.Element
.Methods
),
3469 "SELECT": Object
.clone(Form
.Element
.Methods
),
3470 "TEXTAREA": Object
.clone(Form
.Element
.Methods
),
3471 "BUTTON": Object
.clone(Form
.Element
.Methods
)
3475 Element
.addMethods(methods
);
3477 function destroyCache_IE() {
3479 ELEMENT_CACHE
= null;
3482 if (window
.attachEvent
)
3483 window
.attachEvent('onunload', destroyCache_IE
);
3488 function toDecimal(pctString
) {
3489 var match
= pctString
.match(/^(\d+)%?$/i);
3490 if (!match
) return null;
3491 return (Number(match
[1]) / 100);
3494 function getRawStyle(element
, style
) {
3495 element
= $(element
);
3497 var value
= element
.style
[style
];
3498 if (!value
|| value
=== 'auto') {
3499 var css
= document
.defaultView
.getComputedStyle(element
, null);
3500 value
= css
? css
[style
] : null;
3503 if (style
=== 'opacity') return value
? parseFloat(value
) : 1.0;
3504 return value
=== 'auto' ? null : value
;
3507 function getRawStyle_IE(element
, style
) {
3508 var value
= element
.style
[style
];
3509 if (!value
&& element
.currentStyle
) {
3510 value
= element
.currentStyle
[style
];
3515 function getContentWidth(element
, context
) {
3516 var boxWidth
= element
.offsetWidth
;
3518 var bl
= getPixelValue(element
, 'borderLeftWidth', context
) || 0;
3519 var br
= getPixelValue(element
, 'borderRightWidth', context
) || 0;
3520 var pl
= getPixelValue(element
, 'paddingLeft', context
) || 0;
3521 var pr
= getPixelValue(element
, 'paddingRight', context
) || 0;
3523 return boxWidth
- bl
- br
- pl
- pr
;
3526 if (!Object
.isUndefined(document
.documentElement
.currentStyle
) && !Prototype
.Browser
.Opera
) {
3527 getRawStyle
= getRawStyle_IE
;
3531 function getPixelValue(value
, property
, context
) {
3533 if (Object
.isElement(value
)) {
3535 value
= getRawStyle(element
, property
);
3538 if (value
=== null || Object
.isUndefined(value
)) {
3542 if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value
)) {
3543 return window
.parseFloat(value
);
3546 var isPercentage
= value
.include('%'), isViewport
= (context
=== document
.viewport
);
3548 if (/\d/.test(value
) && element
&& element
.runtimeStyle
&& !(isPercentage
&& isViewport
)) {
3549 var style
= element
.style
.left
, rStyle
= element
.runtimeStyle
.left
;
3550 element
.runtimeStyle
.left
= element
.currentStyle
.left
;
3551 element
.style
.left
= value
|| 0;
3552 value
= element
.style
.pixelLeft
;
3553 element
.style
.left
= style
;
3554 element
.runtimeStyle
.left
= rStyle
;
3559 if (element
&& isPercentage
) {
3560 context
= context
|| element
.parentNode
;
3561 var decimal = toDecimal(value
), whole
= null;
3563 var isHorizontal
= property
.include('left') || property
.include('right') ||
3564 property
.include('width');
3566 var isVertical
= property
.include('top') || property
.include('bottom') ||
3567 property
.include('height');
3569 if (context
=== document
.viewport
) {
3571 whole
= document
.viewport
.getWidth();
3572 } else if (isVertical
) {
3573 whole
= document
.viewport
.getHeight();
3577 whole
= $(context
).measure('width');
3578 } else if (isVertical
) {
3579 whole
= $(context
).measure('height');
3583 return (whole
=== null) ? 0 : whole
* decimal;
3589 function toCSSPixels(number
) {
3590 if (Object
.isString(number
) && number
.endsWith('px'))
3592 return number
+ 'px';
3595 function isDisplayed(element
) {
3596 while (element
&& element
.parentNode
) {
3597 var display
= element
.getStyle('display');
3598 if (display
=== 'none') {
3601 element
= $(element
.parentNode
);
3606 var hasLayout
= Prototype
.K
;
3607 if ('currentStyle' in document
.documentElement
) {
3608 hasLayout = function(element
) {
3609 if (!element
.currentStyle
.hasLayout
) {
3610 element
.style
.zoom
= 1;
3616 function cssNameFor(key
) {
3617 if (key
.include('border')) key
= key
+ '-width';
3618 return key
.camelize();
3621 Element
.Layout
= Class
.create(Hash
, {
3622 initialize: function($super, element
, preCompute
) {
3624 this.element
= $(element
);
3626 Element
.Layout
.PROPERTIES
.each( function(property
) {
3627 this._set(property
, null);
3631 this._preComputing
= true;
3633 Element
.Layout
.PROPERTIES
.each( this._compute
, this );
3635 this._preComputing
= false;
3639 _set: function(property
, value
) {
3640 return Hash
.prototype.set.call(this, property
, value
);
3643 set: function(property
, value
) {
3644 throw "Properties of Element.Layout are read-only.";
3647 get: function($super, property
) {
3648 var value
= $super(property
);
3649 return value
=== null ? this._compute(property
) : value
;
3652 _begin: function() {
3653 if (this._isPrepared()) return;
3655 var element
= this.element
;
3656 if (isDisplayed(element
)) {
3657 this._setPrepared(true);
3662 var originalStyles
= {
3663 position
: element
.style
.position
|| '',
3664 width
: element
.style
.width
|| '',
3665 visibility
: element
.style
.visibility
|| '',
3666 display
: element
.style
.display
|| ''
3669 element
.store('prototype_original_styles', originalStyles
);
3671 var position
= getRawStyle(element
, 'position'), width
= element
.offsetWidth
;
3673 if (width
=== 0 || width
=== null) {
3674 element
.style
.display
= 'block';
3675 width
= element
.offsetWidth
;
3678 var context
= (position
=== 'fixed') ? document
.viewport
:
3682 visibility
: 'hidden',
3686 if (position
!== 'fixed') tempStyles
.position
= 'absolute';
3688 element
.setStyle(tempStyles
);
3690 var positionedWidth
= element
.offsetWidth
, newWidth
;
3691 if (width
&& (positionedWidth
=== width
)) {
3692 newWidth
= getContentWidth(element
, context
);
3693 } else if (position
=== 'absolute' || position
=== 'fixed') {
3694 newWidth
= getContentWidth(element
, context
);
3696 var parent
= element
.parentNode
, pLayout
= $(parent
).getLayout();
3698 newWidth
= pLayout
.get('width') -
3699 this.get('margin-left') -
3700 this.get('border-left') -
3701 this.get('padding-left') -
3702 this.get('padding-right') -
3703 this.get('border-right') -
3704 this.get('margin-right');
3707 element
.setStyle({ width
: newWidth
+ 'px' });
3709 this._setPrepared(true);
3713 var element
= this.element
;
3714 var originalStyles
= element
.retrieve('prototype_original_styles');
3715 element
.store('prototype_original_styles', null);
3716 element
.setStyle(originalStyles
);
3717 this._setPrepared(false);
3720 _compute: function(property
) {
3721 var COMPUTATIONS
= Element
.Layout
.COMPUTATIONS
;
3722 if (!(property
in COMPUTATIONS
)) {
3723 throw "Property not found.";
3726 return this._set(property
, COMPUTATIONS
[property
].call(this, this.element
));
3729 _isPrepared: function() {
3730 return this.element
.retrieve('prototype_element_layout_prepared', false);
3733 _setPrepared: function(bool
) {
3734 return this.element
.store('prototype_element_layout_prepared', bool
);
3737 toObject: function() {
3738 var args
= $A(arguments
);
3739 var keys
= (args
.length
=== 0) ? Element
.Layout
.PROPERTIES
:
3740 args
.join(' ').split(' ');
3742 keys
.each( function(key
) {
3743 if (!Element
.Layout
.PROPERTIES
.include(key
)) return;
3744 var value
= this.get(key
);
3745 if (value
!= null) obj
[key
] = value
;
3750 toHash: function() {
3751 var obj
= this.toObject
.apply(this, arguments
);
3752 return new Hash(obj
);
3756 var args
= $A(arguments
);
3757 var keys
= (args
.length
=== 0) ? Element
.Layout
.PROPERTIES
:
3758 args
.join(' ').split(' ');
3761 keys
.each( function(key
) {
3762 if (!Element
.Layout
.PROPERTIES
.include(key
)) return;
3763 if (Element
.Layout
.COMPOSITE_PROPERTIES
.include(key
)) return;
3765 var value
= this.get(key
);
3766 if (value
!= null) css
[cssNameFor(key
)] = value
+ 'px';
3771 inspect: function() {
3772 return "#<Element.Layout>";
3776 Object
.extend(Element
.Layout
, {
3777 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'),
3779 COMPOSITE_PROPERTIES
: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3782 'height': function(element
) {
3783 if (!this._preComputing
) this._begin();
3785 var bHeight
= this.get('border-box-height');
3787 if (!this._preComputing
) this._end();
3791 var bTop
= this.get('border-top'),
3792 bBottom
= this.get('border-bottom');
3794 var pTop
= this.get('padding-top'),
3795 pBottom
= this.get('padding-bottom');
3797 if (!this._preComputing
) this._end();
3799 return bHeight
- bTop
- bBottom
- pTop
- pBottom
;
3802 'width': function(element
) {
3803 if (!this._preComputing
) this._begin();
3805 var bWidth
= this.get('border-box-width');
3807 if (!this._preComputing
) this._end();
3811 var bLeft
= this.get('border-left'),
3812 bRight
= this.get('border-right');
3814 var pLeft
= this.get('padding-left'),
3815 pRight
= this.get('padding-right');
3817 if (!this._preComputing
) this._end();
3818 return bWidth
- bLeft
- bRight
- pLeft
- pRight
;
3821 'padding-box-height': function(element
) {
3822 var height
= this.get('height'),
3823 pTop
= this.get('padding-top'),
3824 pBottom
= this.get('padding-bottom');
3826 return height
+ pTop
+ pBottom
;
3829 'padding-box-width': function(element
) {
3830 var width
= this.get('width'),
3831 pLeft
= this.get('padding-left'),
3832 pRight
= this.get('padding-right');
3834 return width
+ pLeft
+ pRight
;
3837 'border-box-height': function(element
) {
3838 if (!this._preComputing
) this._begin();
3839 var height
= element
.offsetHeight
;
3840 if (!this._preComputing
) this._end();
3844 'border-box-width': function(element
) {
3845 if (!this._preComputing
) this._begin();
3846 var width
= element
.offsetWidth
;
3847 if (!this._preComputing
) this._end();
3851 'margin-box-height': function(element
) {
3852 var bHeight
= this.get('border-box-height'),
3853 mTop
= this.get('margin-top'),
3854 mBottom
= this.get('margin-bottom');
3856 if (bHeight
<= 0) return 0;
3858 return bHeight
+ mTop
+ mBottom
;
3861 'margin-box-width': function(element
) {
3862 var bWidth
= this.get('border-box-width'),
3863 mLeft
= this.get('margin-left'),
3864 mRight
= this.get('margin-right');
3866 if (bWidth
<= 0) return 0;
3868 return bWidth
+ mLeft
+ mRight
;
3871 'top': function(element
) {
3872 var offset
= element
.positionedOffset();
3876 'bottom': function(element
) {
3877 var offset
= element
.positionedOffset(),
3878 parent
= element
.getOffsetParent(),
3879 pHeight
= parent
.measure('height');
3881 var mHeight
= this.get('border-box-height');
3883 return pHeight
- mHeight
- offset
.top
;
3886 'left': function(element
) {
3887 var offset
= element
.positionedOffset();
3891 'right': function(element
) {
3892 var offset
= element
.positionedOffset(),
3893 parent
= element
.getOffsetParent(),
3894 pWidth
= parent
.measure('width');
3896 var mWidth
= this.get('border-box-width');
3898 return pWidth
- mWidth
- offset
.left
;
3901 'padding-top': function(element
) {
3902 return getPixelValue(element
, 'paddingTop');
3905 'padding-bottom': function(element
) {
3906 return getPixelValue(element
, 'paddingBottom');
3909 'padding-left': function(element
) {
3910 return getPixelValue(element
, 'paddingLeft');
3913 'padding-right': function(element
) {
3914 return getPixelValue(element
, 'paddingRight');
3917 'border-top': function(element
) {
3918 return getPixelValue(element
, 'borderTopWidth');
3921 'border-bottom': function(element
) {
3922 return getPixelValue(element
, 'borderBottomWidth');
3925 'border-left': function(element
) {
3926 return getPixelValue(element
, 'borderLeftWidth');
3929 'border-right': function(element
) {
3930 return getPixelValue(element
, 'borderRightWidth');
3933 'margin-top': function(element
) {
3934 return getPixelValue(element
, 'marginTop');
3937 'margin-bottom': function(element
) {
3938 return getPixelValue(element
, 'marginBottom');
3941 'margin-left': function(element
) {
3942 return getPixelValue(element
, 'marginLeft');
3945 'margin-right': function(element
) {
3946 return getPixelValue(element
, 'marginRight');
3951 if ('getBoundingClientRect' in document
.documentElement
) {
3952 Object
.extend(Element
.Layout
.COMPUTATIONS
, {
3953 'right': function(element
) {
3954 var parent
= hasLayout(element
.getOffsetParent());
3955 var rect
= element
.getBoundingClientRect(),
3956 pRect
= parent
.getBoundingClientRect();
3958 return (pRect
.right
- rect
.right
).round();
3961 'bottom': function(element
) {
3962 var parent
= hasLayout(element
.getOffsetParent());
3963 var rect
= element
.getBoundingClientRect(),
3964 pRect
= parent
.getBoundingClientRect();
3966 return (pRect
.bottom
- rect
.bottom
).round();
3971 Element
.Offset
= Class
.create({
3972 initialize: function(left
, top
) {
3973 this.left
= left
.round();
3974 this.top
= top
.round();
3976 this[0] = this.left
;
3980 relativeTo: function(offset
) {
3981 return new Element
.Offset(
3982 this.left
- offset
.left
,
3983 this.top
- offset
.top
3987 inspect: function() {
3988 return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3991 toString: function() {
3992 return "[#{left}, #{top}]".interpolate(this);
3995 toArray: function() {
3996 return [this.left
, this.top
];
4000 function getLayout(element
, preCompute
) {
4001 return new Element
.Layout(element
, preCompute
);
4004 function measure(element
, property
) {
4005 return $(element
).getLayout().get(property
);
4008 function getHeight(element
) {
4009 return Element
.getDimensions(element
).height
;
4012 function getWidth(element
) {
4013 return Element
.getDimensions(element
).width
;
4016 function getDimensions(element
) {
4017 element
= $(element
);
4018 var display
= Element
.getStyle(element
, 'display');
4020 if (display
&& display
!== 'none') {
4021 return { width
: element
.offsetWidth
, height
: element
.offsetHeight
};
4024 var style
= element
.style
;
4025 var originalStyles
= {
4026 visibility
: style
.visibility
,
4027 position
: style
.position
,
4028 display
: style
.display
4032 visibility
: 'hidden',
4036 if (originalStyles
.position
!== 'fixed')
4037 newStyles
.position
= 'absolute';
4039 Element
.setStyle(element
, newStyles
);
4042 width
: element
.offsetWidth
,
4043 height
: element
.offsetHeight
4046 Element
.setStyle(element
, originalStyles
);
4051 function getOffsetParent(element
) {
4052 element
= $(element
);
4054 function selfOrBody(element
) {
4055 return isHtml(element
) ? $(document
.body
) : $(element
);
4058 if (isDocument(element
) || isDetached(element
) || isBody(element
) || isHtml(element
))
4059 return $(document
.body
);
4061 var isInline
= (Element
.getStyle(element
, 'display') === 'inline');
4062 if (!isInline
&& element
.offsetParent
) return selfOrBody(element
.offsetParent
);
4064 while ((element
= element
.parentNode
) && element
!== document
.body
) {
4065 if (Element
.getStyle(element
, 'position') !== 'static') {
4066 return selfOrBody(element
);
4070 return $(document
.body
);
4074 function cumulativeOffset(element
) {
4075 element
= $(element
);
4076 var valueT
= 0, valueL
= 0;
4077 if (element
.parentNode
) {
4079 valueT
+= element
.offsetTop
|| 0;
4080 valueL
+= element
.offsetLeft
|| 0;
4081 element
= element
.offsetParent
;
4084 return new Element
.Offset(valueL
, valueT
);
4087 function positionedOffset(element
) {
4088 element
= $(element
);
4090 var layout
= element
.getLayout();
4092 var valueT
= 0, valueL
= 0;
4094 valueT
+= element
.offsetTop
|| 0;
4095 valueL
+= element
.offsetLeft
|| 0;
4096 element
= element
.offsetParent
;
4098 if (isBody(element
)) break;
4099 var p
= Element
.getStyle(element
, 'position');
4100 if (p
!== 'static') break;
4104 valueL
-= layout
.get('margin-left');
4105 valueT
-= layout
.get('margin-top');
4107 return new Element
.Offset(valueL
, valueT
);
4110 function cumulativeScrollOffset(element
) {
4111 var valueT
= 0, valueL
= 0;
4113 if (element
=== document
.body
) {
4114 var bodyScrollNode
= document
.documentElement
|| document
.body
.parentNode
|| document
.body
;
4115 valueT
+= !Object
.isUndefined(window
.pageYOffset
) ? window
.pageYOffset
: bodyScrollNode
.scrollTop
|| 0;
4116 valueL
+= !Object
.isUndefined(window
.pageXOffset
) ? window
.pageXOffset
: bodyScrollNode
.scrollLeft
|| 0;
4119 valueT
+= element
.scrollTop
|| 0;
4120 valueL
+= element
.scrollLeft
|| 0;
4121 element
= element
.parentNode
;
4124 return new Element
.Offset(valueL
, valueT
);
4127 function viewportOffset(forElement
) {
4128 var valueT
= 0, valueL
= 0, docBody
= document
.body
;
4130 forElement
= $(forElement
);
4131 var element
= forElement
;
4133 valueT
+= element
.offsetTop
|| 0;
4134 valueL
+= element
.offsetLeft
|| 0;
4135 if (element
.offsetParent
== docBody
&&
4136 Element
.getStyle(element
, 'position') == 'absolute') break;
4137 } while (element
= element
.offsetParent
);
4139 element
= forElement
;
4141 if (element
!= docBody
) {
4142 valueT
-= element
.scrollTop
|| 0;
4143 valueL
-= element
.scrollLeft
|| 0;
4145 } while (element
= element
.parentNode
);
4146 return new Element
.Offset(valueL
, valueT
);
4149 function absolutize(element
) {
4150 element
= $(element
);
4152 if (Element
.getStyle(element
, 'position') === 'absolute') {
4156 var offsetParent
= getOffsetParent(element
);
4157 var eOffset
= element
.viewportOffset(),
4158 pOffset
= offsetParent
.viewportOffset();
4160 var offset
= eOffset
.relativeTo(pOffset
);
4161 var layout
= element
.getLayout();
4163 element
.store('prototype_absolutize_original_styles', {
4164 position
: element
.getStyle('position'),
4165 left
: element
.getStyle('left'),
4166 top
: element
.getStyle('top'),
4167 width
: element
.getStyle('width'),
4168 height
: element
.getStyle('height')
4172 position
: 'absolute',
4173 top
: offset
.top
+ 'px',
4174 left
: offset
.left
+ 'px',
4175 width
: layout
.get('width') + 'px',
4176 height
: layout
.get('height') + 'px'
4182 function relativize(element
) {
4183 element
= $(element
);
4184 if (Element
.getStyle(element
, 'position') === 'relative') {
4188 var originalStyles
=
4189 element
.retrieve('prototype_absolutize_original_styles');
4191 if (originalStyles
) element
.setStyle(originalStyles
);
4196 function scrollTo(element
) {
4197 element
= $(element
);
4198 var pos
= Element
.cumulativeOffset(element
);
4199 window
.scrollTo(pos
.left
, pos
.top
);
4204 function makePositioned(element
) {
4205 element
= $(element
);
4206 var position
= Element
.getStyle(element
, 'position'), styles
= {};
4207 if (position
=== 'static' || !position
) {
4208 styles
.position
= 'relative';
4209 if (Prototype
.Browser
.Opera
) {
4213 Element
.setStyle(element
, styles
);
4214 Element
.store(element
, 'prototype_made_positioned', true);
4219 function undoPositioned(element
) {
4220 element
= $(element
);
4221 var storage
= Element
.getStorage(element
),
4222 madePositioned
= storage
.get('prototype_made_positioned');
4224 if (madePositioned
) {
4225 storage
.unset('prototype_made_positioned');
4226 Element
.setStyle(element
, {
4237 function makeClipping(element
) {
4238 element
= $(element
);
4240 var storage
= Element
.getStorage(element
),
4241 madeClipping
= storage
.get('prototype_made_clipping');
4243 if (Object
.isUndefined(madeClipping
)) {
4244 var overflow
= Element
.getStyle(element
, 'overflow');
4245 storage
.set('prototype_made_clipping', overflow
);
4246 if (overflow
!== 'hidden')
4247 element
.style
.overflow
= 'hidden';
4253 function undoClipping(element
) {
4254 element
= $(element
);
4255 var storage
= Element
.getStorage(element
),
4256 overflow
= storage
.get('prototype_made_clipping');
4258 if (!Object
.isUndefined(overflow
)) {
4259 storage
.unset('prototype_made_clipping');
4260 element
.style
.overflow
= overflow
|| '';
4266 function clonePosition(element
, source
, options
) {
4267 options
= Object
.extend({
4276 var docEl
= document
.documentElement
;
4279 element
= $(element
);
4280 var p
, delta
, layout
, styles
= {};
4282 if (options
.setLeft
|| options
.setTop
) {
4283 p
= Element
.viewportOffset(source
);
4285 if (Element
.getStyle(element
, 'position') === 'absolute') {
4286 var parent
= Element
.getOffsetParent(element
);
4287 if (parent
!== document
.body
) delta
= Element
.viewportOffset(parent
);
4291 function pageScrollXY() {
4293 if (Object
.isNumber(window
.pageXOffset
)) {
4294 x
= window
.pageXOffset
;
4295 y
= window
.pageYOffset
;
4296 } else if (document
.body
&& (document
.body
.scrollLeft
|| document
.body
.scrollTop
)) {
4297 x
= document
.body
.scrollLeft
;
4298 y
= document
.body
.scrollTop
;
4299 } else if (docEl
&& (docEl
.scrollLeft
|| docEl
.scrollTop
)) {
4300 x
= docEl
.scrollLeft
;
4301 y
= docEl
.scrollTop
;
4303 return { x
: x
, y
: y
};
4306 var pageXY
= pageScrollXY();
4309 if (options
.setWidth
|| options
.setHeight
) {
4310 layout
= Element
.getLayout(source
);
4313 if (options
.setLeft
)
4314 styles
.left
= (p
[0] + pageXY
.x
- delta
[0] + options
.offsetLeft
) + 'px';
4316 styles
.top
= (p
[1] + pageXY
.y
- delta
[1] + options
.offsetTop
) + 'px';
4318 var currentLayout
= element
.getLayout();
4320 if (options
.setWidth
) {
4321 styles
.width
= layout
.get('width') + 'px';
4323 if (options
.setHeight
) {
4324 styles
.height
= layout
.get('height') + 'px';
4327 return Element
.setStyle(element
, styles
);
4331 if (Prototype
.Browser
.IE
) {
4332 getOffsetParent
= getOffsetParent
.wrap(
4333 function(proceed
, element
) {
4334 element
= $(element
);
4336 if (isDocument(element
) || isDetached(element
) || isBody(element
) || isHtml(element
))
4337 return $(document
.body
);
4339 var position
= element
.getStyle('position');
4340 if (position
!== 'static') return proceed(element
);
4342 element
.setStyle({ position
: 'relative' });
4343 var value
= proceed(element
);
4344 element
.setStyle({ position
: position
});
4349 positionedOffset
= positionedOffset
.wrap(function(proceed
, element
) {
4350 element
= $(element
);
4351 if (!element
.parentNode
) return new Element
.Offset(0, 0);
4352 var position
= element
.getStyle('position');
4353 if (position
!== 'static') return proceed(element
);
4355 var offsetParent
= element
.getOffsetParent();
4356 if (offsetParent
&& offsetParent
.getStyle('position') === 'fixed')
4357 hasLayout(offsetParent
);
4359 element
.setStyle({ position
: 'relative' });
4360 var value
= proceed(element
);
4361 element
.setStyle({ position
: position
});
4364 } else if (Prototype
.Browser
.Webkit
) {
4365 cumulativeOffset = function(element
) {
4366 element
= $(element
);
4367 var valueT
= 0, valueL
= 0;
4369 valueT
+= element
.offsetTop
|| 0;
4370 valueL
+= element
.offsetLeft
|| 0;
4371 if (element
.offsetParent
== document
.body
) {
4372 if (Element
.getStyle(element
, 'position') == 'absolute') break;
4375 element
= element
.offsetParent
;
4378 return new Element
.Offset(valueL
, valueT
);
4383 Element
.addMethods({
4384 getLayout
: getLayout
,
4387 getHeight
: getHeight
,
4388 getDimensions
: getDimensions
,
4389 getOffsetParent
: getOffsetParent
,
4390 cumulativeOffset
: cumulativeOffset
,
4391 positionedOffset
: positionedOffset
,
4392 cumulativeScrollOffset
: cumulativeScrollOffset
,
4393 viewportOffset
: viewportOffset
,
4394 absolutize
: absolutize
,
4395 relativize
: relativize
,
4397 makePositioned
: makePositioned
,
4398 undoPositioned
: undoPositioned
,
4399 makeClipping
: makeClipping
,
4400 undoClipping
: undoClipping
,
4401 clonePosition
: clonePosition
4404 function isBody(element
) {
4405 return element
.nodeName
.toUpperCase() === 'BODY';
4408 function isHtml(element
) {
4409 return element
.nodeName
.toUpperCase() === 'HTML';
4412 function isDocument(element
) {
4413 return element
.nodeType
=== Node
.DOCUMENT_NODE
;
4416 function isDetached(element
) {
4417 return element
!== document
.body
&&
4418 !Element
.descendantOf(element
, document
.body
);
4421 if ('getBoundingClientRect' in document
.documentElement
) {
4422 Element
.addMethods({
4423 viewportOffset: function(element
) {
4424 element
= $(element
);
4425 if (isDetached(element
)) return new Element
.Offset(0, 0);
4427 var rect
= element
.getBoundingClientRect(),
4428 docEl
= document
.documentElement
;
4429 return new Element
.Offset(rect
.left
- docEl
.clientLeft
,
4430 rect
.top
- docEl
.clientTop
);
4440 var IS_OLD_OPERA
= Prototype
.Browser
.Opera
&&
4441 (window
.parseFloat(window
.opera
.version()) < 9.5);
4443 function getRootElement() {
4444 if (ROOT
) return ROOT
;
4445 ROOT
= IS_OLD_OPERA
? document
.body
: document
.documentElement
;
4449 function getDimensions() {
4450 return { width
: this.getWidth(), height
: this.getHeight() };
4453 function getWidth() {
4454 return getRootElement().clientWidth
;
4457 function getHeight() {
4458 return getRootElement().clientHeight
;
4461 function getScrollOffsets() {
4462 var x
= window
.pageXOffset
|| document
.documentElement
.scrollLeft
||
4463 document
.body
.scrollLeft
;
4464 var y
= window
.pageYOffset
|| document
.documentElement
.scrollTop
||
4465 document
.body
.scrollTop
;
4467 return new Element
.Offset(x
, y
);
4470 document
.viewport
= {
4471 getDimensions
: getDimensions
,
4473 getHeight
: getHeight
,
4474 getScrollOffsets
: getScrollOffsets
4478 window
.$$ = function() {
4479 var expression
= $A(arguments
).join(', ');
4480 return Prototype
.Selector
.select(expression
, document
);
4483 Prototype
.Selector
= (function() {
4486 throw new Error('Method "Prototype.Selector.select" must be defined.');
4490 throw new Error('Method "Prototype.Selector.match" must be defined.');
4493 function find(elements
, expression
, index
) {
4495 var match
= Prototype
.Selector
.match
, length
= elements
.length
, matchIndex
= 0, i
;
4497 for (i
= 0; i
< length
; i
++) {
4498 if (match(elements
[i
], expression
) && index
== matchIndex
++) {
4499 return Element
.extend(elements
[i
]);
4504 function extendElements(elements
) {
4505 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
4506 Element
.extend(elements
[i
]);
4512 var K
= Prototype
.K
;
4518 extendElements
: (Element
.extend
=== K
) ? K
: extendElements
,
4519 extendElement
: Element
.extend
4522 Prototype
._original_property
= window
.Sizzle
;
4525 function fakeDefine(fn
) {
4526 Prototype
._actual_sizzle
= fn();
4528 fakeDefine
.amd
= true;
4530 if (typeof define
!== 'undefined' && define
.amd
) {
4531 Prototype
._original_define
= define
;
4532 Prototype
._actual_sizzle
= null;
4533 window
.define
= fakeDefine
;
4538 * Sizzle CSS Selector Engine v1.10.18
4539 * http://sizzlejs.com/
4541 * Copyright 2013 jQuery Foundation, Inc. and other contributors
4542 * Released under the MIT license
4543 * http://jquery.org/license
4547 (function( window
) {
4569 expando
= "sizzle" + -(new Date()),
4570 preferredDoc
= window
.document
,
4573 classCache
= createCache(),
4574 tokenCache
= createCache(),
4575 compilerCache
= createCache(),
4576 sortOrder = function( a
, b
) {
4578 hasDuplicate
= true;
4583 strundefined
= typeof undefined,
4584 MAX_NEGATIVE
= 1 << 31,
4586 hasOwn
= ({}).hasOwnProperty
,
4589 push_native
= arr
.push
,
4592 indexOf
= arr
.indexOf
|| function( elem
) {
4595 for ( ; i
< len
; i
++ ) {
4596 if ( this[i
] === elem
) {
4603 booleans
= "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
4606 whitespace
= "[\\x20\\t\\r\\n\\f]",
4607 characterEncoding
= "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
4609 identifier
= characterEncoding
.replace( "w", "w#" ),
4611 attributes
= "\\[" + whitespace
+ "*(" + characterEncoding
+ ")" + whitespace
+
4612 "*(?:([*^$|!~]?=)" + whitespace
+ "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier
+ ")|)|)" + whitespace
+ "*\\]",
4614 pseudos
= ":(" + characterEncoding
+ ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes
.replace( 3, 8 ) + ")*)|.*)\\)|)",
4616 rtrim
= new RegExp( "^" + whitespace
+ "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace
+ "+$", "g" ),
4618 rcomma
= new RegExp( "^" + whitespace
+ "*," + whitespace
+ "*" ),
4619 rcombinators
= new RegExp( "^" + whitespace
+ "*([>+~]|" + whitespace
+ ")" + whitespace
+ "*" ),
4621 rattributeQuotes
= new RegExp( "=" + whitespace
+ "*([^\\]'\"]*?)" + whitespace
+ "*\\]", "g" ),
4623 rpseudo
= new RegExp( pseudos
),
4624 ridentifier
= new RegExp( "^" + identifier
+ "$" ),
4627 "ID": new RegExp( "^#(" + characterEncoding
+ ")" ),
4628 "CLASS": new RegExp( "^\\.(" + characterEncoding
+ ")" ),
4629 "TAG": new RegExp( "^(" + characterEncoding
.replace( "w", "w*" ) + ")" ),
4630 "ATTR": new RegExp( "^" + attributes
),
4631 "PSEUDO": new RegExp( "^" + pseudos
),
4632 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace
+
4633 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace
+ "*(?:([+-]|)" + whitespace
+
4634 "*(\\d+)|))" + whitespace
+ "*\\)|)", "i" ),
4635 "bool": new RegExp( "^(?:" + booleans
+ ")$", "i" ),
4636 "needsContext": new RegExp( "^" + whitespace
+ "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
4637 whitespace
+ "*((?:-\\d)?\\d*)" + whitespace
+ "*\\)|)(?=[^-]|$)", "i" )
4640 rinputs
= /^(?:input|select|textarea|button)$/i,
4643 rnative
= /^[^{]+\{\s*\[native \w/,
4645 rquickExpr
= /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
4650 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
4651 funescape = function( _, escaped, escapedWhitespace ) {
4652 var high = "0x" + escaped - 0x10000;
4653 return high !== high || escapedWhitespace ?
4656 String.fromCharCode( high + 0x10000 ) :
4657 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
4662 (arr = slice.call( preferredDoc.childNodes )),
4663 preferredDoc.childNodes
4665 arr[ preferredDoc.childNodes.length ].nodeType;
4667 push = { apply: arr.length ?
4669 function( target, els ) {
4670 push_native.apply( target, slice.call(els) );
4673 function( target, els ) {
4674 var j = target.length,
4676 while ( (target[j++] = els[i++]) ) {}
4677 target.length = j - 1;
4682 function Sizzle( selector, context, results, seed ) {
4683 var match, elem, m, nodeType,
4684 i, groups, old, nid, newContext, newSelector;
4686 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
4687 setDocument( context );
4690 context = context || document;
4691 results = results || [];
4693 if ( !selector || typeof selector !== "string" ) {
4697 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
4701 if ( documentIsHTML && !seed ) {
4703 if ( (match = rquickExpr.exec( selector )) ) {
4704 if ( (m = match[1]) ) {
4705 if ( nodeType === 9 ) {
4706 elem = context.getElementById( m );
4707 if ( elem && elem.parentNode ) {
4708 if ( elem.id === m ) {
4709 results.push( elem );
4716 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
4717 contains( context, elem ) && elem.id === m ) {
4718 results.push( elem );
4723 } else if ( match[2] ) {
4724 push.apply( results, context.getElementsByTagName( selector ) );
4727 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
4728 push.apply( results, context.getElementsByClassName( m ) );
4733 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
4734 nid = old = expando;
4735 newContext = context;
4736 newSelector = nodeType === 9 && selector;
4738 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
4739 groups = tokenize( selector );
4741 if ( (old = context.getAttribute("id")) ) {
4742 nid = old.replace( rescape, "\\$&" );
4744 context.setAttribute( "id", nid );
4746 nid = "[id='" + nid + "'] ";
4750 groups[i] = nid + toSelector( groups[i] );
4752 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
4753 newSelector = groups.join(",");
4756 if ( newSelector ) {
4758 push.apply( results,
4759 newContext.querySelectorAll( newSelector )
4765 context.removeAttribute("id");
4772 return select( selector.replace( rtrim, "$1" ), context, results, seed );
4776 * Create key-value caches of limited size
4777 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
4778 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
4779 * deleting the oldest entry
4781 function createCache() {
4784 function cache( key, value ) {
4785 if ( keys.push( key + " " ) > Expr.cacheLength ) {
4786 delete cache[ keys.shift() ];
4788 return (cache[ key + " " ] = value);
4794 * Mark a function for special use by Sizzle
4795 * @param {Function} fn The function to mark
4797 function markFunction( fn ) {
4798 fn[ expando ] = true;
4803 * Support testing using an element
4804 * @param {Function} fn Passed the created div and expects a boolean result
4806 function assert( fn ) {
4807 var div = document.createElement("div");
4814 if ( div.parentNode ) {
4815 div.parentNode.removeChild( div );
4822 * Adds the same handler for all of the specified attrs
4823 * @param {String} attrs Pipe-separated list of attributes
4824 * @param {Function} handler The method that will be applied
4826 function addHandle( attrs, handler ) {
4827 var arr = attrs.split("|"),
4831 Expr.attrHandle[ arr[i] ] = handler;
4836 * Checks document order of two siblings
4837 * @param {Element} a
4838 * @param {Element} b
4839 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
4841 function siblingCheck( a, b ) {
4843 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
4844 ( ~b.sourceIndex || MAX_NEGATIVE ) -
4845 ( ~a.sourceIndex || MAX_NEGATIVE );
4852 while ( (cur = cur.nextSibling) ) {
4863 * Returns a function to use in pseudos for input types
4864 * @param {String} type
4866 function createInputPseudo( type ) {
4867 return function( elem ) {
4868 var name = elem.nodeName.toLowerCase();
4869 return name === "input" && elem.type === type;
4874 * Returns a function to use in pseudos for buttons
4875 * @param {String} type
4877 function createButtonPseudo( type ) {
4878 return function( elem ) {
4879 var name = elem.nodeName.toLowerCase();
4880 return (name === "input" || name === "button") && elem.type === type;
4885 * Returns a function to use in pseudos for positionals
4886 * @param {Function} fn
4888 function createPositionalPseudo( fn ) {
4889 return markFunction(function( argument ) {
4890 argument = +argument;
4891 return markFunction(function( seed, matches ) {
4893 matchIndexes = fn( [], seed.length, argument ),
4894 i = matchIndexes.length;
4897 if ( seed[ (j = matchIndexes[i]) ] ) {
4898 seed[j] = !(matches[j] = seed[j]);
4906 * Checks a node for validity as a Sizzle context
4907 * @param {Element|Object=} context
4908 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
4910 function testContext( context ) {
4911 return context && typeof context.getElementsByTagName !== strundefined && context;
4914 support = Sizzle.support = {};
4918 * @param {Element|Object} elem An element or a document
4919 * @returns {Boolean} True iff elem is a non-HTML XML node
4921 isXML = Sizzle.isXML = function( elem ) {
4922 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4923 return documentElement ? documentElement.nodeName !== "HTML" : false;
4927 * Sets document-related variables once based on the current document
4928 * @param {Element|Object} [doc] An element or document object to use to set the document
4929 * @returns {Object} Returns the current document
4931 setDocument = Sizzle.setDocument = function( node ) {
4933 doc = node ? node.ownerDocument || node : preferredDoc,
4934 parent = doc.defaultView;
4936 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4941 docElem = doc.documentElement;
4943 documentIsHTML = !isXML( doc );
4945 if ( parent && parent !== parent.top ) {
4946 if ( parent.addEventListener ) {
4947 parent.addEventListener( "unload", function() {
4950 } else if ( parent.attachEvent ) {
4951 parent.attachEvent( "onunload", function() {
4958 ---------------------------------------------------------------------- */
4960 support.attributes = assert(function( div ) {
4961 div.className = "i";
4962 return !div.getAttribute("className");
4966 ---------------------------------------------------------------------- */
4968 support.getElementsByTagName = assert(function( div ) {
4969 div.appendChild( doc.createComment("") );
4970 return !div.getElementsByTagName("*").length;
4973 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
4974 div.innerHTML = "<div class='a
'></div><div class='a i
'></div>";
4976 div.firstChild.className = "i";
4977 return div.getElementsByClassName("i").length === 2;
4980 support.getById = assert(function( div ) {
4981 docElem.appendChild( div ).id = expando;
4982 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
4985 if ( support.getById ) {
4986 Expr.find["ID"] = function( id, context ) {
4987 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
4988 var m = context.getElementById( id );
4989 return m && m.parentNode ? [m] : [];
4992 Expr.filter["ID"] = function( id ) {
4993 var attrId = id.replace( runescape, funescape );
4994 return function( elem ) {
4995 return elem.getAttribute("id") === attrId;
4999 delete Expr.find["ID"];
5001 Expr.filter["ID"] = function( id ) {
5002 var attrId = id.replace( runescape, funescape );
5003 return function( elem ) {
5004 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
5005 return node && node.value === attrId;
5010 Expr.find["TAG"] = support.getElementsByTagName ?
5011 function( tag, context ) {
5012 if ( typeof context.getElementsByTagName !== strundefined ) {
5013 return context.getElementsByTagName( tag );
5016 function( tag, context ) {
5020 results = context.getElementsByTagName( tag );
5022 if ( tag === "*" ) {
5023 while ( (elem = results[i++]) ) {
5024 if ( elem.nodeType === 1 ) {
5034 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
5035 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
5036 return context.getElementsByClassName( className );
5040 /* QSA/matchesSelector
5041 ---------------------------------------------------------------------- */
5048 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
5049 assert(function( div ) {
5050 div.innerHTML = "<select t=''><option selected=''></option></select>";
5052 if ( div.querySelectorAll("[t^='']").length ) {
5053 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
5056 if ( !div.querySelectorAll("[selected]").length ) {
5057 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
5060 if ( !div.querySelectorAll(":checked").length ) {
5061 rbuggyQSA.push(":checked");
5065 assert(function( div ) {
5066 var input = doc.createElement("input");
5067 input.setAttribute( "type", "hidden" );
5068 div.appendChild( input ).setAttribute( "name", "D" );
5070 if ( div.querySelectorAll("[name=d]").length ) {
5071 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
5074 if ( !div.querySelectorAll(":enabled").length ) {
5075 rbuggyQSA.push( ":enabled", ":disabled" );
5078 div.querySelectorAll("*,:x");
5079 rbuggyQSA.push(",.*:");
5083 if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
5084 docElem.mozMatchesSelector ||
5085 docElem.oMatchesSelector ||
5086 docElem.msMatchesSelector) )) ) {
5088 assert(function( div ) {
5089 support.disconnectedMatch = matches.call( div, "div" );
5091 matches.call( div, "[s!='']:x" );
5092 rbuggyMatches.push( "!=", pseudos );
5096 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
5097 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
5100 ---------------------------------------------------------------------- */
5101 hasCompare = rnative.test( docElem.compareDocumentPosition );
5103 contains = hasCompare || rnative.test( docElem.contains ) ?
5105 var adown = a.nodeType === 9 ? a.documentElement : a,
5106 bup = b && b.parentNode;
5107 return a === bup || !!( bup && bup.nodeType === 1 && (
5109 adown.contains( bup ) :
5110 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
5115 while ( (b = b.parentNode) ) {
5125 ---------------------------------------------------------------------- */
5127 sortOrder = hasCompare ?
5131 hasDuplicate = true;
5135 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
5140 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
5141 a.compareDocumentPosition( b ) :
5146 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
5148 if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
5151 if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
5156 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5160 return compare & 4 ? -1 : 1;
5164 hasDuplicate = true;
5175 if ( !aup || !bup ) {
5176 return a === doc ? -1 :
5181 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5184 } else if ( aup === bup ) {
5185 return siblingCheck( a, b );
5189 while ( (cur = cur.parentNode) ) {
5193 while ( (cur = cur.parentNode) ) {
5197 while ( ap[i] === bp[i] ) {
5202 siblingCheck( ap[i], bp[i] ) :
5204 ap[i] === preferredDoc ? -1 :
5205 bp[i] === preferredDoc ? 1 :
5212 Sizzle.matches = function( expr, elements ) {
5213 return Sizzle( expr, null, null, elements );
5216 Sizzle.matchesSelector = function( elem, expr ) {
5217 if ( ( elem.ownerDocument || elem ) !== document ) {
5218 setDocument( elem );
5221 expr = expr.replace( rattributeQuotes, "='$1']" );
5223 if ( support.matchesSelector && documentIsHTML &&
5224 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
5225 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
5228 var ret = matches.call( elem, expr );
5230 if ( ret || support.disconnectedMatch ||
5231 elem.document && elem.document.nodeType !== 11 ) {
5237 return Sizzle( expr, document, null, [elem] ).length > 0;
5240 Sizzle.contains = function( context, elem ) {
5241 if ( ( context.ownerDocument || context ) !== document ) {
5242 setDocument( context );
5244 return contains( context, elem );
5247 Sizzle.attr = function( elem, name ) {
5248 if ( ( elem.ownerDocument || elem ) !== document ) {
5249 setDocument( elem );
5252 var fn = Expr.attrHandle[ name.toLowerCase() ],
5253 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
5254 fn( elem, name, !documentIsHTML ) :
5257 return val !== undefined ?
5259 support.attributes || !documentIsHTML ?
5260 elem.getAttribute( name ) :
5261 (val = elem.getAttributeNode(name)) && val.specified ?
5266 Sizzle.error = function( msg ) {
5267 throw new Error( "Syntax error, unrecognized expression: " + msg );
5271 * Document sorting and removing duplicates
5272 * @param {ArrayLike} results
5274 Sizzle.uniqueSort = function( results ) {
5280 hasDuplicate = !support.detectDuplicates;
5281 sortInput = !support.sortStable && results.slice( 0 );
5282 results.sort( sortOrder );
5284 if ( hasDuplicate ) {
5285 while ( (elem = results[i++]) ) {
5286 if ( elem === results[ i ] ) {
5287 j = duplicates.push( i );
5291 results.splice( duplicates[ j ], 1 );
5301 * Utility function for retrieving the text value of an array of DOM nodes
5302 * @param {Array|Element} elem
5304 getText = Sizzle.getText = function( elem ) {
5308 nodeType = elem.nodeType;
5311 while ( (node = elem[i++]) ) {
5312 ret += getText( node );
5314 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
5315 if ( typeof elem.textContent === "string" ) {
5316 return elem.textContent;
5318 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5319 ret += getText( elem );
5322 } else if ( nodeType === 3 || nodeType === 4 ) {
5323 return elem.nodeValue;
5329 Expr = Sizzle.selectors = {
5333 createPseudo: markFunction,
5342 ">": { dir: "parentNode", first: true },
5343 " ": { dir: "parentNode" },
5344 "+": { dir: "previousSibling", first: true },
5345 "~": { dir: "previousSibling" }
5349 "ATTR": function( match ) {
5350 match[1] = match[1].replace( runescape, funescape );
5352 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
5354 if ( match[2] === "~=" ) {
5355 match[3] = " " + match[3] + " ";
5358 return match.slice( 0, 4 );
5361 "CHILD": function( match ) {
5362 /* matches from matchExpr["CHILD"]
5363 1 type (only|nth|...)
5364 2 what (child|of-type)
5365 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
5366 4 xn-component of xn+y argument ([+-]?\d*n|)
5367 5 sign of xn-component
5369 7 sign of y-component
5372 match[1] = match[1].toLowerCase();
5374 if ( match[1].slice( 0, 3 ) === "nth" ) {
5376 Sizzle.error( match[0] );
5379 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
5380 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
5382 } else if ( match[3] ) {
5383 Sizzle.error( match[0] );
5389 "PSEUDO": function( match ) {
5391 unquoted = !match[5] && match[2];
5393 if ( matchExpr["CHILD"].test( match[0] ) ) {
5397 if ( match[3] && match[4] !== undefined ) {
5398 match[2] = match[4];
5400 } else if ( unquoted && rpseudo.test( unquoted ) &&
5401 (excess = tokenize( unquoted, true )) &&
5402 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
5404 match[0] = match[0].slice( 0, excess );
5405 match[2] = unquoted.slice( 0, excess );
5408 return match.slice( 0, 3 );
5414 "TAG": function( nodeNameSelector ) {
5415 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
5416 return nodeNameSelector === "*" ?
5417 function() { return true; } :
5419 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
5423 "CLASS": function( className ) {
5424 var pattern = classCache[ className + " " ];
5427 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
5428 classCache( className, function( elem ) {
5429 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
5433 "ATTR": function( name, operator, check ) {
5434 return function( elem ) {
5435 var result = Sizzle.attr( elem, name );
5437 if ( result == null ) {
5438 return operator === "!=";
5446 return operator === "=" ? result === check :
5447 operator === "!=" ? result !== check :
5448 operator === "^=" ? check && result.indexOf( check ) === 0 :
5449 operator === "*=" ? check && result.indexOf( check ) > -1 :
5450 operator === "$=" ? check && result.slice( -check.length ) === check :
5451 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
5452 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
5457 "CHILD": function( type, what, argument, first, last ) {
5458 var simple = type.slice( 0, 3 ) !== "nth",
5459 forward = type.slice( -4 ) !== "last",
5460 ofType = what === "of-type";
5462 return first === 1 && last === 0 ?
5465 return !!elem.parentNode;
5468 function( elem, context, xml ) {
5469 var cache, outerCache, node, diff, nodeIndex, start,
5470 dir = simple !== forward ? "nextSibling" : "previousSibling",
5471 parent = elem.parentNode,
5472 name = ofType && elem.nodeName.toLowerCase(),
5473 useCache = !xml && !ofType;
5480 while ( (node = node[ dir ]) ) {
5481 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
5485 start = dir = type === "only" && !start && "nextSibling";
5490 start = [ forward ? parent.firstChild : parent.lastChild ];
5492 if ( forward && useCache ) {
5493 outerCache = parent[ expando ] || (parent[ expando ] = {});
5494 cache = outerCache[ type ] || [];
5495 nodeIndex = cache[0] === dirruns && cache[1];
5496 diff = cache[0] === dirruns && cache[2];
5497 node = nodeIndex && parent.childNodes[ nodeIndex ];
5499 while ( (node = ++nodeIndex && node && node[ dir ] ||
5501 (diff = nodeIndex = 0) || start.pop()) ) {
5503 if ( node.nodeType === 1 && ++diff && node === elem ) {
5504 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
5509 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
5513 while ( (node = ++nodeIndex && node && node[ dir ] ||
5514 (diff = nodeIndex = 0) || start.pop()) ) {
5516 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
5518 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
5521 if ( node === elem ) {
5529 return diff === first || ( diff % first === 0 && diff / first >= 0 );
5534 "PSEUDO": function( pseudo, argument ) {
5536 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
5537 Sizzle.error( "unsupported pseudo: " + pseudo );
5539 if ( fn[ expando ] ) {
5540 return fn( argument );
5543 if ( fn.length > 1 ) {
5544 args = [ pseudo, pseudo, "", argument ];
5545 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
5546 markFunction(function( seed, matches ) {
5548 matched = fn( seed, argument ),
5551 idx = indexOf.call( seed, matched[i] );
5552 seed[ idx ] = !( matches[ idx ] = matched[i] );
5556 return fn( elem, 0, args );
5565 "not": markFunction(function( selector ) {
5568 matcher = compile( selector.replace( rtrim, "$1" ) );
5570 return matcher[ expando ] ?
5571 markFunction(function( seed, matches, context, xml ) {
5573 unmatched = matcher( seed, null, xml, [] ),
5577 if ( (elem = unmatched[i]) ) {
5578 seed[i] = !(matches[i] = elem);
5582 function( elem, context, xml ) {
5584 matcher( input, null, xml, results );
5585 return !results.pop();
5589 "has": markFunction(function( selector ) {
5590 return function( elem ) {
5591 return Sizzle( selector, elem ).length > 0;
5595 "contains": markFunction(function( text ) {
5596 return function( elem ) {
5597 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
5601 "lang": markFunction( function( lang ) {
5602 if ( !ridentifier.test(lang || "") ) {
5603 Sizzle.error( "unsupported lang: " + lang );
5605 lang = lang.replace( runescape, funescape ).toLowerCase();
5606 return function( elem ) {
5609 if ( (elemLang = documentIsHTML ?
5611 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
5613 elemLang = elemLang.toLowerCase();
5614 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
5616 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
5621 "target": function( elem ) {
5622 var hash = window.location && window.location.hash;
5623 return hash && hash.slice( 1 ) === elem.id;
5626 "root": function( elem ) {
5627 return elem === docElem;
5630 "focus": function( elem ) {
5631 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
5634 "enabled": function( elem ) {
5635 return elem.disabled === false;
5638 "disabled": function( elem ) {
5639 return elem.disabled === true;
5642 "checked": function( elem ) {
5643 var nodeName = elem.nodeName.toLowerCase();
5644 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
5647 "selected": function( elem ) {
5648 if ( elem.parentNode ) {
5649 elem.parentNode.selectedIndex;
5652 return elem.selected === true;
5655 "empty": function( elem ) {
5656 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5657 if ( elem.nodeType < 6 ) {
5664 "parent": function( elem ) {
5665 return !Expr.pseudos["empty"]( elem );
5668 "header": function( elem ) {
5669 return rheader.test( elem.nodeName );
5672 "input": function( elem ) {
5673 return rinputs.test( elem.nodeName );
5676 "button": function( elem ) {
5677 var name = elem.nodeName.toLowerCase();
5678 return name === "input" && elem.type === "button" || name === "button";
5681 "text": function( elem ) {
5683 return elem.nodeName.toLowerCase() === "input" &&
5684 elem.type === "text" &&
5686 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
5689 "first": createPositionalPseudo(function() {
5693 "last": createPositionalPseudo(function( matchIndexes, length ) {
5694 return [ length - 1 ];
5697 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
5698 return [ argument < 0 ? argument + length : argument ];
5701 "even": createPositionalPseudo(function( matchIndexes, length ) {
5703 for ( ; i < length; i += 2 ) {
5704 matchIndexes.push( i );
5706 return matchIndexes;
5709 "odd": createPositionalPseudo(function( matchIndexes, length ) {
5711 for ( ; i < length; i += 2 ) {
5712 matchIndexes.push( i );
5714 return matchIndexes;
5717 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5718 var i = argument < 0 ? argument + length : argument;
5719 for ( ; --i >= 0; ) {
5720 matchIndexes.push( i );
5722 return matchIndexes;
5725 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5726 var i = argument < 0 ? argument + length : argument;
5727 for ( ; ++i < length; ) {
5728 matchIndexes.push( i );
5730 return matchIndexes;
5735 Expr.pseudos["nth"] = Expr.pseudos["eq"];
5737 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5738 Expr.pseudos[ i ] = createInputPseudo( i );
5740 for ( i in { submit: true, reset: true } ) {
5741 Expr.pseudos[ i ] = createButtonPseudo( i );
5744 function setFilters() {}
5745 setFilters.prototype = Expr.filters = Expr.pseudos;
5746 Expr.setFilters = new setFilters();
5748 function tokenize( selector, parseOnly ) {
5749 var matched, match, tokens, type,
5750 soFar, groups, preFilters,
5751 cached = tokenCache[ selector + " " ];
5754 return parseOnly ? 0 : cached.slice( 0 );
5759 preFilters = Expr.preFilter;
5763 if ( !matched || (match = rcomma.exec( soFar )) ) {
5765 soFar = soFar.slice( match[0].length ) || soFar;
5767 groups.push( (tokens = []) );
5772 if ( (match = rcombinators.exec( soFar )) ) {
5773 matched = match.shift();
5776 type: match[0].replace( rtrim, " " )
5778 soFar = soFar.slice( matched.length );
5781 for ( type in Expr.filter ) {
5782 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5783 (match = preFilters[ type ]( match ))) ) {
5784 matched = match.shift();
5790 soFar = soFar.slice( matched.length );
5802 Sizzle.error( selector ) :
5803 tokenCache( selector, groups ).slice( 0 );
5806 function toSelector( tokens ) {
5808 len = tokens.length,
5810 for ( ; i < len; i++ ) {
5811 selector += tokens[i].value;
5816 function addCombinator( matcher, combinator, base ) {
5817 var dir = combinator.dir,
5818 checkNonElements = base && dir === "parentNode",
5821 return combinator.first ?
5822 function( elem, context, xml ) {
5823 while ( (elem = elem[ dir ]) ) {
5824 if ( elem.nodeType === 1 || checkNonElements ) {
5825 return matcher( elem, context, xml );
5830 function( elem, context, xml ) {
5831 var oldCache, outerCache,
5832 newCache = [ dirruns, doneName ];
5835 while ( (elem = elem[ dir ]) ) {
5836 if ( elem.nodeType === 1 || checkNonElements ) {
5837 if ( matcher( elem, context, xml ) ) {
5843 while ( (elem = elem[ dir ]) ) {
5844 if ( elem.nodeType === 1 || checkNonElements ) {
5845 outerCache = elem[ expando ] || (elem[ expando ] = {});
5846 if ( (oldCache = outerCache[ dir ]) &&
5847 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
5849 return (newCache[ 2 ] = oldCache[ 2 ]);
5851 outerCache[ dir ] = newCache;
5853 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
5863 function elementMatcher( matchers ) {
5864 return matchers.length > 1 ?
5865 function( elem, context, xml ) {
5866 var i = matchers.length;
5868 if ( !matchers[i]( elem, context, xml ) ) {
5877 function multipleContexts( selector, contexts, results ) {
5879 len = contexts.length;
5880 for ( ; i < len; i++ ) {
5881 Sizzle( selector, contexts[i], results );
5886 function condense( unmatched, map, filter, context, xml ) {
5890 len = unmatched.length,
5891 mapped = map != null;
5893 for ( ; i < len; i++ ) {
5894 if ( (elem = unmatched[i]) ) {
5895 if ( !filter || filter( elem, context, xml ) ) {
5896 newUnmatched.push( elem );
5904 return newUnmatched;
5907 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5908 if ( postFilter && !postFilter[ expando ] ) {
5909 postFilter = setMatcher( postFilter );
5911 if ( postFinder && !postFinder[ expando ] ) {
5912 postFinder = setMatcher( postFinder, postSelector );
5914 return markFunction(function( seed, results, context, xml ) {
5918 preexisting = results.length,
5920 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5922 matcherIn = preFilter && ( seed || !selector ) ?
5923 condense( elems, preMap, preFilter, context, xml ) :
5926 matcherOut = matcher ?
5927 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5935 matcher( matcherIn, matcherOut, context, xml );
5939 temp = condense( matcherOut, postMap );
5940 postFilter( temp, [], context, xml );
5944 if ( (elem = temp[i]) ) {
5945 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5951 if ( postFinder || preFilter ) {
5954 i = matcherOut.length;
5956 if ( (elem = matcherOut[i]) ) {
5957 temp.push( (matcherIn[i] = elem) );
5960 postFinder( null, (matcherOut = []), temp, xml );
5963 i = matcherOut.length;
5965 if ( (elem = matcherOut[i]) &&
5966 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5968 seed[temp] = !(results[temp] = elem);
5974 matcherOut = condense(
5975 matcherOut === results ?
5976 matcherOut.splice( preexisting, matcherOut.length ) :
5980 postFinder( null, results, matcherOut, xml );
5982 push.apply( results, matcherOut );
5988 function matcherFromTokens( tokens ) {
5989 var checkContext, matcher, j,
5990 len = tokens.length,
5991 leadingRelative = Expr.relative[ tokens[0].type ],
5992 implicitRelative = leadingRelative || Expr.relative[" "],
5993 i = leadingRelative ? 1 : 0,
5995 matchContext = addCombinator( function( elem ) {
5996 return elem === checkContext;
5997 }, implicitRelative, true ),
5998 matchAnyContext = addCombinator( function( elem ) {
5999 return indexOf.call( checkContext, elem ) > -1;
6000 }, implicitRelative, true ),
6001 matchers = [ function( elem, context, xml ) {
6002 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
6003 (checkContext = context).nodeType ?
6004 matchContext( elem, context, xml ) :
6005 matchAnyContext( elem, context, xml ) );
6008 for ( ; i < len; i++ ) {
6009 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
6010 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
6012 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
6014 if ( matcher[ expando ] ) {
6016 for ( ; j < len; j++ ) {
6017 if ( Expr.relative[ tokens[j].type ] ) {
6022 i > 1 && elementMatcher( matchers ),
6023 i > 1 && toSelector(
6024 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
6025 ).replace( rtrim, "$1" ),
6027 i < j && matcherFromTokens( tokens.slice( i, j ) ),
6028 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
6029 j < len && toSelector( tokens )
6032 matchers.push( matcher );
6036 return elementMatcher( matchers );
6039 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
6040 var bySet = setMatchers.length > 0,
6041 byElement = elementMatchers.length > 0,
6042 superMatcher = function( seed, context, xml, results, outermost ) {
6043 var elem, j, matcher,
6046 unmatched = seed && [],
6048 contextBackup = outermostContext,
6049 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
6050 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
6054 outermostContext = context !== document && context;
6057 for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
6058 if ( byElement && elem ) {
6060 while ( (matcher = elementMatchers[j++]) ) {
6061 if ( matcher( elem, context, xml ) ) {
6062 results.push( elem );
6067 dirruns = dirrunsUnique;
6072 if ( (elem = !matcher && elem) ) {
6077 unmatched.push( elem );
6083 if ( bySet && i !== matchedCount ) {
6085 while ( (matcher = setMatchers[j++]) ) {
6086 matcher( unmatched, setMatched, context, xml );
6090 if ( matchedCount > 0 ) {
6092 if ( !(unmatched[i] || setMatched[i]) ) {
6093 setMatched[i] = pop.call( results );
6098 setMatched = condense( setMatched );
6101 push.apply( results, setMatched );
6103 if ( outermost && !seed && setMatched.length > 0 &&
6104 ( matchedCount + setMatchers.length ) > 1 ) {
6106 Sizzle.uniqueSort( results );
6111 dirruns = dirrunsUnique;
6112 outermostContext = contextBackup;
6119 markFunction( superMatcher ) :
6123 compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
6126 elementMatchers = [],
6127 cached = compilerCache[ selector + " " ];
6131 match = tokenize( selector );
6135 cached = matcherFromTokens( match[i] );
6136 if ( cached[ expando ] ) {
6137 setMatchers.push( cached );
6139 elementMatchers.push( cached );
6143 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
6145 cached.selector = selector;
6151 * A low-level selection function that works with Sizzle's compiled
6152 * selector functions
6153 * @param
{String
|Function
} selector A selector or a pre
-compiled
6154 * selector
function built
with Sizzle
.compile
6155 * @param
{Element
} context
6156 * @param
{Array
} [results
]
6157 * @param
{Array
} [seed
] A
set of elements to match against
6159 select
= Sizzle
.select = function( selector
, context
, results
, seed
) {
6160 var i
, tokens
, token
, type
, find
,
6161 compiled
= typeof selector
=== "function" && selector
,
6162 match
= !seed
&& tokenize( (selector
= compiled
.selector
|| selector
) );
6164 results
= results
|| [];
6166 if ( match
.length
=== 1 ) {
6168 tokens
= match
[0] = match
[0].slice( 0 );
6169 if ( tokens
.length
> 2 && (token
= tokens
[0]).type
=== "ID" &&
6170 support
.getById
&& context
.nodeType
=== 9 && documentIsHTML
&&
6171 Expr
.relative
[ tokens
[1].type
] ) {
6173 context
= ( Expr
.find
["ID"]( token
.matches
[0].replace(runescape
, funescape
), context
) || [] )[0];
6177 } else if ( compiled
) {
6178 context
= context
.parentNode
;
6181 selector
= selector
.slice( tokens
.shift().value
.length
);
6184 i
= matchExpr
["needsContext"].test( selector
) ? 0 : tokens
.length
;
6188 if ( Expr
.relative
[ (type
= token
.type
) ] ) {
6191 if ( (find
= Expr
.find
[ type
]) ) {
6193 token
.matches
[0].replace( runescape
, funescape
),
6194 rsibling
.test( tokens
[0].type
) && testContext( context
.parentNode
) || context
6197 tokens
.splice( i
, 1 );
6198 selector
= seed
.length
&& toSelector( tokens
);
6200 push
.apply( results
, seed
);
6210 ( compiled
|| compile( selector
, match
) )(
6215 rsibling
.test( selector
) && testContext( context
.parentNode
) || context
6221 support
.sortStable
= expando
.split("").sort( sortOrder
).join("") === expando
;
6223 support
.detectDuplicates
= !!hasDuplicate
;
6227 support
.sortDetached
= assert(function( div1
) {
6228 return div1
.compareDocumentPosition( document
.createElement("div") ) & 1;
6231 if ( !assert(function( div
) {
6232 div
.innerHTML
= "<a href='#'></a>";
6233 return div
.firstChild
.getAttribute("href") === "#" ;
6235 addHandle( "type|href|height|width", function( elem
, name
, isXML
) {
6237 return elem
.getAttribute( name
, name
.toLowerCase() === "type" ? 1 : 2 );
6242 if ( !support
.attributes
|| !assert(function( div
) {
6243 div
.innerHTML
= "<input/>";
6244 div
.firstChild
.setAttribute( "value", "" );
6245 return div
.firstChild
.getAttribute( "value" ) === "";
6247 addHandle( "value", function( elem
, name
, isXML
) {
6248 if ( !isXML
&& elem
.nodeName
.toLowerCase() === "input" ) {
6249 return elem
.defaultValue
;
6254 if ( !assert(function( div
) {
6255 return div
.getAttribute("disabled") == null;
6257 addHandle( booleans
, function( elem
, name
, isXML
) {
6260 return elem
[ name
] === true ? name
.toLowerCase() :
6261 (val
= elem
.getAttributeNode( name
)) && val
.specified
?
6268 if ( typeof define
=== "function" && define
.amd
) {
6269 define(function() { return Sizzle
; });
6270 } else if ( typeof module
!== "undefined" && module
.exports
) {
6271 module
.exports
= Sizzle
;
6273 window
.Sizzle
= Sizzle
;
6279 if (typeof Sizzle
!== 'undefined') {
6283 if (typeof define
!== 'undefined' && define
.amd
) {
6284 window
.Sizzle
= Prototype
._actual_sizzle
;
6285 window
.define
= Prototype
._original_define
;
6286 delete Prototype
._actual_sizzle
;
6287 delete Prototype
._original_define
;
6288 } else if (typeof module
!== 'undefined' && module
.exports
) {
6289 window
.Sizzle
= module
.exports
;
6290 module
.exports
= {};
6294 ;(function(engine
) {
6295 var extendElements
= Prototype
.Selector
.extendElements
;
6297 function select(selector
, scope
) {
6298 return extendElements(engine(selector
, scope
|| document
));
6301 function match(element
, selector
) {
6302 return engine
.matches(selector
, [element
]).length
== 1;
6305 Prototype
.Selector
.engine
= engine
;
6306 Prototype
.Selector
.select
= select
;
6307 Prototype
.Selector
.match
= match
;
6310 window
.Sizzle
= Prototype
._original_property
;
6311 delete Prototype
._original_property
;
6314 reset: function(form
) {
6320 serializeElements: function(elements
, options
) {
6321 if (typeof options
!= 'object') options
= { hash
: !!options
};
6322 else if (Object
.isUndefined(options
.hash
)) options
.hash
= true;
6323 var key
, value
, submitted
= false, submit
= options
.submit
, accumulator
, initial
;
6327 accumulator = function(result
, key
, value
) {
6328 if (key
in result
) {
6329 if (!Object
.isArray(result
[key
])) result
[key
] = [result
[key
]];
6330 result
[key
] = result
[key
].concat(value
);
6331 } else result
[key
] = value
;
6336 accumulator = function(result
, key
, values
) {
6337 if (!Object
.isArray(values
)) {values
= [values
];}
6338 if (!values
.length
) {return result
;}
6339 var encodedKey
= encodeURIComponent(key
).gsub(/%20/, '+');
6340 return result
+ (result
? "&" : "") + values
.map(function (value
) {
6341 value
= value
.gsub(/(\r)?\n/, '\r\n');
6342 value
= encodeURIComponent(value
);
6343 value
= value
.gsub(/%20/, '+');
6344 return encodedKey
+ "=" + value
;
6349 return elements
.inject(initial
, function(result
, element
) {
6350 if (!element
.disabled
&& element
.name
) {
6351 key
= element
.name
; value
= $(element
).getValue();
6352 if (value
!= null && element
.type
!= 'file' && (element
.type
!= 'submit' || (!submitted
&&
6353 submit
!== false && (!submit
|| key
== submit
) && (submitted
= true)))) {
6354 result
= accumulator(result
, key
, value
);
6363 serialize: function(form
, options
) {
6364 return Form
.serializeElements(Form
.getElements(form
), options
);
6368 getElements: function(form
) {
6369 var elements
= $(form
).getElementsByTagName('*');
6370 var element
, results
= [], serializers
= Form
.Element
.Serializers
;
6372 for (var i
= 0; element
= elements
[i
]; i
++) {
6373 if (serializers
[element
.tagName
.toLowerCase()])
6374 results
.push(Element
.extend(element
));
6379 getInputs: function(form
, typeName
, name
) {
6381 var inputs
= form
.getElementsByTagName('input');
6383 if (!typeName
&& !name
) return $A(inputs
).map(Element
.extend
);
6385 for (var i
= 0, matchingInputs
= [], length
= inputs
.length
; i
< length
; i
++) {
6386 var input
= inputs
[i
];
6387 if ((typeName
&& input
.type
!= typeName
) || (name
&& input
.name
!= name
))
6389 matchingInputs
.push(Element
.extend(input
));
6392 return matchingInputs
;
6395 disable: function(form
) {
6397 Form
.getElements(form
).invoke('disable');
6401 enable: function(form
) {
6403 Form
.getElements(form
).invoke('enable');
6407 findFirstElement: function(form
) {
6408 var elements
= $(form
).getElements().findAll(function(element
) {
6409 return 'hidden' != element
.type
&& !element
.disabled
;
6411 var firstByIndex
= elements
.findAll(function(element
) {
6412 return element
.hasAttribute('tabIndex') && element
.tabIndex
>= 0;
6413 }).sortBy(function(element
) { return element
.tabIndex
}).first();
6415 return firstByIndex
? firstByIndex
: elements
.find(function(element
) {
6416 return /^(?:input|select|textarea)$/i.test(element
.tagName
);
6420 focusFirstElement: function(form
) {
6422 var element
= form
.findFirstElement();
6423 if (element
) element
.activate();
6427 request: function(form
, options
) {
6428 form
= $(form
), options
= Object
.clone(options
|| { });
6430 var params
= options
.parameters
, action
= form
.readAttribute('action') || '';
6431 if (action
.blank()) action
= window
.location
.href
;
6432 options
.parameters
= form
.serialize(true);
6435 if (Object
.isString(params
)) params
= params
.toQueryParams();
6436 Object
.extend(options
.parameters
, params
);
6439 if (form
.hasAttribute('method') && !options
.method
)
6440 options
.method
= form
.method
;
6442 return new Ajax
.Request(action
, options
);
6446 /*--------------------------------------------------------------------------*/
6450 focus: function(element
) {
6455 select: function(element
) {
6456 $(element
).select();
6461 Form
.Element
.Methods
= {
6463 serialize: function(element
) {
6464 element
= $(element
);
6465 if (!element
.disabled
&& element
.name
) {
6466 var value
= element
.getValue();
6467 if (value
!= undefined) {
6469 pair
[element
.name
] = value
;
6470 return Object
.toQueryString(pair
);
6476 getValue: function(element
) {
6477 element
= $(element
);
6478 var method
= element
.tagName
.toLowerCase();
6479 return Form
.Element
.Serializers
[method
](element
);
6482 setValue: function(element
, value
) {
6483 element
= $(element
);
6484 var method
= element
.tagName
.toLowerCase();
6485 Form
.Element
.Serializers
[method
](element
, value
);
6489 clear: function(element
) {
6490 $(element
).value
= '';
6494 present: function(element
) {
6495 return $(element
).value
!= '';
6498 activate: function(element
) {
6499 element
= $(element
);
6502 if (element
.select
&& (element
.tagName
.toLowerCase() != 'input' ||
6503 !(/^(?:button|reset|submit)$/i.test(element
.type
))))
6509 disable: function(element
) {
6510 element
= $(element
);
6511 element
.disabled
= true;
6515 enable: function(element
) {
6516 element
= $(element
);
6517 element
.disabled
= false;
6522 /*--------------------------------------------------------------------------*/
6524 var Field
= Form
.Element
;
6526 var $F
= Form
.Element
.Methods
.getValue
;
6528 /*--------------------------------------------------------------------------*/
6530 Form
.Element
.Serializers
= (function() {
6531 function input(element
, value
) {
6532 switch (element
.type
.toLowerCase()) {
6535 return inputSelector(element
, value
);
6537 return valueSelector(element
, value
);
6541 function inputSelector(element
, value
) {
6542 if (Object
.isUndefined(value
))
6543 return element
.checked
? element
.value
: null;
6544 else element
.checked
= !!value
;
6547 function valueSelector(element
, value
) {
6548 if (Object
.isUndefined(value
)) return element
.value
;
6549 else element
.value
= value
;
6552 function select(element
, value
) {
6553 if (Object
.isUndefined(value
))
6554 return (element
.type
=== 'select-one' ? selectOne
: selectMany
)(element
);
6556 var opt
, currentValue
, single
= !Object
.isArray(value
);
6557 for (var i
= 0, length
= element
.length
; i
< length
; i
++) {
6558 opt
= element
.options
[i
];
6559 currentValue
= this.optionValue(opt
);
6561 if (currentValue
== value
) {
6562 opt
.selected
= true;
6566 else opt
.selected
= value
.include(currentValue
);
6570 function selectOne(element
) {
6571 var index
= element
.selectedIndex
;
6572 return index
>= 0 ? optionValue(element
.options
[index
]) : null;
6575 function selectMany(element
) {
6576 var values
, length
= element
.length
;
6577 if (!length
) return null;
6579 for (var i
= 0, values
= []; i
< length
; i
++) {
6580 var opt
= element
.options
[i
];
6581 if (opt
.selected
) values
.push(optionValue(opt
));
6586 function optionValue(opt
) {
6587 return Element
.hasAttribute(opt
, 'value') ? opt
.value
: opt
.text
;
6592 inputSelector
: inputSelector
,
6593 textarea
: valueSelector
,
6595 selectOne
: selectOne
,
6596 selectMany
: selectMany
,
6597 optionValue
: optionValue
,
6598 button
: valueSelector
6602 /*--------------------------------------------------------------------------*/
6605 Abstract
.TimedObserver
= Class
.create(PeriodicalExecuter
, {
6606 initialize: function($super, element
, frequency
, callback
) {
6607 $super(callback
, frequency
);
6608 this.element
= $(element
);
6609 this.lastValue
= this.getValue();
6612 execute: function() {
6613 var value
= this.getValue();
6614 if (Object
.isString(this.lastValue
) && Object
.isString(value
) ?
6615 this.lastValue
!= value
: String(this.lastValue
) != String(value
)) {
6616 this.callback(this.element
, value
);
6617 this.lastValue
= value
;
6622 Form
.Element
.Observer
= Class
.create(Abstract
.TimedObserver
, {
6623 getValue: function() {
6624 return Form
.Element
.getValue(this.element
);
6628 Form
.Observer
= Class
.create(Abstract
.TimedObserver
, {
6629 getValue: function() {
6630 return Form
.serialize(this.element
);
6634 /*--------------------------------------------------------------------------*/
6636 Abstract
.EventObserver
= Class
.create({
6637 initialize: function(element
, callback
) {
6638 this.element
= $(element
);
6639 this.callback
= callback
;
6641 this.lastValue
= this.getValue();
6642 if (this.element
.tagName
.toLowerCase() == 'form')
6643 this.registerFormCallbacks();
6645 this.registerCallback(this.element
);
6648 onElementEvent: function() {
6649 var value
= this.getValue();
6650 if (this.lastValue
!= value
) {
6651 this.callback(this.element
, value
);
6652 this.lastValue
= value
;
6656 registerFormCallbacks: function() {
6657 Form
.getElements(this.element
).each(this.registerCallback
, this);
6660 registerCallback: function(element
) {
6662 switch (element
.type
.toLowerCase()) {
6665 Event
.observe(element
, 'click', this.onElementEvent
.bind(this));
6668 Event
.observe(element
, 'change', this.onElementEvent
.bind(this));
6675 Form
.Element
.EventObserver
= Class
.create(Abstract
.EventObserver
, {
6676 getValue: function() {
6677 return Form
.Element
.getValue(this.element
);
6681 Form
.EventObserver
= Class
.create(Abstract
.EventObserver
, {
6682 getValue: function() {
6683 return Form
.serialize(this.element
);
6687 var DIV
= document
.createElement('div');
6688 var docEl
= document
.documentElement
;
6689 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
= 'onmouseenter' in docEl
6690 && 'onmouseleave' in docEl
;
6710 var isIELegacyEvent = function(event
) { return false; };
6712 if (window
.attachEvent
) {
6713 if (window
.addEventListener
) {
6714 isIELegacyEvent = function(event
) {
6715 return !(event
instanceof window
.Event
);
6718 isIELegacyEvent = function(event
) { return true; };
6724 function _isButtonForDOMEvents(event
, code
) {
6725 return event
.which
? (event
.which
=== code
+ 1) : (event
.button
=== code
);
6728 var legacyButtonMap
= { 0: 1, 1: 4, 2: 2 };
6729 function _isButtonForLegacyEvents(event
, code
) {
6730 return event
.button
=== legacyButtonMap
[code
];
6733 function _isButtonForWebKit(event
, code
) {
6735 case 0: return event
.which
== 1 && !event
.metaKey
;
6736 case 1: return event
.which
== 2 || (event
.which
== 1 && event
.metaKey
);
6737 case 2: return event
.which
== 3;
6738 default: return false;
6742 if (window
.attachEvent
) {
6743 if (!window
.addEventListener
) {
6744 _isButton
= _isButtonForLegacyEvents
;
6746 _isButton = function(event
, code
) {
6747 return isIELegacyEvent(event
) ? _isButtonForLegacyEvents(event
, code
) :
6748 _isButtonForDOMEvents(event
, code
);
6751 } else if (Prototype
.Browser
.WebKit
) {
6752 _isButton
= _isButtonForWebKit
;
6754 _isButton
= _isButtonForDOMEvents
;
6757 function isLeftClick(event
) { return _isButton(event
, 0) }
6759 function isMiddleClick(event
) { return _isButton(event
, 1) }
6761 function isRightClick(event
) { return _isButton(event
, 2) }
6763 function element(event
) {
6764 return Element
.extend(_element(event
));
6767 function _element(event
) {
6768 event
= Event
.extend(event
);
6770 var node
= event
.target
, type
= event
.type
,
6771 currentTarget
= event
.currentTarget
;
6773 if (currentTarget
&& currentTarget
.tagName
) {
6774 if (type
=== 'load' || type
=== 'error' ||
6775 (type
=== 'click' && currentTarget
.tagName
.toLowerCase() === 'input'
6776 && currentTarget
.type
=== 'radio'))
6777 node
= currentTarget
;
6780 return node
.nodeType
== Node
.TEXT_NODE
? node
.parentNode
: node
;
6783 function findElement(event
, expression
) {
6784 var element
= _element(event
), selector
= Prototype
.Selector
;
6785 if (!expression
) return Element
.extend(element
);
6787 if (Object
.isElement(element
) && selector
.match(element
, expression
))
6788 return Element
.extend(element
);
6789 element
= element
.parentNode
;
6793 function pointer(event
) {
6794 return { x
: pointerX(event
), y
: pointerY(event
) };
6797 function pointerX(event
) {
6798 var docElement
= document
.documentElement
,
6799 body
= document
.body
|| { scrollLeft
: 0 };
6801 return event
.pageX
|| (event
.clientX
+
6802 (docElement
.scrollLeft
|| body
.scrollLeft
) -
6803 (docElement
.clientLeft
|| 0));
6806 function pointerY(event
) {
6807 var docElement
= document
.documentElement
,
6808 body
= document
.body
|| { scrollTop
: 0 };
6810 return event
.pageY
|| (event
.clientY
+
6811 (docElement
.scrollTop
|| body
.scrollTop
) -
6812 (docElement
.clientTop
|| 0));
6816 function stop(event
) {
6817 Event
.extend(event
);
6818 event
.preventDefault();
6819 event
.stopPropagation();
6821 event
.stopped
= true;
6826 isLeftClick
: isLeftClick
,
6827 isMiddleClick
: isMiddleClick
,
6828 isRightClick
: isRightClick
,
6831 findElement
: findElement
,
6840 var methods
= Object
.keys(Event
.Methods
).inject({ }, function(m
, name
) {
6841 m
[name
] = Event
.Methods
[name
].methodize();
6845 if (window
.attachEvent
) {
6846 function _relatedTarget(event
) {
6848 switch (event
.type
) {
6851 element
= event
.fromElement
;
6855 element
= event
.toElement
;
6860 return Element
.extend(element
);
6863 var additionalMethods
= {
6864 stopPropagation: function() { this.cancelBubble
= true },
6865 preventDefault: function() { this.returnValue
= false },
6866 inspect: function() { return '[object Event]' }
6869 Event
.extend = function(event
, element
) {
6870 if (!event
) return false;
6872 if (!isIELegacyEvent(event
)) return event
;
6874 if (event
._extendedByPrototype
) return event
;
6875 event
._extendedByPrototype
= Prototype
.emptyFunction
;
6877 var pointer
= Event
.pointer(event
);
6879 Object
.extend(event
, {
6880 target
: event
.srcElement
|| element
,
6881 relatedTarget
: _relatedTarget(event
),
6886 Object
.extend(event
, methods
);
6887 Object
.extend(event
, additionalMethods
);
6892 Event
.extend
= Prototype
.K
;
6895 if (window
.addEventListener
) {
6896 Event
.prototype = window
.Event
.prototype || document
.createEvent('HTMLEvents').__proto__
;
6897 Object
.extend(Event
.prototype, methods
);
6900 var EVENT_TRANSLATIONS
= {
6901 mouseenter
: 'mouseover',
6902 mouseleave
: 'mouseout'
6905 function getDOMEventName(eventName
) {
6906 return EVENT_TRANSLATIONS
[eventName
] || eventName
;
6909 if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
)
6910 getDOMEventName
= Prototype
.K
;
6912 function getUniqueElementID(element
) {
6913 if (element
=== window
) return 0;
6915 if (typeof element
._prototypeUID
=== 'undefined')
6916 element
._prototypeUID
= Element
.Storage
.UID
++;
6917 return element
._prototypeUID
;
6920 function getUniqueElementID_IE(element
) {
6921 if (element
=== window
) return 0;
6922 if (element
== document
) return 1;
6923 return element
.uniqueID
;
6926 if ('uniqueID' in DIV
)
6927 getUniqueElementID
= getUniqueElementID_IE
;
6929 function isCustomEvent(eventName
) {
6930 return eventName
.include(':');
6933 Event
._isCustomEvent
= isCustomEvent
;
6935 function getOrCreateRegistryFor(element
, uid
) {
6936 var CACHE
= GLOBAL
.Event
.cache
;
6937 if (Object
.isUndefined(uid
))
6938 uid
= getUniqueElementID(element
);
6939 if (!CACHE
[uid
]) CACHE
[uid
] = { element
: element
};
6943 function destroyRegistryForElement(element
, uid
) {
6944 if (Object
.isUndefined(uid
))
6945 uid
= getUniqueElementID(element
);
6946 delete GLOBAL
.Event
.cache
[uid
];
6950 function register(element
, eventName
, handler
) {
6951 var registry
= getOrCreateRegistryFor(element
);
6952 if (!registry
[eventName
]) registry
[eventName
] = [];
6953 var entries
= registry
[eventName
];
6955 var i
= entries
.length
;
6957 if (entries
[i
].handler
=== handler
) return null;
6959 var uid
= getUniqueElementID(element
);
6960 var responder
= GLOBAL
.Event
._createResponder(uid
, eventName
, handler
);
6962 responder
: responder
,
6966 entries
.push(entry
);
6970 function unregister(element
, eventName
, handler
) {
6971 var registry
= getOrCreateRegistryFor(element
);
6972 var entries
= registry
[eventName
] || [];
6974 var i
= entries
.length
, entry
;
6976 if (entries
[i
].handler
=== handler
) {
6983 var index
= entries
.indexOf(entry
);
6984 entries
.splice(index
, 1);
6987 if (entries
.length
=== 0) {
6988 delete registry
[eventName
];
6989 if (Object
.keys(registry
).length
=== 1 && ('element' in registry
))
6990 destroyRegistryForElement(element
);
6997 function observe(element
, eventName
, handler
) {
6998 element
= $(element
);
6999 var entry
= register(element
, eventName
, handler
);
7001 if (entry
=== null) return element
;
7003 var responder
= entry
.responder
;
7004 if (isCustomEvent(eventName
))
7005 observeCustomEvent(element
, eventName
, responder
);
7007 observeStandardEvent(element
, eventName
, responder
);
7012 function observeStandardEvent(element
, eventName
, responder
) {
7013 var actualEventName
= getDOMEventName(eventName
);
7014 if (element
.addEventListener
) {
7015 element
.addEventListener(actualEventName
, responder
, false);
7017 element
.attachEvent('on' + actualEventName
, responder
);
7021 function observeCustomEvent(element
, eventName
, responder
) {
7022 if (element
.addEventListener
) {
7023 element
.addEventListener('dataavailable', responder
, false);
7025 element
.attachEvent('ondataavailable', responder
);
7026 element
.attachEvent('onlosecapture', responder
);
7030 function stopObserving(element
, eventName
, handler
) {
7031 element
= $(element
);
7032 var handlerGiven
= !Object
.isUndefined(handler
),
7033 eventNameGiven
= !Object
.isUndefined(eventName
);
7035 if (!eventNameGiven
&& !handlerGiven
) {
7036 stopObservingElement(element
);
7040 if (!handlerGiven
) {
7041 stopObservingEventName(element
, eventName
);
7045 var entry
= unregister(element
, eventName
, handler
);
7047 if (!entry
) return element
;
7048 removeEvent(element
, eventName
, entry
.responder
);
7052 function stopObservingStandardEvent(element
, eventName
, responder
) {
7053 var actualEventName
= getDOMEventName(eventName
);
7054 if (element
.removeEventListener
) {
7055 element
.removeEventListener(actualEventName
, responder
, false);
7057 element
.detachEvent('on' + actualEventName
, responder
);
7061 function stopObservingCustomEvent(element
, eventName
, responder
) {
7062 if (element
.removeEventListener
) {
7063 element
.removeEventListener('dataavailable', responder
, false);
7065 element
.detachEvent('ondataavailable', responder
);
7066 element
.detachEvent('onlosecapture', responder
);
7072 function stopObservingElement(element
) {
7073 var uid
= getUniqueElementID(element
), registry
= GLOBAL
.Event
.cache
[uid
];
7074 if (!registry
) return;
7076 destroyRegistryForElement(element
, uid
);
7079 for (var eventName
in registry
) {
7080 if (eventName
=== 'element') continue;
7082 entries
= registry
[eventName
];
7085 removeEvent(element
, eventName
, entries
[i
].responder
);
7089 function stopObservingEventName(element
, eventName
) {
7090 var registry
= getOrCreateRegistryFor(element
);
7091 var entries
= registry
[eventName
];
7093 delete registry
[eventName
];
7096 entries
= entries
|| [];
7098 var i
= entries
.length
;
7100 removeEvent(element
, eventName
, entries
[i
].responder
);
7102 for (var name
in registry
) {
7103 if (name
=== 'element') continue;
7104 return; // There is another registered event
7107 destroyRegistryForElement(element
);
7111 function removeEvent(element
, eventName
, handler
) {
7112 if (isCustomEvent(eventName
))
7113 stopObservingCustomEvent(element
, eventName
, handler
);
7115 stopObservingStandardEvent(element
, eventName
, handler
);
7120 function getFireTarget(element
) {
7121 if (element
!== document
) return element
;
7122 if (document
.createEvent
&& !element
.dispatchEvent
)
7123 return document
.documentElement
;
7127 function fire(element
, eventName
, memo
, bubble
) {
7128 element
= getFireTarget($(element
));
7129 if (Object
.isUndefined(bubble
)) bubble
= true;
7132 var event
= fireEvent(element
, eventName
, memo
, bubble
);
7133 return Event
.extend(event
);
7136 function fireEvent_DOM(element
, eventName
, memo
, bubble
) {
7137 var event
= document
.createEvent('HTMLEvents');
7138 event
.initEvent('dataavailable', bubble
, true);
7140 event
.eventName
= eventName
;
7143 element
.dispatchEvent(event
);
7147 function fireEvent_IE(element
, eventName
, memo
, bubble
) {
7148 var event
= document
.createEventObject();
7149 event
.eventType
= bubble
? 'ondataavailable' : 'onlosecapture';
7151 event
.eventName
= eventName
;
7154 element
.fireEvent(event
.eventType
, event
);
7158 var fireEvent
= document
.createEvent
? fireEvent_DOM
: fireEvent_IE
;
7162 Event
.Handler
= Class
.create({
7163 initialize: function(element
, eventName
, selector
, callback
) {
7164 this.element
= $(element
);
7165 this.eventName
= eventName
;
7166 this.selector
= selector
;
7167 this.callback
= callback
;
7168 this.handler
= this.handleEvent
.bind(this);
7173 Event
.observe(this.element
, this.eventName
, this.handler
);
7178 Event
.stopObserving(this.element
, this.eventName
, this.handler
);
7182 handleEvent: function(event
) {
7183 var element
= Event
.findElement(event
, this.selector
);
7184 if (element
) this.callback
.call(this.element
, event
, element
);
7188 function on(element
, eventName
, selector
, callback
) {
7189 element
= $(element
);
7190 if (Object
.isFunction(selector
) && Object
.isUndefined(callback
)) {
7191 callback
= selector
, selector
= null;
7194 return new Event
.Handler(element
, eventName
, selector
, callback
).start();
7197 Object
.extend(Event
, Event
.Methods
);
7199 Object
.extend(Event
, {
7202 stopObserving
: stopObserving
,
7206 Element
.addMethods({
7211 stopObserving
: stopObserving
,
7216 Object
.extend(document
, {
7217 fire
: fire
.methodize(),
7219 observe
: observe
.methodize(),
7221 stopObserving
: stopObserving
.methodize(),
7223 p_on
: on
.methodize(),
7228 if (GLOBAL
.Event
) Object
.extend(window
.Event
, Event
);
7229 else GLOBAL
.Event
= Event
;
7231 GLOBAL
.Event
.cache
= {};
7233 function destroyCache_IE() {
7234 GLOBAL
.Event
.cache
= null;
7237 if (window
.attachEvent
)
7238 window
.attachEvent('onunload', destroyCache_IE
);
7245 /* Code for creating leak-free event responders is based on work by
7246 John-David Dalton. */
7248 var docEl
= document
.documentElement
;
7249 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
= 'onmouseenter' in docEl
7250 && 'onmouseleave' in docEl
;
7252 function isSimulatedMouseEnterLeaveEvent(eventName
) {
7253 return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
&&
7254 (eventName
=== 'mouseenter' || eventName
=== 'mouseleave');
7257 function createResponder(uid
, eventName
, handler
) {
7258 if (Event
._isCustomEvent(eventName
))
7259 return createResponderForCustomEvent(uid
, eventName
, handler
);
7260 if (isSimulatedMouseEnterLeaveEvent(eventName
))
7261 return createMouseEnterLeaveResponder(uid
, eventName
, handler
);
7263 return function(event
) {
7264 if (!Event
.cache
) return;
7266 var element
= Event
.cache
[uid
].element
;
7267 Event
.extend(event
, element
);
7268 handler
.call(element
, event
);
7272 function createResponderForCustomEvent(uid
, eventName
, handler
) {
7273 return function(event
) {
7274 var cache
= Event
.cache
[uid
];
7275 var element
= cache
&& cache
.element
;
7277 if (Object
.isUndefined(event
.eventName
))
7280 if (event
.eventName
!== eventName
)
7283 Event
.extend(event
, element
);
7284 handler
.call(element
, event
);
7288 function createMouseEnterLeaveResponder(uid
, eventName
, handler
) {
7289 return function(event
) {
7290 var element
= Event
.cache
[uid
].element
;
7292 Event
.extend(event
, element
);
7293 var parent
= event
.relatedTarget
;
7295 while (parent
&& parent
!== element
) {
7296 try { parent
= parent
.parentNode
; }
7297 catch(e
) { parent
= element
; }
7300 if (parent
=== element
) return;
7301 handler
.call(element
, event
);
7305 GLOBAL
.Event
._createResponder
= createResponder
;
7310 /* Support for the DOMContentLoaded event is based on work by Dan Webb,
7311 Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
7315 function fireContentLoadedEvent() {
7316 if (document
.loaded
) return;
7317 if (TIMER
) window
.clearTimeout(TIMER
);
7318 document
.loaded
= true;
7319 document
.fire('dom:loaded');
7322 function checkReadyState() {
7323 if (document
.readyState
=== 'complete') {
7324 document
.detachEvent('onreadystatechange', checkReadyState
);
7325 fireContentLoadedEvent();
7329 function pollDoScroll() {
7331 document
.documentElement
.doScroll('left');
7333 TIMER
= pollDoScroll
.defer();
7337 fireContentLoadedEvent();
7341 if (document
.readyState
=== 'complete') {
7342 fireContentLoadedEvent();
7346 if (document
.addEventListener
) {
7347 document
.addEventListener('DOMContentLoaded', fireContentLoadedEvent
, false);
7349 document
.attachEvent('onreadystatechange', checkReadyState
);
7350 if (window
== top
) TIMER
= pollDoScroll
.defer();
7353 Event
.observe(window
, 'load', fireContentLoadedEvent
);
7357 Element
.addMethods();
7358 /*------------------------------- DEPRECATED -------------------------------*/
7360 Hash
.toQueryString
= Object
.toQueryString
;
7362 var Toggle
= { display
: Element
.toggle
};
7364 Element
.addMethods({
7365 childOf
: Element
.Methods
.descendantOf
7369 Before: function(element
, content
) {
7370 return Element
.insert(element
, {before
:content
});
7373 Top: function(element
, content
) {
7374 return Element
.insert(element
, {top
:content
});
7377 Bottom: function(element
, content
) {
7378 return Element
.insert(element
, {bottom
:content
});
7381 After: function(element
, content
) {
7382 return Element
.insert(element
, {after
:content
});
7386 var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
7389 includeScrollOffsets
: false,
7391 prepare: function() {
7392 this.deltaX
= window
.pageXOffset
7393 || document
.documentElement
.scrollLeft
7394 || document
.body
.scrollLeft
7396 this.deltaY
= window
.pageYOffset
7397 || document
.documentElement
.scrollTop
7398 || document
.body
.scrollTop
7402 within: function(element
, x
, y
) {
7403 if (this.includeScrollOffsets
)
7404 return this.withinIncludingScrolloffsets(element
, x
, y
);
7407 this.offset
= Element
.cumulativeOffset(element
);
7409 return (y
>= this.offset
[1] &&
7410 y
< this.offset
[1] + element
.offsetHeight
&&
7411 x
>= this.offset
[0] &&
7412 x
< this.offset
[0] + element
.offsetWidth
);
7415 withinIncludingScrolloffsets: function(element
, x
, y
) {
7416 var offsetcache
= Element
.cumulativeScrollOffset(element
);
7418 this.xcomp
= x
+ offsetcache
[0] - this.deltaX
;
7419 this.ycomp
= y
+ offsetcache
[1] - this.deltaY
;
7420 this.offset
= Element
.cumulativeOffset(element
);
7422 return (this.ycomp
>= this.offset
[1] &&
7423 this.ycomp
< this.offset
[1] + element
.offsetHeight
&&
7424 this.xcomp
>= this.offset
[0] &&
7425 this.xcomp
< this.offset
[0] + element
.offsetWidth
);
7428 overlap: function(mode
, element
) {
7429 if (!mode
) return 0;
7430 if (mode
== 'vertical')
7431 return ((this.offset
[1] + element
.offsetHeight
) - this.ycomp
) /
7432 element
.offsetHeight
;
7433 if (mode
== 'horizontal')
7434 return ((this.offset
[0] + element
.offsetWidth
) - this.xcomp
) /
7435 element
.offsetWidth
;
7439 cumulativeOffset
: Element
.Methods
.cumulativeOffset
,
7441 positionedOffset
: Element
.Methods
.positionedOffset
,
7443 absolutize: function(element
) {
7445 return Element
.absolutize(element
);
7448 relativize: function(element
) {
7450 return Element
.relativize(element
);
7453 realOffset
: Element
.Methods
.cumulativeScrollOffset
,
7455 offsetParent
: Element
.Methods
.getOffsetParent
,
7457 page
: Element
.Methods
.viewportOffset
,
7459 clone: function(source
, target
, options
) {
7460 options
= options
|| { };
7461 return Element
.clonePosition(target
, source
, options
);
7465 /*--------------------------------------------------------------------------*/
7467 if (!document
.getElementsByClassName
) document
.getElementsByClassName = function(instanceMethods
){
7468 function iter(name
) {
7469 return name
.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name
+ " ')]";
7472 instanceMethods
.getElementsByClassName
= Prototype
.BrowserFeatures
.XPath
?
7473 function(element
, className
) {
7474 className
= className
.toString().strip();
7475 var cond
= /\s/.test(className
) ? $w(className
).map(iter
).join('') : iter(className
);
7476 return cond
? document
._getElementsByXPath('.//*' + cond
, element
) : [];
7477 } : function(element
, className
) {
7478 className
= className
.toString().strip();
7479 var elements
= [], classNames
= (/\s/.test(className
) ? $w(className
) : null);
7480 if (!classNames
&& !className
) return elements
;
7482 var nodes
= $(element
).getElementsByTagName('*');
7483 className
= ' ' + className
+ ' ';
7485 for (var i
= 0, child
, cn
; child
= nodes
[i
]; i
++) {
7486 if (child
.className
&& (cn
= ' ' + child
.className
+ ' ') && (cn
.include(className
) ||
7487 (classNames
&& classNames
.all(function(name
) {
7488 return !name
.toString().blank() && cn
.include(' ' + name
+ ' ');
7490 elements
.push(Element
.extend(child
));
7495 return function(className
, parentElement
) {
7496 return $(parentElement
|| document
.body
).getElementsByClassName(className
);
7500 /*--------------------------------------------------------------------------*/
7502 Element
.ClassNames
= Class
.create();
7503 Element
.ClassNames
.prototype = {
7504 initialize: function(element
) {
7505 this.element
= $(element
);
7508 _each: function(iterator
, context
) {
7509 this.element
.className
.split(/\s+/).select(function(name
) {
7510 return name
.length
> 0;
7511 })._each(iterator
, context
);
7514 set: function(className
) {
7515 this.element
.className
= className
;
7518 add: function(classNameToAdd
) {
7519 if (this.include(classNameToAdd
)) return;
7520 this.set($A(this).concat(classNameToAdd
).join(' '));
7523 remove: function(classNameToRemove
) {
7524 if (!this.include(classNameToRemove
)) return;
7525 this.set($A(this).without(classNameToRemove
).join(' '));
7528 toString: function() {
7529 return $A(this).join(' ');
7533 Object
.extend(Element
.ClassNames
.prototype, Enumerable
);
7535 /*--------------------------------------------------------------------------*/
7538 window
.Selector
= Class
.create({
7539 initialize: function(expression
) {
7540 this.expression
= expression
.strip();
7543 findElements: function(rootElement
) {
7544 return Prototype
.Selector
.select(this.expression
, rootElement
);
7547 match: function(element
) {
7548 return Prototype
.Selector
.match(element
, this.expression
);
7551 toString: function() {
7552 return this.expression
;
7555 inspect: function() {
7556 return "#<Selector: " + this.expression
+ ">";
7560 Object
.extend(Selector
, {
7561 matchElements: function(elements
, expression
) {
7562 var match
= Prototype
.Selector
.match
,
7565 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
7566 var element
= elements
[i
];
7567 if (match(element
, expression
)) {
7568 results
.push(Element
.extend(element
));
7574 findElement: function(elements
, expression
, index
) {
7576 var matchIndex
= 0, element
;
7577 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
7578 element
= elements
[i
];
7579 if (Prototype
.Selector
.match(element
, expression
) && index
=== matchIndex
++) {
7580 return Element
.extend(element
);
7585 findChildElements: function(element
, expressions
) {
7586 var selector
= expressions
.toArray().join(', ');
7587 return Prototype
.Selector
.select(selector
, element
|| document
);