1 // Modified document.on() to modified.p_on() to fix compatibility with Dojo -fox
3 /* Prototype JavaScript framework, version 1.7
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>',
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;
73 for (var i
= 0, length
= arguments
.length
; i
< length
; i
++) {
74 var lambda
= arguments
[i
];
76 returnValue
= lambda();
85 /* Based on Alex Arnell's inheritance implementation. */
87 var Class
= (function() {
89 var IS_DONTENUM_BUGGY
= (function(){
90 for (var p
in { toString
: 1 }) {
91 if (p
=== 'toString') return false;
96 function subclass() {};
98 var parent
= null, properties
= $A(arguments
);
99 if (Object
.isFunction(properties
[0]))
100 parent
= properties
.shift();
103 this.initialize
.apply(this, arguments
);
106 Object
.extend(klass
, Class
.Methods
);
107 klass
.superclass
= parent
;
108 klass
.subclasses
= [];
111 subclass
.prototype = parent
.prototype;
112 klass
.prototype = new subclass
;
113 parent
.subclasses
.push(klass
);
116 for (var i
= 0, length
= properties
.length
; i
< length
; i
++)
117 klass
.addMethods(properties
[i
]);
119 if (!klass
.prototype.initialize
)
120 klass
.prototype.initialize
= Prototype
.emptyFunction
;
122 klass
.prototype.constructor = klass
;
126 function addMethods(source
) {
127 var ancestor
= this.superclass
&& this.superclass
.prototype,
128 properties
= Object
.keys(source
);
130 if (IS_DONTENUM_BUGGY
) {
131 if (source
.toString
!= Object
.prototype.toString
)
132 properties
.push("toString");
133 if (source
.valueOf
!= Object
.prototype.valueOf
)
134 properties
.push("valueOf");
137 for (var i
= 0, length
= properties
.length
; i
< length
; i
++) {
138 var property
= properties
[i
], value
= source
[property
];
139 if (ancestor
&& Object
.isFunction(value
) &&
140 value
.argumentNames()[0] == "$super") {
142 value
= (function(m
) {
143 return function() { return ancestor
[m
].apply(this, arguments
); };
144 })(property
).wrap(method
);
146 value
.valueOf
= method
.valueOf
.bind(method
);
147 value
.toString
= method
.toString
.bind(method
);
149 this.prototype[property
] = value
;
158 addMethods
: addMethods
164 var _toString
= Object
.prototype.toString
,
166 UNDEFINED_TYPE
= 'Undefined',
167 BOOLEAN_TYPE
= 'Boolean',
168 NUMBER_TYPE
= 'Number',
169 STRING_TYPE
= 'String',
170 OBJECT_TYPE
= 'Object',
171 FUNCTION_CLASS
= '[object Function]',
172 BOOLEAN_CLASS
= '[object Boolean]',
173 NUMBER_CLASS
= '[object Number]',
174 STRING_CLASS
= '[object String]',
175 ARRAY_CLASS
= '[object Array]',
176 DATE_CLASS
= '[object Date]',
177 NATIVE_JSON_STRINGIFY_SUPPORT
= window
.JSON
&&
178 typeof JSON
.stringify
=== 'function' &&
179 JSON
.stringify(0) === '0' &&
180 typeof JSON
.stringify(Prototype
.K
) === 'undefined';
184 case null: return NULL_TYPE
;
185 case (void 0): return UNDEFINED_TYPE
;
189 case 'boolean': return BOOLEAN_TYPE
;
190 case 'number': return NUMBER_TYPE
;
191 case 'string': return STRING_TYPE
;
196 function extend(destination
, source
) {
197 for (var property
in source
)
198 destination
[property
] = source
[property
];
202 function inspect(object
) {
204 if (isUndefined(object
)) return 'undefined';
205 if (object
=== null) return 'null';
206 return object
.inspect
? object
.inspect() : String(object
);
208 if (e
instanceof RangeError
) return '...';
213 function toJSON(value
) {
214 return Str('', { '': value
}, []);
217 function Str(key
, holder
, stack
) {
218 var value
= holder
[key
],
221 if (Type(value
) === OBJECT_TYPE
&& typeof value
.toJSON
=== 'function') {
222 value
= value
.toJSON(key
);
225 var _class
= _toString
.call(value
);
231 value
= value
.valueOf();
235 case null: return 'null';
236 case true: return 'true';
237 case false: return 'false';
243 return value
.inspect(true);
245 return isFinite(value
) ? String(value
) : 'null';
248 for (var i
= 0, length
= stack
.length
; i
< length
; i
++) {
249 if (stack
[i
] === value
) { throw new TypeError(); }
254 if (_class
=== ARRAY_CLASS
) {
255 for (var i
= 0, length
= value
.length
; i
< length
; i
++) {
256 var str
= Str(i
, value
, stack
);
257 partial
.push(typeof str
=== 'undefined' ? 'null' : str
);
259 partial
= '[' + partial
.join(',') + ']';
261 var keys
= Object
.keys(value
);
262 for (var i
= 0, length
= keys
.length
; i
< length
; i
++) {
263 var key
= keys
[i
], str
= Str(key
, value
, stack
);
264 if (typeof str
!== "undefined") {
265 partial
.push(key
.inspect(true)+ ':' + str
);
268 partial
= '{' + partial
.join(',') + '}';
275 function stringify(object
) {
276 return JSON
.stringify(object
);
279 function toQueryString(object
) {
280 return $H(object
).toQueryString();
283 function toHTML(object
) {
284 return object
&& object
.toHTML
? object
.toHTML() : String
.interpret(object
);
287 function keys(object
) {
288 if (Type(object
) !== OBJECT_TYPE
) { throw new TypeError(); }
290 for (var property
in object
) {
291 if (object
.hasOwnProperty(property
)) {
292 results
.push(property
);
298 function values(object
) {
300 for (var property
in object
)
301 results
.push(object
[property
]);
305 function clone(object
) {
306 return extend({ }, object
);
309 function isElement(object
) {
310 return !!(object
&& object
.nodeType
== 1);
313 function isArray(object
) {
314 return _toString
.call(object
) === ARRAY_CLASS
;
317 var hasNativeIsArray
= (typeof Array
.isArray
== 'function')
318 && Array
.isArray([]) && !Array
.isArray({});
320 if (hasNativeIsArray
) {
321 isArray
= Array
.isArray
;
324 function isHash(object
) {
325 return object
instanceof Hash
;
328 function isFunction(object
) {
329 return _toString
.call(object
) === FUNCTION_CLASS
;
332 function isString(object
) {
333 return _toString
.call(object
) === STRING_CLASS
;
336 function isNumber(object
) {
337 return _toString
.call(object
) === NUMBER_CLASS
;
340 function isDate(object
) {
341 return _toString
.call(object
) === DATE_CLASS
;
344 function isUndefined(object
) {
345 return typeof object
=== "undefined";
351 toJSON
: NATIVE_JSON_STRINGIFY_SUPPORT
? stringify
: toJSON
,
352 toQueryString
: toQueryString
,
354 keys
: Object
.keys
|| keys
,
357 isElement
: isElement
,
360 isFunction
: isFunction
,
364 isUndefined
: isUndefined
367 Object
.extend(Function
.prototype, (function() {
368 var slice
= Array
.prototype.slice
;
370 function update(array
, args
) {
371 var arrayLength
= array
.length
, length
= args
.length
;
372 while (length
--) array
[arrayLength
+ length
] = args
[length
];
376 function merge(array
, args
) {
377 array
= slice
.call(array
, 0);
378 return update(array
, args
);
381 function argumentNames() {
382 var names
= this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
383 .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
384 .replace(/\s+/g, '').split(',');
385 return names
.length
== 1 && !names
[0] ? [] : names
;
388 function bind(context
) {
389 if (arguments
.length
< 2 && Object
.isUndefined(arguments
[0])) return this;
390 var __method
= this, args
= slice
.call(arguments
, 1);
392 var a
= merge(args
, arguments
);
393 return __method
.apply(context
, a
);
397 function bindAsEventListener(context
) {
398 var __method
= this, args
= slice
.call(arguments
, 1);
399 return function(event
) {
400 var a
= update([event
|| window
.event
], args
);
401 return __method
.apply(context
, a
);
406 if (!arguments
.length
) return this;
407 var __method
= this, args
= slice
.call(arguments
, 0);
409 var a
= merge(args
, arguments
);
410 return __method
.apply(this, a
);
414 function delay(timeout
) {
415 var __method
= this, args
= slice
.call(arguments
, 1);
416 timeout
= timeout
* 1000;
417 return window
.setTimeout(function() {
418 return __method
.apply(__method
, args
);
423 var args
= update([0.01], arguments
);
424 return this.delay
.apply(this, args
);
427 function wrap(wrapper
) {
430 var a
= update([__method
.bind(this)], arguments
);
431 return wrapper
.apply(this, a
);
435 function methodize() {
436 if (this._methodized
) return this._methodized
;
438 return this._methodized = function() {
439 var a
= update([this], arguments
);
440 return __method
.apply(null, a
);
445 argumentNames
: argumentNames
,
447 bindAsEventListener
: bindAsEventListener
,
461 function toISOString() {
462 return this.getUTCFullYear() + '-' +
463 (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
464 this.getUTCDate().toPaddedString(2) + 'T' +
465 this.getUTCHours().toPaddedString(2) + ':' +
466 this.getUTCMinutes().toPaddedString(2) + ':' +
467 this.getUTCSeconds().toPaddedString(2) + 'Z';
472 return this.toISOString();
475 if (!proto
.toISOString
) proto
.toISOString
= toISOString
;
476 if (!proto
.toJSON
) proto
.toJSON
= toJSON
;
481 RegExp
.prototype.match
= RegExp
.prototype.test
;
483 RegExp
.escape = function(str
) {
484 return String(str
).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
486 var PeriodicalExecuter
= Class
.create({
487 initialize: function(callback
, frequency
) {
488 this.callback
= callback
;
489 this.frequency
= frequency
;
490 this.currentlyExecuting
= false;
492 this.registerCallback();
495 registerCallback: function() {
496 this.timer
= setInterval(this.onTimerEvent
.bind(this), this.frequency
* 1000);
499 execute: function() {
504 if (!this.timer
) return;
505 clearInterval(this.timer
);
509 onTimerEvent: function() {
510 if (!this.currentlyExecuting
) {
512 this.currentlyExecuting
= true;
514 this.currentlyExecuting
= false;
516 this.currentlyExecuting
= false;
522 Object
.extend(String
, {
523 interpret: function(value
) {
524 return value
== null ? '' : String(value
);
536 Object
.extend(String
.prototype, (function() {
537 var NATIVE_JSON_PARSE_SUPPORT
= window
.JSON
&&
538 typeof JSON
.parse
=== 'function' &&
539 JSON
.parse('{"test": true}').test
;
541 function prepareReplacement(replacement
) {
542 if (Object
.isFunction(replacement
)) return replacement
;
543 var template
= new Template(replacement
);
544 return function(match
) { return template
.evaluate(match
) };
547 function gsub(pattern
, replacement
) {
548 var result
= '', source
= this, match
;
549 replacement
= prepareReplacement(replacement
);
551 if (Object
.isString(pattern
))
552 pattern
= RegExp
.escape(pattern
);
554 if (!(pattern
.length
|| pattern
.source
)) {
555 replacement
= replacement('');
556 return replacement
+ source
.split('').join(replacement
) + replacement
;
559 while (source
.length
> 0) {
560 if (match
= source
.match(pattern
)) {
561 result
+= source
.slice(0, match
.index
);
562 result
+= String
.interpret(replacement(match
));
563 source
= source
.slice(match
.index
+ match
[0].length
);
565 result
+= source
, source
= '';
571 function sub(pattern
, replacement
, count
) {
572 replacement
= prepareReplacement(replacement
);
573 count
= Object
.isUndefined(count
) ? 1 : count
;
575 return this.gsub(pattern
, function(match
) {
576 if (--count
< 0) return match
[0];
577 return replacement(match
);
581 function scan(pattern
, iterator
) {
582 this.gsub(pattern
, iterator
);
586 function truncate(length
, truncation
) {
587 length
= length
|| 30;
588 truncation
= Object
.isUndefined(truncation
) ? '...' : truncation
;
589 return this.length
> length
?
590 this.slice(0, length
- truncation
.length
) + truncation
: String(this);
594 return this.replace(/^\s+/, '').replace(/\s+$/, '');
597 function stripTags() {
598 return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
601 function stripScripts() {
602 return this.replace(new RegExp(Prototype
.ScriptFragment
, 'img'), '');
605 function extractScripts() {
606 var matchAll
= new RegExp(Prototype
.ScriptFragment
, 'img'),
607 matchOne
= new RegExp(Prototype
.ScriptFragment
, 'im');
608 return (this.match(matchAll
) || []).map(function(scriptTag
) {
609 return (scriptTag
.match(matchOne
) || ['', ''])[1];
613 function evalScripts() {
614 return this.extractScripts().map(function(script
) { return eval(script
) });
617 function escapeHTML() {
618 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g
,'>');
621 function unescapeHTML() {
622 return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');
626 function toQueryParams(separator
) {
627 var match
= this.strip().match(/([^?#]*)(#.*)?$/);
628 if (!match
) return { };
630 return match
[1].split(separator
|| '&').inject({ }, function(hash
, pair
) {
631 if ((pair
= pair
.split('='))[0]) {
632 var key
= decodeURIComponent(pair
.shift()),
633 value
= pair
.length
> 1 ? pair
.join('=') : pair
[0];
635 if (value
!= undefined) value
= decodeURIComponent(value
);
638 if (!Object
.isArray(hash
[key
])) hash
[key
] = [hash
[key
]];
639 hash
[key
].push(value
);
641 else hash
[key
] = value
;
648 return this.split('');
652 return this.slice(0, this.length
- 1) +
653 String
.fromCharCode(this.charCodeAt(this.length
- 1) + 1);
656 function times(count
) {
657 return count
< 1 ? '' : new Array(count
+ 1).join(this);
660 function camelize() {
661 return this.replace(/-+(.)?/g, function(match
, chr
) {
662 return chr
? chr
.toUpperCase() : '';
666 function capitalize() {
667 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
670 function underscore() {
671 return this.replace(/::/g, '/')
672 .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
673 .replace(/([a-z\d])([A-Z])/g, '$1_$2')
678 function dasherize() {
679 return this.replace(/_
/g
, '-');
682 function inspect(useDoubleQuotes
) {
683 var escapedString
= this.replace(/[\x00-\x1f\\]/g, function(character
) {
684 if (character
in String
.specialChar
) {
685 return String
.specialChar
[character
];
687 return '\\u00' + character
.charCodeAt().toPaddedString(2, 16);
689 if (useDoubleQuotes
) return '"' + escapedString
.replace(/"/g, '\\"') + '"';
690 return "'" + escapedString.replace(/'/g
, '\\\'') + "'";
693 function unfilterJSON(filter
) {
694 return this.replace(filter
|| Prototype
.JSONFilter
, '$1');
699 if (str
.blank()) return false;
700 str
= str
.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
701 str
= str
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
702 str
= str
.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
703 return (/^[\],:{}\s]*$/).test(str
);
706 function evalJSON(sanitize
) {
707 var json
= this.unfilterJSON(),
708 cx
= /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
710 json
= json
.replace(cx
, function (a
) {
711 return '\\u' + ('0000' + a
.charCodeAt(0).toString(16)).slice(-4);
715 if (!sanitize
|| json
.isJSON()) return eval('(' + json
+ ')');
717 throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
720 function parseJSON() {
721 var json
= this.unfilterJSON();
722 return JSON
.parse(json
);
725 function include(pattern
) {
726 return this.indexOf(pattern
) > -1;
729 function startsWith(pattern
) {
730 return this.lastIndexOf(pattern
, 0) === 0;
733 function endsWith(pattern
) {
734 var d
= this.length
- pattern
.length
;
735 return d
>= 0 && this.indexOf(pattern
, d
) === d
;
743 return /^\s*$/.test(this);
746 function interpolate(object
, pattern
) {
747 return new Template(this, pattern
).evaluate(object
);
755 strip
: String
.prototype.trim
|| strip
,
756 stripTags
: stripTags
,
757 stripScripts
: stripScripts
,
758 extractScripts
: extractScripts
,
759 evalScripts
: evalScripts
,
760 escapeHTML
: escapeHTML
,
761 unescapeHTML
: unescapeHTML
,
762 toQueryParams
: toQueryParams
,
763 parseQuery
: toQueryParams
,
768 capitalize
: capitalize
,
769 underscore
: underscore
,
770 dasherize
: dasherize
,
772 unfilterJSON
: unfilterJSON
,
774 evalJSON
: NATIVE_JSON_PARSE_SUPPORT
? parseJSON
: evalJSON
,
776 startsWith
: startsWith
,
780 interpolate
: interpolate
784 var Template
= Class
.create({
785 initialize: function(template
, pattern
) {
786 this.template
= template
.toString();
787 this.pattern
= pattern
|| Template
.Pattern
;
790 evaluate: function(object
) {
791 if (object
&& Object
.isFunction(object
.toTemplateReplacements
))
792 object
= object
.toTemplateReplacements();
794 return this.template
.gsub(this.pattern
, function(match
) {
795 if (object
== null) return (match
[1] + '');
797 var before
= match
[1] || '';
798 if (before
== '\\') return match
[2];
800 var ctx
= object
, expr
= match
[3],
801 pattern
= /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
803 match
= pattern
.exec(expr
);
804 if (match
== null) return before
;
806 while (match
!= null) {
807 var comp
= match
[1].startsWith('[') ? match
[2].replace(/\\\\]/g, ']') : match
[1];
809 if (null == ctx
|| '' == match
[3]) break;
810 expr
= expr
.substring('[' == match
[3] ? match
[1].length
: match
[0].length
);
811 match
= pattern
.exec(expr
);
814 return before
+ String
.interpret(ctx
);
818 Template
.Pattern
= /(^|.|\r|\n)(#\{(.*?)\})/;
822 var Enumerable
= (function() {
823 function each(iterator
, context
) {
826 this._each(function(value
) {
827 iterator
.call(context
, value
, index
++);
830 if (e
!= $break) throw e
;
835 function eachSlice(number
, iterator
, context
) {
836 var index
= -number
, slices
= [], array
= this.toArray();
837 if (number
< 1) return array
;
838 while ((index
+= number
) < array
.length
)
839 slices
.push(array
.slice(index
, index
+number
));
840 return slices
.collect(iterator
, context
);
843 function all(iterator
, context
) {
844 iterator
= iterator
|| Prototype
.K
;
846 this.each(function(value
, index
) {
847 result
= result
&& !!iterator
.call(context
, value
, index
);
848 if (!result
) throw $break;
853 function any(iterator
, context
) {
854 iterator
= iterator
|| Prototype
.K
;
856 this.each(function(value
, index
) {
857 if (result
= !!iterator
.call(context
, value
, index
))
863 function collect(iterator
, context
) {
864 iterator
= iterator
|| Prototype
.K
;
866 this.each(function(value
, index
) {
867 results
.push(iterator
.call(context
, value
, index
));
872 function detect(iterator
, context
) {
874 this.each(function(value
, index
) {
875 if (iterator
.call(context
, value
, index
)) {
883 function findAll(iterator
, context
) {
885 this.each(function(value
, index
) {
886 if (iterator
.call(context
, value
, index
))
892 function grep(filter
, iterator
, context
) {
893 iterator
= iterator
|| Prototype
.K
;
896 if (Object
.isString(filter
))
897 filter
= new RegExp(RegExp
.escape(filter
));
899 this.each(function(value
, index
) {
900 if (filter
.match(value
))
901 results
.push(iterator
.call(context
, value
, index
));
906 function include(object
) {
907 if (Object
.isFunction(this.indexOf
))
908 if (this.indexOf(object
) != -1) return true;
911 this.each(function(value
) {
912 if (value
== object
) {
920 function inGroupsOf(number
, fillWith
) {
921 fillWith
= Object
.isUndefined(fillWith
) ? null : fillWith
;
922 return this.eachSlice(number
, function(slice
) {
923 while(slice
.length
< number
) slice
.push(fillWith
);
928 function inject(memo
, iterator
, context
) {
929 this.each(function(value
, index
) {
930 memo
= iterator
.call(context
, memo
, value
, index
);
935 function invoke(method
) {
936 var args
= $A(arguments
).slice(1);
937 return this.map(function(value
) {
938 return value
[method
].apply(value
, args
);
942 function max(iterator
, context
) {
943 iterator
= iterator
|| Prototype
.K
;
945 this.each(function(value
, index
) {
946 value
= iterator
.call(context
, value
, index
);
947 if (result
== null || value
>= result
)
953 function min(iterator
, context
) {
954 iterator
= iterator
|| Prototype
.K
;
956 this.each(function(value
, index
) {
957 value
= iterator
.call(context
, value
, index
);
958 if (result
== null || value
< result
)
964 function partition(iterator
, context
) {
965 iterator
= iterator
|| Prototype
.K
;
966 var trues
= [], falses
= [];
967 this.each(function(value
, index
) {
968 (iterator
.call(context
, value
, index
) ?
969 trues
: falses
).push(value
);
971 return [trues
, falses
];
974 function pluck(property
) {
976 this.each(function(value
) {
977 results
.push(value
[property
]);
982 function reject(iterator
, context
) {
984 this.each(function(value
, index
) {
985 if (!iterator
.call(context
, value
, index
))
991 function sortBy(iterator
, context
) {
992 return this.map(function(value
, index
) {
995 criteria
: iterator
.call(context
, value
, index
)
997 }).sort(function(left
, right
) {
998 var a
= left
.criteria
, b
= right
.criteria
;
999 return a
< b
? -1 : a
> b
? 1 : 0;
1003 function toArray() {
1008 var iterator
= Prototype
.K
, args
= $A(arguments
);
1009 if (Object
.isFunction(args
.last()))
1010 iterator
= args
.pop();
1012 var collections
= [this].concat(args
).map($A
);
1013 return this.map(function(value
, index
) {
1014 return iterator(collections
.pluck(index
));
1019 return this.toArray().length
;
1022 function inspect() {
1023 return '#<Enumerable:' + this.toArray().inspect() + '>';
1036 eachSlice
: eachSlice
,
1050 inGroupsOf
: inGroupsOf
,
1055 partition
: partition
,
1068 function $A(iterable
) {
1069 if (!iterable
) return [];
1070 if ('toArray' in Object(iterable
)) return iterable
.toArray();
1071 var length
= iterable
.length
|| 0, results
= new Array(length
);
1072 while (length
--) results
[length
] = iterable
[length
];
1077 function $w(string
) {
1078 if (!Object
.isString(string
)) return [];
1079 string
= string
.strip();
1080 return string
? string
.split(/\s+/) : [];
1087 var arrayProto
= Array
.prototype,
1088 slice
= arrayProto
.slice
,
1089 _each
= arrayProto
.forEach
; // use native browser JS 1.6 implementation if available
1091 function each(iterator
, context
) {
1092 for (var i
= 0, length
= this.length
>>> 0; i
< length
; i
++) {
1093 if (i
in this) iterator
.call(context
, this[i
], i
, this);
1096 if (!_each
) _each
= each
;
1108 return this[this.length
- 1];
1111 function compact() {
1112 return this.select(function(value
) {
1113 return value
!= null;
1117 function flatten() {
1118 return this.inject([], function(array
, value
) {
1119 if (Object
.isArray(value
))
1120 return array
.concat(value
.flatten());
1126 function without() {
1127 var values
= slice
.call(arguments
, 0);
1128 return this.select(function(value
) {
1129 return !values
.include(value
);
1133 function reverse(inline
) {
1134 return (inline
=== false ? this.toArray() : this)._reverse();
1137 function uniq(sorted
) {
1138 return this.inject([], function(array
, value
, index
) {
1139 if (0 == index
|| (sorted
? array
.last() != value
: !array
.include(value
)))
1145 function intersect(array
) {
1146 return this.uniq().findAll(function(item
) {
1147 return array
.detect(function(value
) { return item
=== value
});
1153 return slice
.call(this, 0);
1160 function inspect() {
1161 return '[' + this.map(Object
.inspect
).join(', ') + ']';
1164 function indexOf(item
, i
) {
1166 var length
= this.length
;
1167 if (i
< 0) i
= length
+ i
;
1168 for (; i
< length
; i
++)
1169 if (this[i
] === item
) return i
;
1173 function lastIndexOf(item
, i
) {
1174 i
= isNaN(i
) ? this.length
: (i
< 0 ? this.length
+ i
: i
) + 1;
1175 var n
= this.slice(0, i
).reverse().indexOf(item
);
1176 return (n
< 0) ? n
: i
- n
- 1;
1180 var array
= slice
.call(this, 0), item
;
1181 for (var i
= 0, length
= arguments
.length
; i
< length
; i
++) {
1182 item
= arguments
[i
];
1183 if (Object
.isArray(item
) && !('callee' in item
)) {
1184 for (var j
= 0, arrayLength
= item
.length
; j
< arrayLength
; j
++)
1185 array
.push(item
[j
]);
1193 Object
.extend(arrayProto
, Enumerable
);
1195 if (!arrayProto
._reverse
)
1196 arrayProto
._reverse
= arrayProto
.reverse
;
1198 Object
.extend(arrayProto
, {
1208 intersect
: intersect
,
1215 var CONCAT_ARGUMENTS_BUGGY
= (function() {
1216 return [].concat(arguments
)[0][0] !== 1;
1219 if (CONCAT_ARGUMENTS_BUGGY
) arrayProto
.concat
= concat
;
1221 if (!arrayProto
.indexOf
) arrayProto
.indexOf
= indexOf
;
1222 if (!arrayProto
.lastIndexOf
) arrayProto
.lastIndexOf
= lastIndexOf
;
1224 function $H(object
) {
1225 return new Hash(object
);
1228 var Hash
= Class
.create(Enumerable
, (function() {
1229 function initialize(object
) {
1230 this._object
= Object
.isHash(object
) ? object
.toObject() : Object
.clone(object
);
1234 function _each(iterator
) {
1235 for (var key
in this._object
) {
1236 var value
= this._object
[key
], pair
= [key
, value
];
1243 function set(key
, value
) {
1244 return this._object
[key
] = value
;
1248 if (this._object
[key
] !== Object
.prototype[key
])
1249 return this._object
[key
];
1252 function unset(key
) {
1253 var value
= this._object
[key
];
1254 delete this._object
[key
];
1258 function toObject() {
1259 return Object
.clone(this._object
);
1265 return this.pluck('key');
1269 return this.pluck('value');
1272 function index(value
) {
1273 var match
= this.detect(function(pair
) {
1274 return pair
.value
=== value
;
1276 return match
&& match
.key
;
1279 function merge(object
) {
1280 return this.clone().update(object
);
1283 function update(object
) {
1284 return new Hash(object
).inject(this, function(result
, pair
) {
1285 result
.set(pair
.key
, pair
.value
);
1290 function toQueryPair(key
, value
) {
1291 if (Object
.isUndefined(value
)) return key
;
1292 return key
+ '=' + encodeURIComponent(String
.interpret(value
));
1295 function toQueryString() {
1296 return this.inject([], function(results
, pair
) {
1297 var key
= encodeURIComponent(pair
.key
), values
= pair
.value
;
1299 if (values
&& typeof values
== 'object') {
1300 if (Object
.isArray(values
)) {
1301 var queryValues
= [];
1302 for (var i
= 0, len
= values
.length
, value
; i
< len
; i
++) {
1304 queryValues
.push(toQueryPair(key
, value
));
1306 return results
.concat(queryValues
);
1308 } else results
.push(toQueryPair(key
, values
));
1313 function inspect() {
1314 return '#<Hash:{' + this.map(function(pair
) {
1315 return pair
.map(Object
.inspect
).join(': ');
1316 }).join(', ') + '}>';
1320 return new Hash(this);
1324 initialize
: initialize
,
1330 toTemplateReplacements
: toObject
,
1336 toQueryString
: toQueryString
,
1344 Object
.extend(Number
.prototype, (function() {
1345 function toColorPart() {
1346 return this.toPaddedString(2, 16);
1353 function times(iterator
, context
) {
1354 $R(0, this, true).each(iterator
, context
);
1358 function toPaddedString(length
, radix
) {
1359 var string
= this.toString(radix
|| 10);
1360 return '0'.times(length
- string
.length
) + string
;
1364 return Math
.abs(this);
1368 return Math
.round(this);
1372 return Math
.ceil(this);
1376 return Math
.floor(this);
1380 toColorPart
: toColorPart
,
1383 toPaddedString
: toPaddedString
,
1391 function $R(start
, end
, exclusive
) {
1392 return new ObjectRange(start
, end
, exclusive
);
1395 var ObjectRange
= Class
.create(Enumerable
, (function() {
1396 function initialize(start
, end
, exclusive
) {
1399 this.exclusive
= exclusive
;
1402 function _each(iterator
) {
1403 var value
= this.start
;
1404 while (this.include(value
)) {
1406 value
= value
.succ();
1410 function include(value
) {
1411 if (value
< this.start
)
1414 return value
< this.end
;
1415 return value
<= this.end
;
1419 initialize
: initialize
,
1428 getTransport: function() {
1430 function() {return new XMLHttpRequest()},
1431 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1432 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1436 activeRequestCount
: 0
1442 _each: function(iterator
) {
1443 this.responders
._each(iterator
);
1446 register: function(responder
) {
1447 if (!this.include(responder
))
1448 this.responders
.push(responder
);
1451 unregister: function(responder
) {
1452 this.responders
= this.responders
.without(responder
);
1455 dispatch: function(callback
, request
, transport
, json
) {
1456 this.each(function(responder
) {
1457 if (Object
.isFunction(responder
[callback
])) {
1459 responder
[callback
].apply(responder
, [request
, transport
, json
]);
1466 Object
.extend(Ajax
.Responders
, Enumerable
);
1468 Ajax
.Responders
.register({
1469 onCreate: function() { Ajax
.activeRequestCount
++ },
1470 onComplete: function() { Ajax
.activeRequestCount
-- }
1472 Ajax
.Base
= Class
.create({
1473 initialize: function(options
) {
1477 contentType
: 'application/x-www-form-urlencoded',
1483 Object
.extend(this.options
, options
|| { });
1485 this.options
.method
= this.options
.method
.toLowerCase();
1487 if (Object
.isHash(this.options
.parameters
))
1488 this.options
.parameters
= this.options
.parameters
.toObject();
1491 Ajax
.Request
= Class
.create(Ajax
.Base
, {
1494 initialize: function($super, url
, options
) {
1496 this.transport
= Ajax
.getTransport();
1500 request: function(url
) {
1502 this.method
= this.options
.method
;
1503 var params
= Object
.isString(this.options
.parameters
) ?
1504 this.options
.parameters
:
1505 Object
.toQueryString(this.options
.parameters
);
1507 if (!['get', 'post'].include(this.method
)) {
1508 params
+= (params
? '&' : '') + "_method=" + this.method
;
1509 this.method
= 'post';
1512 if (params
&& this.method
=== 'get') {
1513 this.url
+= (this.url
.include('?') ? '&' : '?') + params
;
1516 this.parameters
= params
.toQueryParams();
1519 var response
= new Ajax
.Response(this);
1520 if (this.options
.onCreate
) this.options
.onCreate(response
);
1521 Ajax
.Responders
.dispatch('onCreate', this, response
);
1523 this.transport
.open(this.method
.toUpperCase(), this.url
,
1524 this.options
.asynchronous
);
1526 if (this.options
.asynchronous
) this.respondToReadyState
.bind(this).defer(1);
1528 this.transport
.onreadystatechange
= this.onStateChange
.bind(this);
1529 this.setRequestHeaders();
1531 this.body
= this.method
== 'post' ? (this.options
.postBody
|| params
) : null;
1532 this.transport
.send(this.body
);
1534 /* Force Firefox to handle ready state 4 for synchronous requests */
1535 if (!this.options
.asynchronous
&& this.transport
.overrideMimeType
)
1536 this.onStateChange();
1540 this.dispatchException(e
);
1544 onStateChange: function() {
1545 var readyState
= this.transport
.readyState
;
1546 if (readyState
> 1 && !((readyState
== 4) && this._complete
))
1547 this.respondToReadyState(this.transport
.readyState
);
1550 setRequestHeaders: function() {
1552 'X-Requested-With': 'XMLHttpRequest',
1553 'X-Prototype-Version': Prototype
.Version
,
1554 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1557 if (this.method
== 'post') {
1558 headers
['Content-type'] = this.options
.contentType
+
1559 (this.options
.encoding
? '; charset=' + this.options
.encoding
: '');
1561 /* Force "Connection: close" for older Mozilla browsers to work
1562 * around a bug where XMLHttpRequest sends an incorrect
1563 * Content-length header. See Mozilla Bugzilla #246651.
1565 if (this.transport
.overrideMimeType
&&
1566 (navigator
.userAgent
.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1567 headers
['Connection'] = 'close';
1570 if (typeof this.options
.requestHeaders
== 'object') {
1571 var extras
= this.options
.requestHeaders
;
1573 if (Object
.isFunction(extras
.push
))
1574 for (var i
= 0, length
= extras
.length
; i
< length
; i
+= 2)
1575 headers
[extras
[i
]] = extras
[i
+1];
1577 $H(extras
).each(function(pair
) { headers
[pair
.key
] = pair
.value
});
1580 for (var name
in headers
)
1581 this.transport
.setRequestHeader(name
, headers
[name
]);
1584 success: function() {
1585 var status
= this.getStatus();
1586 return !status
|| (status
>= 200 && status
< 300) || status
== 304;
1589 getStatus: function() {
1591 if (this.transport
.status
=== 1223) return 204;
1592 return this.transport
.status
|| 0;
1593 } catch (e
) { return 0 }
1596 respondToReadyState: function(readyState
) {
1597 var state
= Ajax
.Request
.Events
[readyState
], response
= new Ajax
.Response(this);
1599 if (state
== 'Complete') {
1601 this._complete
= true;
1602 (this.options
['on' + response
.status
]
1603 || this.options
['on' + (this.success() ? 'Success' : 'Failure')]
1604 || Prototype
.emptyFunction
)(response
, response
.headerJSON
);
1606 this.dispatchException(e
);
1609 var contentType
= response
.getHeader('Content-type');
1610 if (this.options
.evalJS
== 'force'
1611 || (this.options
.evalJS
&& this.isSameOrigin() && contentType
1612 && contentType
.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1613 this.evalResponse();
1617 (this.options
['on' + state
] || Prototype
.emptyFunction
)(response
, response
.headerJSON
);
1618 Ajax
.Responders
.dispatch('on' + state
, this, response
, response
.headerJSON
);
1620 this.dispatchException(e
);
1623 if (state
== 'Complete') {
1624 this.transport
.onreadystatechange
= Prototype
.emptyFunction
;
1628 isSameOrigin: function() {
1629 var m
= this.url
.match(/^\s*https?:\/\/[^\/]*/);
1630 return !m
|| (m
[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1631 protocol
: location
.protocol
,
1632 domain
: document
.domain
,
1633 port
: location
.port
? ':' + location
.port
: ''
1637 getHeader: function(name
) {
1639 return this.transport
.getResponseHeader(name
) || null;
1640 } catch (e
) { return null; }
1643 evalResponse: function() {
1645 return eval((this.transport
.responseText
|| '').unfilterJSON());
1647 this.dispatchException(e
);
1651 dispatchException: function(exception
) {
1652 (this.options
.onException
|| Prototype
.emptyFunction
)(this, exception
);
1653 Ajax
.Responders
.dispatch('onException', this, exception
);
1657 Ajax
.Request
.Events
=
1658 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1667 Ajax
.Response
= Class
.create({
1668 initialize: function(request
){
1669 this.request
= request
;
1670 var transport
= this.transport
= request
.transport
,
1671 readyState
= this.readyState
= transport
.readyState
;
1673 if ((readyState
> 2 && !Prototype
.Browser
.IE
) || readyState
== 4) {
1674 this.status
= this.getStatus();
1675 this.statusText
= this.getStatusText();
1676 this.responseText
= String
.interpret(transport
.responseText
);
1677 this.headerJSON
= this._getHeaderJSON();
1680 if (readyState
== 4) {
1681 var xml
= transport
.responseXML
;
1682 this.responseXML
= Object
.isUndefined(xml
) ? null : xml
;
1683 this.responseJSON
= this._getResponseJSON();
1691 getStatus
: Ajax
.Request
.prototype.getStatus
,
1693 getStatusText: function() {
1695 return this.transport
.statusText
|| '';
1696 } catch (e
) { return '' }
1699 getHeader
: Ajax
.Request
.prototype.getHeader
,
1701 getAllHeaders: function() {
1703 return this.getAllResponseHeaders();
1704 } catch (e
) { return null }
1707 getResponseHeader: function(name
) {
1708 return this.transport
.getResponseHeader(name
);
1711 getAllResponseHeaders: function() {
1712 return this.transport
.getAllResponseHeaders();
1715 _getHeaderJSON: function() {
1716 var json
= this.getHeader('X-JSON');
1717 if (!json
) return null;
1718 json
= decodeURIComponent(escape(json
));
1720 return json
.evalJSON(this.request
.options
.sanitizeJSON
||
1721 !this.request
.isSameOrigin());
1723 this.request
.dispatchException(e
);
1727 _getResponseJSON: function() {
1728 var options
= this.request
.options
;
1729 if (!options
.evalJSON
|| (options
.evalJSON
!= 'force' &&
1730 !(this.getHeader('Content-type') || '').include('application/json')) ||
1731 this.responseText
.blank())
1734 return this.responseText
.evalJSON(options
.sanitizeJSON
||
1735 !this.request
.isSameOrigin());
1737 this.request
.dispatchException(e
);
1742 Ajax
.Updater
= Class
.create(Ajax
.Request
, {
1743 initialize: function($super, container
, url
, options
) {
1745 success
: (container
.success
|| container
),
1746 failure
: (container
.failure
|| (container
.success
? null : container
))
1749 options
= Object
.clone(options
);
1750 var onComplete
= options
.onComplete
;
1751 options
.onComplete
= (function(response
, json
) {
1752 this.updateContent(response
.responseText
);
1753 if (Object
.isFunction(onComplete
)) onComplete(response
, json
);
1756 $super(url
, options
);
1759 updateContent: function(responseText
) {
1760 var receiver
= this.container
[this.success() ? 'success' : 'failure'],
1761 options
= this.options
;
1763 if (!options
.evalScripts
) responseText
= responseText
.stripScripts();
1765 if (receiver
= $(receiver
)) {
1766 if (options
.insertion
) {
1767 if (Object
.isString(options
.insertion
)) {
1768 var insertion
= { }; insertion
[options
.insertion
] = responseText
;
1769 receiver
.insert(insertion
);
1771 else options
.insertion(receiver
, responseText
);
1773 else receiver
.update(responseText
);
1778 Ajax
.PeriodicalUpdater
= Class
.create(Ajax
.Base
, {
1779 initialize: function($super, container
, url
, options
) {
1781 this.onComplete
= this.options
.onComplete
;
1783 this.frequency
= (this.options
.frequency
|| 2);
1784 this.decay
= (this.options
.decay
|| 1);
1787 this.container
= container
;
1794 this.options
.onComplete
= this.updateComplete
.bind(this);
1795 this.onTimerEvent();
1799 this.updater
.options
.onComplete
= undefined;
1800 clearTimeout(this.timer
);
1801 (this.onComplete
|| Prototype
.emptyFunction
).apply(this, arguments
);
1804 updateComplete: function(response
) {
1805 if (this.options
.decay
) {
1806 this.decay
= (response
.responseText
== this.lastText
?
1807 this.decay
* this.options
.decay
: 1);
1809 this.lastText
= response
.responseText
;
1811 this.timer
= this.onTimerEvent
.bind(this).delay(this.decay
* this.frequency
);
1814 onTimerEvent: function() {
1815 this.updater
= new Ajax
.Updater(this.container
, this.url
, this.options
);
1820 function $(element
) {
1821 if (arguments
.length
> 1) {
1822 for (var i
= 0, elements
= [], length
= arguments
.length
; i
< length
; i
++)
1823 elements
.push($(arguments
[i
]));
1826 if (Object
.isString(element
))
1827 element
= document
.getElementById(element
);
1828 return Element
.extend(element
);
1831 if (Prototype
.BrowserFeatures
.XPath
) {
1832 document
._getElementsByXPath = function(expression
, parentElement
) {
1834 var query
= document
.evaluate(expression
, $(parentElement
) || document
,
1835 null, XPathResult
.ORDERED_NODE_SNAPSHOT_TYPE
, null);
1836 for (var i
= 0, length
= query
.snapshotLength
; i
< length
; i
++)
1837 results
.push(Element
.extend(query
.snapshotItem(i
)));
1842 /*--------------------------------------------------------------------------*/
1844 if (!Node
) var Node
= { };
1846 if (!Node
.ELEMENT_NODE
) {
1847 Object
.extend(Node
, {
1851 CDATA_SECTION_NODE
: 4,
1852 ENTITY_REFERENCE_NODE
: 5,
1854 PROCESSING_INSTRUCTION_NODE
: 7,
1857 DOCUMENT_TYPE_NODE
: 10,
1858 DOCUMENT_FRAGMENT_NODE
: 11,
1866 function shouldUseCache(tagName
, attributes
) {
1867 if (tagName
=== 'select') return false;
1868 if ('type' in attributes
) return false;
1872 var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
= (function(){
1874 var el
= document
.createElement('<input name="x">');
1875 return el
.tagName
.toLowerCase() === 'input' && el
.name
=== 'x';
1882 var element
= global
.Element
;
1884 global
.Element = function(tagName
, attributes
) {
1885 attributes
= attributes
|| { };
1886 tagName
= tagName
.toLowerCase();
1887 var cache
= Element
.cache
;
1889 if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX
&& attributes
.name
) {
1890 tagName
= '<' + tagName
+ ' name="' + attributes
.name
+ '">';
1891 delete attributes
.name
;
1892 return Element
.writeAttribute(document
.createElement(tagName
), attributes
);
1895 if (!cache
[tagName
]) cache
[tagName
] = Element
.extend(document
.createElement(tagName
));
1897 var node
= shouldUseCache(tagName
, attributes
) ?
1898 cache
[tagName
].cloneNode(false) : document
.createElement(tagName
);
1900 return Element
.writeAttribute(node
, attributes
);
1903 Object
.extend(global
.Element
, element
|| { });
1904 if (element
) global
.Element
.prototype = element
.prototype;
1908 Element
.idCounter
= 1;
1909 Element
.cache
= { };
1911 Element
._purgeElement = function(element
) {
1912 var uid
= element
._prototypeUID
;
1914 Element
.stopObserving(element
);
1915 element
._prototypeUID
= void 0;
1916 delete Element
.Storage
[uid
];
1921 visible: function(element
) {
1922 return $(element
).style
.display
!= 'none';
1925 toggle: function(element
) {
1926 element
= $(element
);
1927 Element
[Element
.visible(element
) ? 'hide' : 'show'](element
);
1931 hide: function(element
) {
1932 element
= $(element
);
1933 element
.style
.display
= 'none';
1937 show: function(element
) {
1938 element
= $(element
);
1939 element
.style
.display
= '';
1943 remove: function(element
) {
1944 element
= $(element
);
1945 element
.parentNode
.removeChild(element
);
1949 update
: (function(){
1951 var SELECT_ELEMENT_INNERHTML_BUGGY
= (function(){
1952 var el
= document
.createElement("select"),
1954 el
.innerHTML
= "<option value=\"test\">test</option>";
1955 if (el
.options
&& el
.options
[0]) {
1956 isBuggy
= el
.options
[0].nodeName
.toUpperCase() !== "OPTION";
1962 var TABLE_ELEMENT_INNERHTML_BUGGY
= (function(){
1964 var el
= document
.createElement("table");
1965 if (el
&& el
.tBodies
) {
1966 el
.innerHTML
= "<tbody><tr><td>test</td></tr></tbody>";
1967 var isBuggy
= typeof el
.tBodies
[0] == "undefined";
1976 var LINK_ELEMENT_INNERHTML_BUGGY
= (function() {
1978 var el
= document
.createElement('div');
1979 el
.innerHTML
= "<link>";
1980 var isBuggy
= (el
.childNodes
.length
=== 0);
1988 var ANY_INNERHTML_BUGGY
= SELECT_ELEMENT_INNERHTML_BUGGY
||
1989 TABLE_ELEMENT_INNERHTML_BUGGY
|| LINK_ELEMENT_INNERHTML_BUGGY
;
1991 var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING
= (function () {
1992 var s
= document
.createElement("script"),
1995 s
.appendChild(document
.createTextNode(""));
1996 isBuggy
= !s
.firstChild
||
1997 s
.firstChild
&& s
.firstChild
.nodeType
!== 3;
2006 function update(element
, content
) {
2007 element
= $(element
);
2008 var purgeElement
= Element
._purgeElement
;
2010 var descendants
= element
.getElementsByTagName('*'),
2011 i
= descendants
.length
;
2012 while (i
--) purgeElement(descendants
[i
]);
2014 if (content
&& content
.toElement
)
2015 content
= content
.toElement();
2017 if (Object
.isElement(content
))
2018 return element
.update().insert(content
);
2020 content
= Object
.toHTML(content
);
2022 var tagName
= element
.tagName
.toUpperCase();
2024 if (tagName
=== 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING
) {
2025 element
.text
= content
;
2029 if (ANY_INNERHTML_BUGGY
) {
2030 if (tagName
in Element
._insertionTranslations
.tags
) {
2031 while (element
.firstChild
) {
2032 element
.removeChild(element
.firstChild
);
2034 Element
._getContentFromAnonymousElement(tagName
, content
.stripScripts())
2035 .each(function(node
) {
2036 element
.appendChild(node
)
2038 } else if (LINK_ELEMENT_INNERHTML_BUGGY
&& Object
.isString(content
) && content
.indexOf('<link') > -1) {
2039 while (element
.firstChild
) {
2040 element
.removeChild(element
.firstChild
);
2042 var nodes
= Element
._getContentFromAnonymousElement(tagName
, content
.stripScripts(), true);
2043 nodes
.each(function(node
) { element
.appendChild(node
) });
2046 element
.innerHTML
= content
.stripScripts();
2050 element
.innerHTML
= content
.stripScripts();
2053 content
.evalScripts
.bind(content
).defer();
2060 replace: function(element
, content
) {
2061 element
= $(element
);
2062 if (content
&& content
.toElement
) content
= content
.toElement();
2063 else if (!Object
.isElement(content
)) {
2064 content
= Object
.toHTML(content
);
2065 var range
= element
.ownerDocument
.createRange();
2066 range
.selectNode(element
);
2067 content
.evalScripts
.bind(content
).defer();
2068 content
= range
.createContextualFragment(content
.stripScripts());
2070 element
.parentNode
.replaceChild(content
, element
);
2074 insert: function(element
, insertions
) {
2075 element
= $(element
);
2077 if (Object
.isString(insertions
) || Object
.isNumber(insertions
) ||
2078 Object
.isElement(insertions
) || (insertions
&& (insertions
.toElement
|| insertions
.toHTML
)))
2079 insertions
= {bottom
:insertions
};
2081 var content
, insert
, tagName
, childNodes
;
2083 for (var position
in insertions
) {
2084 content
= insertions
[position
];
2085 position
= position
.toLowerCase();
2086 insert
= Element
._insertionTranslations
[position
];
2088 if (content
&& content
.toElement
) content
= content
.toElement();
2089 if (Object
.isElement(content
)) {
2090 insert(element
, content
);
2094 content
= Object
.toHTML(content
);
2096 tagName
= ((position
== 'before' || position
== 'after')
2097 ? element
.parentNode
: element
).tagName
.toUpperCase();
2099 childNodes
= Element
._getContentFromAnonymousElement(tagName
, content
.stripScripts());
2101 if (position
== 'top' || position
== 'after') childNodes
.reverse();
2102 childNodes
.each(insert
.curry(element
));
2104 content
.evalScripts
.bind(content
).defer();
2110 wrap: function(element
, wrapper
, attributes
) {
2111 element
= $(element
);
2112 if (Object
.isElement(wrapper
))
2113 $(wrapper
).writeAttribute(attributes
|| { });
2114 else if (Object
.isString(wrapper
)) wrapper
= new Element(wrapper
, attributes
);
2115 else wrapper
= new Element('div', wrapper
);
2116 if (element
.parentNode
)
2117 element
.parentNode
.replaceChild(wrapper
, element
);
2118 wrapper
.appendChild(element
);
2122 inspect: function(element
) {
2123 element
= $(element
);
2124 var result
= '<' + element
.tagName
.toLowerCase();
2125 $H({'id': 'id', 'className': 'class'}).each(function(pair
) {
2126 var property
= pair
.first(),
2127 attribute
= pair
.last(),
2128 value
= (element
[property
] || '').toString();
2129 if (value
) result
+= ' ' + attribute
+ '=' + value
.inspect(true);
2131 return result
+ '>';
2134 recursivelyCollect: function(element
, property
, maximumLength
) {
2135 element
= $(element
);
2136 maximumLength
= maximumLength
|| -1;
2139 while (element
= element
[property
]) {
2140 if (element
.nodeType
== 1)
2141 elements
.push(Element
.extend(element
));
2142 if (elements
.length
== maximumLength
)
2149 ancestors: function(element
) {
2150 return Element
.recursivelyCollect(element
, 'parentNode');
2153 descendants: function(element
) {
2154 return Element
.select(element
, "*");
2157 firstDescendant: function(element
) {
2158 element
= $(element
).firstChild
;
2159 while (element
&& element
.nodeType
!= 1) element
= element
.nextSibling
;
2163 immediateDescendants: function(element
) {
2164 var results
= [], child
= $(element
).firstChild
;
2166 if (child
.nodeType
=== 1) {
2167 results
.push(Element
.extend(child
));
2169 child
= child
.nextSibling
;
2174 previousSiblings: function(element
, maximumLength
) {
2175 return Element
.recursivelyCollect(element
, 'previousSibling');
2178 nextSiblings: function(element
) {
2179 return Element
.recursivelyCollect(element
, 'nextSibling');
2182 siblings: function(element
) {
2183 element
= $(element
);
2184 return Element
.previousSiblings(element
).reverse()
2185 .concat(Element
.nextSiblings(element
));
2188 match: function(element
, selector
) {
2189 element
= $(element
);
2190 if (Object
.isString(selector
))
2191 return Prototype
.Selector
.match(element
, selector
);
2192 return selector
.match(element
);
2195 up: function(element
, expression
, index
) {
2196 element
= $(element
);
2197 if (arguments
.length
== 1) return $(element
.parentNode
);
2198 var ancestors
= Element
.ancestors(element
);
2199 return Object
.isNumber(expression
) ? ancestors
[expression
] :
2200 Prototype
.Selector
.find(ancestors
, expression
, index
);
2203 down: function(element
, expression
, index
) {
2204 element
= $(element
);
2205 if (arguments
.length
== 1) return Element
.firstDescendant(element
);
2206 return Object
.isNumber(expression
) ? Element
.descendants(element
)[expression
] :
2207 Element
.select(element
, expression
)[index
|| 0];
2210 previous: function(element
, expression
, index
) {
2211 element
= $(element
);
2212 if (Object
.isNumber(expression
)) index
= expression
, expression
= false;
2213 if (!Object
.isNumber(index
)) index
= 0;
2216 return Prototype
.Selector
.find(element
.previousSiblings(), expression
, index
);
2218 return element
.recursivelyCollect("previousSibling", index
+ 1)[index
];
2222 next: function(element
, expression
, index
) {
2223 element
= $(element
);
2224 if (Object
.isNumber(expression
)) index
= expression
, expression
= false;
2225 if (!Object
.isNumber(index
)) index
= 0;
2228 return Prototype
.Selector
.find(element
.nextSiblings(), expression
, index
);
2230 var maximumLength
= Object
.isNumber(index
) ? index
+ 1 : 1;
2231 return element
.recursivelyCollect("nextSibling", index
+ 1)[index
];
2236 select: function(element
) {
2237 element
= $(element
);
2238 var expressions
= Array
.prototype.slice
.call(arguments
, 1).join(', ');
2239 return Prototype
.Selector
.select(expressions
, element
);
2242 adjacent: function(element
) {
2243 element
= $(element
);
2244 var expressions
= Array
.prototype.slice
.call(arguments
, 1).join(', ');
2245 return Prototype
.Selector
.select(expressions
, element
.parentNode
).without(element
);
2248 identify: function(element
) {
2249 element
= $(element
);
2250 var id
= Element
.readAttribute(element
, 'id');
2252 do { id
= 'anonymous_element_' + Element
.idCounter
++ } while ($(id
));
2253 Element
.writeAttribute(element
, 'id', id
);
2257 readAttribute: function(element
, name
) {
2258 element
= $(element
);
2259 if (Prototype
.Browser
.IE
) {
2260 var t
= Element
._attributeTranslations
.read
;
2261 if (t
.values
[name
]) return t
.values
[name
](element
, name
);
2262 if (t
.names
[name
]) name
= t
.names
[name
];
2263 if (name
.include(':')) {
2264 return (!element
.attributes
|| !element
.attributes
[name
]) ? null :
2265 element
.attributes
[name
].value
;
2268 return element
.getAttribute(name
);
2271 writeAttribute: function(element
, name
, value
) {
2272 element
= $(element
);
2273 var attributes
= { }, t
= Element
._attributeTranslations
.write
;
2275 if (typeof name
== 'object') attributes
= name
;
2276 else attributes
[name
] = Object
.isUndefined(value
) ? true : value
;
2278 for (var attr
in attributes
) {
2279 name
= t
.names
[attr
] || attr
;
2280 value
= attributes
[attr
];
2281 if (t
.values
[attr
]) name
= t
.values
[attr
](element
, value
);
2282 if (value
=== false || value
=== null)
2283 element
.removeAttribute(name
);
2284 else if (value
=== true)
2285 element
.setAttribute(name
, name
);
2286 else element
.setAttribute(name
, value
);
2291 getHeight: function(element
) {
2292 return Element
.getDimensions(element
).height
;
2295 getWidth: function(element
) {
2296 return Element
.getDimensions(element
).width
;
2299 classNames: function(element
) {
2300 return new Element
.ClassNames(element
);
2303 hasClassName: function(element
, className
) {
2304 if (!(element
= $(element
))) return;
2305 var elementClassName
= element
.className
;
2306 return (elementClassName
.length
> 0 && (elementClassName
== className
||
2307 new RegExp("(^|\\s)" + className
+ "(\\s|$)").test(elementClassName
)));
2310 addClassName: function(element
, className
) {
2311 if (!(element
= $(element
))) return;
2312 if (!Element
.hasClassName(element
, className
))
2313 element
.className
+= (element
.className
? ' ' : '') + className
;
2317 removeClassName: function(element
, className
) {
2318 if (!(element
= $(element
))) return;
2319 element
.className
= element
.className
.replace(
2320 new RegExp("(^|\\s+)" + className
+ "(\\s+|$)"), ' ').strip();
2324 toggleClassName: function(element
, className
) {
2325 if (!(element
= $(element
))) return;
2326 return Element
[Element
.hasClassName(element
, className
) ?
2327 'removeClassName' : 'addClassName'](element
, className
);
2330 cleanWhitespace: function(element
) {
2331 element
= $(element
);
2332 var node
= element
.firstChild
;
2334 var nextNode
= node
.nextSibling
;
2335 if (node
.nodeType
== 3 && !/\S/.test(node
.nodeValue
))
2336 element
.removeChild(node
);
2342 empty: function(element
) {
2343 return $(element
).innerHTML
.blank();
2346 descendantOf: function(element
, ancestor
) {
2347 element
= $(element
), ancestor
= $(ancestor
);
2349 if (element
.compareDocumentPosition
)
2350 return (element
.compareDocumentPosition(ancestor
) & 8) === 8;
2352 if (ancestor
.contains
)
2353 return ancestor
.contains(element
) && ancestor
!== element
;
2355 while (element
= element
.parentNode
)
2356 if (element
== ancestor
) return true;
2361 scrollTo: function(element
) {
2362 element
= $(element
);
2363 var pos
= Element
.cumulativeOffset(element
);
2364 window
.scrollTo(pos
[0], pos
[1]);
2368 getStyle: function(element
, style
) {
2369 element
= $(element
);
2370 style
= style
== 'float' ? 'cssFloat' : style
.camelize();
2371 var value
= element
.style
[style
];
2372 if (!value
|| value
== 'auto') {
2373 var css
= document
.defaultView
.getComputedStyle(element
, null);
2374 value
= css
? css
[style
] : null;
2376 if (style
== 'opacity') return value
? parseFloat(value
) : 1.0;
2377 return value
== 'auto' ? null : value
;
2380 getOpacity: function(element
) {
2381 return $(element
).getStyle('opacity');
2384 setStyle: function(element
, styles
) {
2385 element
= $(element
);
2386 var elementStyle
= element
.style
, match
;
2387 if (Object
.isString(styles
)) {
2388 element
.style
.cssText
+= ';' + styles
;
2389 return styles
.include('opacity') ?
2390 element
.setOpacity(styles
.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element
;
2392 for (var property
in styles
)
2393 if (property
== 'opacity') element
.setOpacity(styles
[property
]);
2395 elementStyle
[(property
== 'float' || property
== 'cssFloat') ?
2396 (Object
.isUndefined(elementStyle
.styleFloat
) ? 'cssFloat' : 'styleFloat') :
2397 property
] = styles
[property
];
2402 setOpacity: function(element
, value
) {
2403 element
= $(element
);
2404 element
.style
.opacity
= (value
== 1 || value
=== '') ? '' :
2405 (value
< 0.00001) ? 0 : value
;
2409 makePositioned: function(element
) {
2410 element
= $(element
);
2411 var pos
= Element
.getStyle(element
, 'position');
2412 if (pos
== 'static' || !pos
) {
2413 element
._madePositioned
= true;
2414 element
.style
.position
= 'relative';
2415 if (Prototype
.Browser
.Opera
) {
2416 element
.style
.top
= 0;
2417 element
.style
.left
= 0;
2423 undoPositioned: function(element
) {
2424 element
= $(element
);
2425 if (element
._madePositioned
) {
2426 element
._madePositioned
= undefined;
2427 element
.style
.position
=
2429 element
.style
.left
=
2430 element
.style
.bottom
=
2431 element
.style
.right
= '';
2436 makeClipping: function(element
) {
2437 element
= $(element
);
2438 if (element
._overflow
) return element
;
2439 element
._overflow
= Element
.getStyle(element
, 'overflow') || 'auto';
2440 if (element
._overflow
!== 'hidden')
2441 element
.style
.overflow
= 'hidden';
2445 undoClipping: function(element
) {
2446 element
= $(element
);
2447 if (!element
._overflow
) return element
;
2448 element
.style
.overflow
= element
._overflow
== 'auto' ? '' : element
._overflow
;
2449 element
._overflow
= null;
2453 clonePosition: function(element
, source
) {
2454 var options
= Object
.extend({
2461 }, arguments
[2] || { });
2464 var p
= Element
.viewportOffset(source
), delta
= [0, 0], parent
= null;
2466 element
= $(element
);
2468 if (Element
.getStyle(element
, 'position') == 'absolute') {
2469 parent
= Element
.getOffsetParent(element
);
2470 delta
= Element
.viewportOffset(parent
);
2473 if (parent
== document
.body
) {
2474 delta
[0] -= document
.body
.offsetLeft
;
2475 delta
[1] -= document
.body
.offsetTop
;
2478 if (options
.setLeft
) element
.style
.left
= (p
[0] - delta
[0] + options
.offsetLeft
) + 'px';
2479 if (options
.setTop
) element
.style
.top
= (p
[1] - delta
[1] + options
.offsetTop
) + 'px';
2480 if (options
.setWidth
) element
.style
.width
= source
.offsetWidth
+ 'px';
2481 if (options
.setHeight
) element
.style
.height
= source
.offsetHeight
+ 'px';
2486 Object
.extend(Element
.Methods
, {
2487 getElementsBySelector
: Element
.Methods
.select
,
2489 childElements
: Element
.Methods
.immediateDescendants
2492 Element
._attributeTranslations
= {
2502 if (Prototype
.Browser
.Opera
) {
2503 Element
.Methods
.getStyle
= Element
.Methods
.getStyle
.wrap(
2504 function(proceed
, element
, style
) {
2506 case 'height': case 'width':
2507 if (!Element
.visible(element
)) return null;
2509 var dim
= parseInt(proceed(element
, style
), 10);
2511 if (dim
!== element
['offset' + style
.capitalize()])
2515 if (style
=== 'height') {
2516 properties
= ['border-top-width', 'padding-top',
2517 'padding-bottom', 'border-bottom-width'];
2520 properties
= ['border-left-width', 'padding-left',
2521 'padding-right', 'border-right-width'];
2523 return properties
.inject(dim
, function(memo
, property
) {
2524 var val
= proceed(element
, property
);
2525 return val
=== null ? memo
: memo
- parseInt(val
, 10);
2527 default: return proceed(element
, style
);
2532 Element
.Methods
.readAttribute
= Element
.Methods
.readAttribute
.wrap(
2533 function(proceed
, element
, attribute
) {
2534 if (attribute
=== 'title') return element
.title
;
2535 return proceed(element
, attribute
);
2540 else if (Prototype
.Browser
.IE
) {
2541 Element
.Methods
.getStyle = function(element
, style
) {
2542 element
= $(element
);
2543 style
= (style
== 'float' || style
== 'cssFloat') ? 'styleFloat' : style
.camelize();
2544 var value
= element
.style
[style
];
2545 if (!value
&& element
.currentStyle
) value
= element
.currentStyle
[style
];
2547 if (style
== 'opacity') {
2548 if (value
= (element
.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
2549 if (value
[1]) return parseFloat(value
[1]) / 100;
2553 if (value
== 'auto') {
2554 if ((style
== 'width' || style
== 'height') && (element
.getStyle('display') != 'none'))
2555 return element
['offset' + style
.capitalize()] + 'px';
2561 Element
.Methods
.setOpacity = function(element
, value
) {
2562 function stripAlpha(filter
){
2563 return filter
.replace(/alpha\([^\)]*\)/gi,'');
2565 element
= $(element
);
2566 var currentStyle
= element
.currentStyle
;
2567 if ((currentStyle
&& !currentStyle
.hasLayout
) ||
2568 (!currentStyle
&& element
.style
.zoom
== 'normal'))
2569 element
.style
.zoom
= 1;
2571 var filter
= element
.getStyle('filter'), style
= element
.style
;
2572 if (value
== 1 || value
=== '') {
2573 (filter
= stripAlpha(filter
)) ?
2574 style
.filter
= filter
: style
.removeAttribute('filter');
2576 } else if (value
< 0.00001) value
= 0;
2577 style
.filter
= stripAlpha(filter
) +
2578 'alpha(opacity=' + (value
* 100) + ')';
2582 Element
._attributeTranslations
= (function(){
2584 var classProp
= 'className',
2586 el
= document
.createElement('div');
2588 el
.setAttribute(classProp
, 'x');
2590 if (el
.className
!== 'x') {
2591 el
.setAttribute('class', 'x');
2592 if (el
.className
=== 'x') {
2593 classProp
= 'class';
2598 el
= document
.createElement('label');
2599 el
.setAttribute(forProp
, 'x');
2600 if (el
.htmlFor
!== 'x') {
2601 el
.setAttribute('htmlFor', 'x');
2602 if (el
.htmlFor
=== 'x') {
2603 forProp
= 'htmlFor';
2612 'className': classProp
,
2617 _getAttr: function(element
, attribute
) {
2618 return element
.getAttribute(attribute
);
2620 _getAttr2: function(element
, attribute
) {
2621 return element
.getAttribute(attribute
, 2);
2623 _getAttrNode: function(element
, attribute
) {
2624 var node
= element
.getAttributeNode(attribute
);
2625 return node
? node
.value
: "";
2627 _getEv
: (function(){
2629 var el
= document
.createElement('div'), f
;
2630 el
.onclick
= Prototype
.emptyFunction
;
2631 var value
= el
.getAttribute('onclick');
2633 if (String(value
).indexOf('{') > -1) {
2634 f = function(element
, attribute
) {
2635 attribute
= element
.getAttribute(attribute
);
2636 if (!attribute
) return null;
2637 attribute
= attribute
.toString();
2638 attribute
= attribute
.split('{')[1];
2639 attribute
= attribute
.split('}')[0];
2640 return attribute
.strip();
2643 else if (value
=== '') {
2644 f = function(element
, attribute
) {
2645 attribute
= element
.getAttribute(attribute
);
2646 if (!attribute
) return null;
2647 return attribute
.strip();
2653 _flag: function(element
, attribute
) {
2654 return $(element
).hasAttribute(attribute
) ? attribute
: null;
2656 style: function(element
) {
2657 return element
.style
.cssText
.toLowerCase();
2659 title: function(element
) {
2660 return element
.title
;
2667 Element
._attributeTranslations
.write
= {
2668 names
: Object
.extend({
2669 cellpadding
: 'cellPadding',
2670 cellspacing
: 'cellSpacing'
2671 }, Element
._attributeTranslations
.read
.names
),
2673 checked: function(element
, value
) {
2674 element
.checked
= !!value
;
2677 style: function(element
, value
) {
2678 element
.style
.cssText
= value
? value
: '';
2683 Element
._attributeTranslations
.has
= {};
2685 $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2686 'encType maxLength readOnly longDesc frameBorder').each(function(attr
) {
2687 Element
._attributeTranslations
.write
.names
[attr
.toLowerCase()] = attr
;
2688 Element
._attributeTranslations
.has
[attr
.toLowerCase()] = attr
;
2696 action
: v
._getAttrNode
,
2704 ondblclick
: v
._getEv
,
2705 onmousedown
: v
._getEv
,
2706 onmouseup
: v
._getEv
,
2707 onmouseover
: v
._getEv
,
2708 onmousemove
: v
._getEv
,
2709 onmouseout
: v
._getEv
,
2712 onkeypress
: v
._getEv
,
2713 onkeydown
: v
._getEv
,
2720 })(Element
._attributeTranslations
.read
.values
);
2722 if (Prototype
.BrowserFeatures
.ElementExtensions
) {
2724 function _descendants(element
) {
2725 var nodes
= element
.getElementsByTagName('*'), results
= [];
2726 for (var i
= 0, node
; node
= nodes
[i
]; i
++)
2727 if (node
.tagName
!== "!") // Filter out comment nodes.
2732 Element
.Methods
.down = function(element
, expression
, index
) {
2733 element
= $(element
);
2734 if (arguments
.length
== 1) return element
.firstDescendant();
2735 return Object
.isNumber(expression
) ? _descendants(element
)[expression
] :
2736 Element
.select(element
, expression
)[index
|| 0];
2743 else if (Prototype
.Browser
.Gecko
&& /rv:1\.8\.0/.test(navigator
.userAgent
)) {
2744 Element
.Methods
.setOpacity = function(element
, value
) {
2745 element
= $(element
);
2746 element
.style
.opacity
= (value
== 1) ? 0.999999 :
2747 (value
=== '') ? '' : (value
< 0.00001) ? 0 : value
;
2752 else if (Prototype
.Browser
.WebKit
) {
2753 Element
.Methods
.setOpacity = function(element
, value
) {
2754 element
= $(element
);
2755 element
.style
.opacity
= (value
== 1 || value
=== '') ? '' :
2756 (value
< 0.00001) ? 0 : value
;
2759 if (element
.tagName
.toUpperCase() == 'IMG' && element
.width
) {
2760 element
.width
++; element
.width
--;
2762 var n
= document
.createTextNode(' ');
2763 element
.appendChild(n
);
2764 element
.removeChild(n
);
2771 if ('outerHTML' in document
.documentElement
) {
2772 Element
.Methods
.replace = function(element
, content
) {
2773 element
= $(element
);
2775 if (content
&& content
.toElement
) content
= content
.toElement();
2776 if (Object
.isElement(content
)) {
2777 element
.parentNode
.replaceChild(content
, element
);
2781 content
= Object
.toHTML(content
);
2782 var parent
= element
.parentNode
, tagName
= parent
.tagName
.toUpperCase();
2784 if (Element
._insertionTranslations
.tags
[tagName
]) {
2785 var nextSibling
= element
.next(),
2786 fragments
= Element
._getContentFromAnonymousElement(tagName
, content
.stripScripts());
2787 parent
.removeChild(element
);
2789 fragments
.each(function(node
) { parent
.insertBefore(node
, nextSibling
) });
2791 fragments
.each(function(node
) { parent
.appendChild(node
) });
2793 else element
.outerHTML
= content
.stripScripts();
2795 content
.evalScripts
.bind(content
).defer();
2800 Element
._returnOffset = function(l
, t
) {
2801 var result
= [l
, t
];
2807 Element
._getContentFromAnonymousElement = function(tagName
, html
, force
) {
2808 var div
= new Element('div'),
2809 t
= Element
._insertionTranslations
.tags
[tagName
];
2811 var workaround
= false;
2812 if (t
) workaround
= true;
2819 div
.innerHTML
= ' ' + t
[0] + html
+ t
[1];
2820 div
.removeChild(div
.firstChild
);
2821 for (var i
= t
[2]; i
--; ) {
2822 div
= div
.firstChild
;
2826 div
.innerHTML
= html
;
2828 return $A(div
.childNodes
);
2831 Element
._insertionTranslations
= {
2832 before: function(element
, node
) {
2833 element
.parentNode
.insertBefore(node
, element
);
2835 top: function(element
, node
) {
2836 element
.insertBefore(node
, element
.firstChild
);
2838 bottom: function(element
, node
) {
2839 element
.appendChild(node
);
2841 after: function(element
, node
) {
2842 element
.parentNode
.insertBefore(node
, element
.nextSibling
);
2845 TABLE
: ['<table>', '</table>', 1],
2846 TBODY
: ['<table><tbody>', '</tbody></table>', 2],
2847 TR
: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2848 TD
: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2849 SELECT
: ['<select>', '</select>', 1]
2854 var tags
= Element
._insertionTranslations
.tags
;
2855 Object
.extend(tags
, {
2862 Element
.Methods
.Simulated
= {
2863 hasAttribute: function(element
, attribute
) {
2864 attribute
= Element
._attributeTranslations
.has
[attribute
] || attribute
;
2865 var node
= $(element
).getAttributeNode(attribute
);
2866 return !!(node
&& node
.specified
);
2870 Element
.Methods
.ByTag
= { };
2872 Object
.extend(Element
, Element
.Methods
);
2876 if (!Prototype
.BrowserFeatures
.ElementExtensions
&& div
['__proto__']) {
2877 window
.HTMLElement
= { };
2878 window
.HTMLElement
.prototype = div
['__proto__'];
2879 Prototype
.BrowserFeatures
.ElementExtensions
= true;
2884 })(document
.createElement('div'));
2886 Element
.extend
= (function() {
2888 function checkDeficiency(tagName
) {
2889 if (typeof window
.Element
!= 'undefined') {
2890 var proto
= window
.Element
.prototype;
2892 var id
= '_' + (Math
.random()+'').slice(2),
2893 el
= document
.createElement(tagName
);
2895 var isBuggy
= (el
[id
] !== 'x');
2904 function extendElementWith(element
, methods
) {
2905 for (var property
in methods
) {
2906 var value
= methods
[property
];
2907 if (Object
.isFunction(value
) && !(property
in element
))
2908 element
[property
] = value
.methodize();
2912 var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY
= checkDeficiency('object');
2914 if (Prototype
.BrowserFeatures
.SpecificElementExtensions
) {
2915 if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY
) {
2916 return function(element
) {
2917 if (element
&& typeof element
._extendedByPrototype
== 'undefined') {
2918 var t
= element
.tagName
;
2919 if (t
&& (/^(?:object|applet|embed)$/i.test(t
))) {
2920 extendElementWith(element
, Element
.Methods
);
2921 extendElementWith(element
, Element
.Methods
.Simulated
);
2922 extendElementWith(element
, Element
.Methods
.ByTag
[t
.toUpperCase()]);
2931 var Methods
= { }, ByTag
= Element
.Methods
.ByTag
;
2933 var extend
= Object
.extend(function(element
) {
2934 if (!element
|| typeof element
._extendedByPrototype
!= 'undefined' ||
2935 element
.nodeType
!= 1 || element
== window
) return element
;
2937 var methods
= Object
.clone(Methods
),
2938 tagName
= element
.tagName
.toUpperCase();
2940 if (ByTag
[tagName
]) Object
.extend(methods
, ByTag
[tagName
]);
2942 extendElementWith(element
, methods
);
2944 element
._extendedByPrototype
= Prototype
.emptyFunction
;
2948 refresh: function() {
2949 if (!Prototype
.BrowserFeatures
.ElementExtensions
) {
2950 Object
.extend(Methods
, Element
.Methods
);
2951 Object
.extend(Methods
, Element
.Methods
.Simulated
);
2960 if (document
.documentElement
.hasAttribute
) {
2961 Element
.hasAttribute = function(element
, attribute
) {
2962 return element
.hasAttribute(attribute
);
2966 Element
.hasAttribute
= Element
.Methods
.Simulated
.hasAttribute
;
2969 Element
.addMethods = function(methods
) {
2970 var F
= Prototype
.BrowserFeatures
, T
= Element
.Methods
.ByTag
;
2973 Object
.extend(Form
, Form
.Methods
);
2974 Object
.extend(Form
.Element
, Form
.Element
.Methods
);
2975 Object
.extend(Element
.Methods
.ByTag
, {
2976 "FORM": Object
.clone(Form
.Methods
),
2977 "INPUT": Object
.clone(Form
.Element
.Methods
),
2978 "SELECT": Object
.clone(Form
.Element
.Methods
),
2979 "TEXTAREA": Object
.clone(Form
.Element
.Methods
),
2980 "BUTTON": Object
.clone(Form
.Element
.Methods
)
2984 if (arguments
.length
== 2) {
2985 var tagName
= methods
;
2986 methods
= arguments
[1];
2989 if (!tagName
) Object
.extend(Element
.Methods
, methods
|| { });
2991 if (Object
.isArray(tagName
)) tagName
.each(extend
);
2992 else extend(tagName
);
2995 function extend(tagName
) {
2996 tagName
= tagName
.toUpperCase();
2997 if (!Element
.Methods
.ByTag
[tagName
])
2998 Element
.Methods
.ByTag
[tagName
] = { };
2999 Object
.extend(Element
.Methods
.ByTag
[tagName
], methods
);
3002 function copy(methods
, destination
, onlyIfAbsent
) {
3003 onlyIfAbsent
= onlyIfAbsent
|| false;
3004 for (var property
in methods
) {
3005 var value
= methods
[property
];
3006 if (!Object
.isFunction(value
)) continue;
3007 if (!onlyIfAbsent
|| !(property
in destination
))
3008 destination
[property
] = value
.methodize();
3012 function findDOMClass(tagName
) {
3015 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3016 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3017 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3018 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3019 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3020 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3021 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3022 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3023 "FrameSet", "IFRAME": "IFrame"
3025 if (trans
[tagName
]) klass
= 'HTML' + trans
[tagName
] + 'Element';
3026 if (window
[klass
]) return window
[klass
];
3027 klass
= 'HTML' + tagName
+ 'Element';
3028 if (window
[klass
]) return window
[klass
];
3029 klass
= 'HTML' + tagName
.capitalize() + 'Element';
3030 if (window
[klass
]) return window
[klass
];
3032 var element
= document
.createElement(tagName
),
3033 proto
= element
['__proto__'] || element
.constructor.prototype;
3039 var elementPrototype
= window
.HTMLElement
? HTMLElement
.prototype :
3042 if (F
.ElementExtensions
) {
3043 copy(Element
.Methods
, elementPrototype
);
3044 copy(Element
.Methods
.Simulated
, elementPrototype
, true);
3047 if (F
.SpecificElementExtensions
) {
3048 for (var tag
in Element
.Methods
.ByTag
) {
3049 var klass
= findDOMClass(tag
);
3050 if (Object
.isUndefined(klass
)) continue;
3051 copy(T
[tag
], klass
.prototype);
3055 Object
.extend(Element
, Element
.Methods
);
3056 delete Element
.ByTag
;
3058 if (Element
.extend
.refresh
) Element
.extend
.refresh();
3059 Element
.cache
= { };
3063 document
.viewport
= {
3065 getDimensions: function() {
3066 return { width
: this.getWidth(), height
: this.getHeight() };
3069 getScrollOffsets: function() {
3070 return Element
._returnOffset(
3071 window
.pageXOffset
|| document
.documentElement
.scrollLeft
|| document
.body
.scrollLeft
,
3072 window
.pageYOffset
|| document
.documentElement
.scrollTop
|| document
.body
.scrollTop
);
3076 (function(viewport
) {
3077 var B
= Prototype
.Browser
, doc
= document
, element
, property
= {};
3079 function getRootElement() {
3080 if (B
.WebKit
&& !doc
.evaluate
)
3083 if (B
.Opera
&& window
.parseFloat(window
.opera
.version()) < 9.5)
3084 return document
.body
;
3086 return document
.documentElement
;
3089 function define(D
) {
3090 if (!element
) element
= getRootElement();
3092 property
[D
] = 'client' + D
;
3094 viewport
['get' + D
] = function() { return element
[property
[D
]] };
3095 return viewport
['get' + D
]();
3098 viewport
.getWidth
= define
.curry('Width');
3100 viewport
.getHeight
= define
.curry('Height');
3101 })(document
.viewport
);
3108 Element
.addMethods({
3109 getStorage: function(element
) {
3110 if (!(element
= $(element
))) return;
3113 if (element
=== window
) {
3116 if (typeof element
._prototypeUID
=== "undefined")
3117 element
._prototypeUID
= Element
.Storage
.UID
++;
3118 uid
= element
._prototypeUID
;
3121 if (!Element
.Storage
[uid
])
3122 Element
.Storage
[uid
] = $H();
3124 return Element
.Storage
[uid
];
3127 store: function(element
, key
, value
) {
3128 if (!(element
= $(element
))) return;
3130 if (arguments
.length
=== 2) {
3131 Element
.getStorage(element
).update(key
);
3133 Element
.getStorage(element
).set(key
, value
);
3139 retrieve: function(element
, key
, defaultValue
) {
3140 if (!(element
= $(element
))) return;
3141 var hash
= Element
.getStorage(element
), value
= hash
.get(key
);
3143 if (Object
.isUndefined(value
)) {
3144 hash
.set(key
, defaultValue
);
3145 value
= defaultValue
;
3151 clone: function(element
, deep
) {
3152 if (!(element
= $(element
))) return;
3153 var clone
= element
.cloneNode(deep
);
3154 clone
._prototypeUID
= void 0;
3156 var descendants
= Element
.select(clone
, '*'),
3157 i
= descendants
.length
;
3159 descendants
[i
]._prototypeUID
= void 0;
3162 return Element
.extend(clone
);
3165 purge: function(element
) {
3166 if (!(element
= $(element
))) return;
3167 var purgeElement
= Element
._purgeElement
;
3169 purgeElement(element
);
3171 var descendants
= element
.getElementsByTagName('*'),
3172 i
= descendants
.length
;
3174 while (i
--) purgeElement(descendants
[i
]);
3182 function toDecimal(pctString
) {
3183 var match
= pctString
.match(/^(\d+)%?$/i);
3184 if (!match
) return null;
3185 return (Number(match
[1]) / 100);
3188 function getPixelValue(value
, property
, context
) {
3190 if (Object
.isElement(value
)) {
3192 value
= element
.getStyle(property
);
3195 if (value
=== null) {
3199 if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value
)) {
3200 return window
.parseFloat(value
);
3203 var isPercentage
= value
.include('%'), isViewport
= (context
=== document
.viewport
);
3205 if (/\d/.test(value
) && element
&& element
.runtimeStyle
&& !(isPercentage
&& isViewport
)) {
3206 var style
= element
.style
.left
, rStyle
= element
.runtimeStyle
.left
;
3207 element
.runtimeStyle
.left
= element
.currentStyle
.left
;
3208 element
.style
.left
= value
|| 0;
3209 value
= element
.style
.pixelLeft
;
3210 element
.style
.left
= style
;
3211 element
.runtimeStyle
.left
= rStyle
;
3216 if (element
&& isPercentage
) {
3217 context
= context
|| element
.parentNode
;
3218 var decimal = toDecimal(value
);
3220 var position
= element
.getStyle('position');
3222 var isHorizontal
= property
.include('left') || property
.include('right') ||
3223 property
.include('width');
3225 var isVertical
= property
.include('top') || property
.include('bottom') ||
3226 property
.include('height');
3228 if (context
=== document
.viewport
) {
3230 whole
= document
.viewport
.getWidth();
3231 } else if (isVertical
) {
3232 whole
= document
.viewport
.getHeight();
3236 whole
= $(context
).measure('width');
3237 } else if (isVertical
) {
3238 whole
= $(context
).measure('height');
3242 return (whole
=== null) ? 0 : whole
* decimal;
3248 function toCSSPixels(number
) {
3249 if (Object
.isString(number
) && number
.endsWith('px')) {
3252 return number
+ 'px';
3255 function isDisplayed(element
) {
3256 var originalElement
= element
;
3257 while (element
&& element
.parentNode
) {
3258 var display
= element
.getStyle('display');
3259 if (display
=== 'none') {
3262 element
= $(element
.parentNode
);
3267 var hasLayout
= Prototype
.K
;
3268 if ('currentStyle' in document
.documentElement
) {
3269 hasLayout = function(element
) {
3270 if (!element
.currentStyle
.hasLayout
) {
3271 element
.style
.zoom
= 1;
3277 function cssNameFor(key
) {
3278 if (key
.include('border')) key
= key
+ '-width';
3279 return key
.camelize();
3282 Element
.Layout
= Class
.create(Hash
, {
3283 initialize: function($super, element
, preCompute
) {
3285 this.element
= $(element
);
3287 Element
.Layout
.PROPERTIES
.each( function(property
) {
3288 this._set(property
, null);
3292 this._preComputing
= true;
3294 Element
.Layout
.PROPERTIES
.each( this._compute
, this );
3296 this._preComputing
= false;
3300 _set: function(property
, value
) {
3301 return Hash
.prototype.set.call(this, property
, value
);
3304 set: function(property
, value
) {
3305 throw "Properties of Element.Layout are read-only.";
3308 get: function($super, property
) {
3309 var value
= $super(property
);
3310 return value
=== null ? this._compute(property
) : value
;
3313 _begin: function() {
3314 if (this._prepared
) return;
3316 var element
= this.element
;
3317 if (isDisplayed(element
)) {
3318 this._prepared
= true;
3322 var originalStyles
= {
3323 position
: element
.style
.position
|| '',
3324 width
: element
.style
.width
|| '',
3325 visibility
: element
.style
.visibility
|| '',
3326 display
: element
.style
.display
|| ''
3329 element
.store('prototype_original_styles', originalStyles
);
3331 var position
= element
.getStyle('position'),
3332 width
= element
.getStyle('width');
3334 if (width
=== "0px" || width
=== null) {
3335 element
.style
.display
= 'block';
3336 width
= element
.getStyle('width');
3339 var context
= (position
=== 'fixed') ? document
.viewport
:
3343 position
: 'absolute',
3344 visibility
: 'hidden',
3348 var positionedWidth
= element
.getStyle('width');
3351 if (width
&& (positionedWidth
=== width
)) {
3352 newWidth
= getPixelValue(element
, 'width', context
);
3353 } else if (position
=== 'absolute' || position
=== 'fixed') {
3354 newWidth
= getPixelValue(element
, 'width', context
);
3356 var parent
= element
.parentNode
, pLayout
= $(parent
).getLayout();
3358 newWidth
= pLayout
.get('width') -
3359 this.get('margin-left') -
3360 this.get('border-left') -
3361 this.get('padding-left') -
3362 this.get('padding-right') -
3363 this.get('border-right') -
3364 this.get('margin-right');
3367 element
.setStyle({ width
: newWidth
+ 'px' });
3369 this._prepared
= true;
3373 var element
= this.element
;
3374 var originalStyles
= element
.retrieve('prototype_original_styles');
3375 element
.store('prototype_original_styles', null);
3376 element
.setStyle(originalStyles
);
3377 this._prepared
= false;
3380 _compute: function(property
) {
3381 var COMPUTATIONS
= Element
.Layout
.COMPUTATIONS
;
3382 if (!(property
in COMPUTATIONS
)) {
3383 throw "Property not found.";
3386 return this._set(property
, COMPUTATIONS
[property
].call(this, this.element
));
3389 toObject: function() {
3390 var args
= $A(arguments
);
3391 var keys
= (args
.length
=== 0) ? Element
.Layout
.PROPERTIES
:
3392 args
.join(' ').split(' ');
3394 keys
.each( function(key
) {
3395 if (!Element
.Layout
.PROPERTIES
.include(key
)) return;
3396 var value
= this.get(key
);
3397 if (value
!= null) obj
[key
] = value
;
3402 toHash: function() {
3403 var obj
= this.toObject
.apply(this, arguments
);
3404 return new Hash(obj
);
3408 var args
= $A(arguments
);
3409 var keys
= (args
.length
=== 0) ? Element
.Layout
.PROPERTIES
:
3410 args
.join(' ').split(' ');
3413 keys
.each( function(key
) {
3414 if (!Element
.Layout
.PROPERTIES
.include(key
)) return;
3415 if (Element
.Layout
.COMPOSITE_PROPERTIES
.include(key
)) return;
3417 var value
= this.get(key
);
3418 if (value
!= null) css
[cssNameFor(key
)] = value
+ 'px';
3423 inspect: function() {
3424 return "#<Element.Layout>";
3428 Object
.extend(Element
.Layout
, {
3429 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'),
3431 COMPOSITE_PROPERTIES
: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3434 'height': function(element
) {
3435 if (!this._preComputing
) this._begin();
3437 var bHeight
= this.get('border-box-height');
3439 if (!this._preComputing
) this._end();
3443 var bTop
= this.get('border-top'),
3444 bBottom
= this.get('border-bottom');
3446 var pTop
= this.get('padding-top'),
3447 pBottom
= this.get('padding-bottom');
3449 if (!this._preComputing
) this._end();
3451 return bHeight
- bTop
- bBottom
- pTop
- pBottom
;
3454 'width': function(element
) {
3455 if (!this._preComputing
) this._begin();
3457 var bWidth
= this.get('border-box-width');
3459 if (!this._preComputing
) this._end();
3463 var bLeft
= this.get('border-left'),
3464 bRight
= this.get('border-right');
3466 var pLeft
= this.get('padding-left'),
3467 pRight
= this.get('padding-right');
3469 if (!this._preComputing
) this._end();
3471 return bWidth
- bLeft
- bRight
- pLeft
- pRight
;
3474 'padding-box-height': function(element
) {
3475 var height
= this.get('height'),
3476 pTop
= this.get('padding-top'),
3477 pBottom
= this.get('padding-bottom');
3479 return height
+ pTop
+ pBottom
;
3482 'padding-box-width': function(element
) {
3483 var width
= this.get('width'),
3484 pLeft
= this.get('padding-left'),
3485 pRight
= this.get('padding-right');
3487 return width
+ pLeft
+ pRight
;
3490 'border-box-height': function(element
) {
3491 if (!this._preComputing
) this._begin();
3492 var height
= element
.offsetHeight
;
3493 if (!this._preComputing
) this._end();
3497 'border-box-width': function(element
) {
3498 if (!this._preComputing
) this._begin();
3499 var width
= element
.offsetWidth
;
3500 if (!this._preComputing
) this._end();
3504 'margin-box-height': function(element
) {
3505 var bHeight
= this.get('border-box-height'),
3506 mTop
= this.get('margin-top'),
3507 mBottom
= this.get('margin-bottom');
3509 if (bHeight
<= 0) return 0;
3511 return bHeight
+ mTop
+ mBottom
;
3514 'margin-box-width': function(element
) {
3515 var bWidth
= this.get('border-box-width'),
3516 mLeft
= this.get('margin-left'),
3517 mRight
= this.get('margin-right');
3519 if (bWidth
<= 0) return 0;
3521 return bWidth
+ mLeft
+ mRight
;
3524 'top': function(element
) {
3525 var offset
= element
.positionedOffset();
3529 'bottom': function(element
) {
3530 var offset
= element
.positionedOffset(),
3531 parent
= element
.getOffsetParent(),
3532 pHeight
= parent
.measure('height');
3534 var mHeight
= this.get('border-box-height');
3536 return pHeight
- mHeight
- offset
.top
;
3539 'left': function(element
) {
3540 var offset
= element
.positionedOffset();
3544 'right': function(element
) {
3545 var offset
= element
.positionedOffset(),
3546 parent
= element
.getOffsetParent(),
3547 pWidth
= parent
.measure('width');
3549 var mWidth
= this.get('border-box-width');
3551 return pWidth
- mWidth
- offset
.left
;
3554 'padding-top': function(element
) {
3555 return getPixelValue(element
, 'paddingTop');
3558 'padding-bottom': function(element
) {
3559 return getPixelValue(element
, 'paddingBottom');
3562 'padding-left': function(element
) {
3563 return getPixelValue(element
, 'paddingLeft');
3566 'padding-right': function(element
) {
3567 return getPixelValue(element
, 'paddingRight');
3570 'border-top': function(element
) {
3571 return getPixelValue(element
, 'borderTopWidth');
3574 'border-bottom': function(element
) {
3575 return getPixelValue(element
, 'borderBottomWidth');
3578 'border-left': function(element
) {
3579 return getPixelValue(element
, 'borderLeftWidth');
3582 'border-right': function(element
) {
3583 return getPixelValue(element
, 'borderRightWidth');
3586 'margin-top': function(element
) {
3587 return getPixelValue(element
, 'marginTop');
3590 'margin-bottom': function(element
) {
3591 return getPixelValue(element
, 'marginBottom');
3594 'margin-left': function(element
) {
3595 return getPixelValue(element
, 'marginLeft');
3598 'margin-right': function(element
) {
3599 return getPixelValue(element
, 'marginRight');
3604 if ('getBoundingClientRect' in document
.documentElement
) {
3605 Object
.extend(Element
.Layout
.COMPUTATIONS
, {
3606 'right': function(element
) {
3607 var parent
= hasLayout(element
.getOffsetParent());
3608 var rect
= element
.getBoundingClientRect(),
3609 pRect
= parent
.getBoundingClientRect();
3611 return (pRect
.right
- rect
.right
).round();
3614 'bottom': function(element
) {
3615 var parent
= hasLayout(element
.getOffsetParent());
3616 var rect
= element
.getBoundingClientRect(),
3617 pRect
= parent
.getBoundingClientRect();
3619 return (pRect
.bottom
- rect
.bottom
).round();
3624 Element
.Offset
= Class
.create({
3625 initialize: function(left
, top
) {
3626 this.left
= left
.round();
3627 this.top
= top
.round();
3629 this[0] = this.left
;
3633 relativeTo: function(offset
) {
3634 return new Element
.Offset(
3635 this.left
- offset
.left
,
3636 this.top
- offset
.top
3640 inspect: function() {
3641 return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3644 toString: function() {
3645 return "[#{left}, #{top}]".interpolate(this);
3648 toArray: function() {
3649 return [this.left
, this.top
];
3653 function getLayout(element
, preCompute
) {
3654 return new Element
.Layout(element
, preCompute
);
3657 function measure(element
, property
) {
3658 return $(element
).getLayout().get(property
);
3661 function getDimensions(element
) {
3662 element
= $(element
);
3663 var display
= Element
.getStyle(element
, 'display');
3665 if (display
&& display
!== 'none') {
3666 return { width
: element
.offsetWidth
, height
: element
.offsetHeight
};
3669 var style
= element
.style
;
3670 var originalStyles
= {
3671 visibility
: style
.visibility
,
3672 position
: style
.position
,
3673 display
: style
.display
3677 visibility
: 'hidden',
3681 if (originalStyles
.position
!== 'fixed')
3682 newStyles
.position
= 'absolute';
3684 Element
.setStyle(element
, newStyles
);
3687 width
: element
.offsetWidth
,
3688 height
: element
.offsetHeight
3691 Element
.setStyle(element
, originalStyles
);
3696 function getOffsetParent(element
) {
3697 element
= $(element
);
3699 if (isDocument(element
) || isDetached(element
) || isBody(element
) || isHtml(element
))
3700 return $(document
.body
);
3702 var isInline
= (Element
.getStyle(element
, 'display') === 'inline');
3703 if (!isInline
&& element
.offsetParent
) return $(element
.offsetParent
);
3705 while ((element
= element
.parentNode
) && element
!== document
.body
) {
3706 if (Element
.getStyle(element
, 'position') !== 'static') {
3707 return isHtml(element
) ? $(document
.body
) : $(element
);
3711 return $(document
.body
);
3715 function cumulativeOffset(element
) {
3716 element
= $(element
);
3717 var valueT
= 0, valueL
= 0;
3718 if (element
.parentNode
) {
3720 valueT
+= element
.offsetTop
|| 0;
3721 valueL
+= element
.offsetLeft
|| 0;
3722 element
= element
.offsetParent
;
3725 return new Element
.Offset(valueL
, valueT
);
3728 function positionedOffset(element
) {
3729 element
= $(element
);
3731 var layout
= element
.getLayout();
3733 var valueT
= 0, valueL
= 0;
3735 valueT
+= element
.offsetTop
|| 0;
3736 valueL
+= element
.offsetLeft
|| 0;
3737 element
= element
.offsetParent
;
3739 if (isBody(element
)) break;
3740 var p
= Element
.getStyle(element
, 'position');
3741 if (p
!== 'static') break;
3745 valueL
-= layout
.get('margin-top');
3746 valueT
-= layout
.get('margin-left');
3748 return new Element
.Offset(valueL
, valueT
);
3751 function cumulativeScrollOffset(element
) {
3752 var valueT
= 0, valueL
= 0;
3754 valueT
+= element
.scrollTop
|| 0;
3755 valueL
+= element
.scrollLeft
|| 0;
3756 element
= element
.parentNode
;
3758 return new Element
.Offset(valueL
, valueT
);
3761 function viewportOffset(forElement
) {
3762 element
= $(element
);
3763 var valueT
= 0, valueL
= 0, docBody
= document
.body
;
3765 var element
= forElement
;
3767 valueT
+= element
.offsetTop
|| 0;
3768 valueL
+= element
.offsetLeft
|| 0;
3769 if (element
.offsetParent
== docBody
&&
3770 Element
.getStyle(element
, 'position') == 'absolute') break;
3771 } while (element
= element
.offsetParent
);
3773 element
= forElement
;
3775 if (element
!= docBody
) {
3776 valueT
-= element
.scrollTop
|| 0;
3777 valueL
-= element
.scrollLeft
|| 0;
3779 } while (element
= element
.parentNode
);
3780 return new Element
.Offset(valueL
, valueT
);
3783 function absolutize(element
) {
3784 element
= $(element
);
3786 if (Element
.getStyle(element
, 'position') === 'absolute') {
3790 var offsetParent
= getOffsetParent(element
);
3791 var eOffset
= element
.viewportOffset(),
3792 pOffset
= offsetParent
.viewportOffset();
3794 var offset
= eOffset
.relativeTo(pOffset
);
3795 var layout
= element
.getLayout();
3797 element
.store('prototype_absolutize_original_styles', {
3798 left
: element
.getStyle('left'),
3799 top
: element
.getStyle('top'),
3800 width
: element
.getStyle('width'),
3801 height
: element
.getStyle('height')
3805 position
: 'absolute',
3806 top
: offset
.top
+ 'px',
3807 left
: offset
.left
+ 'px',
3808 width
: layout
.get('width') + 'px',
3809 height
: layout
.get('height') + 'px'
3815 function relativize(element
) {
3816 element
= $(element
);
3817 if (Element
.getStyle(element
, 'position') === 'relative') {
3821 var originalStyles
=
3822 element
.retrieve('prototype_absolutize_original_styles');
3824 if (originalStyles
) element
.setStyle(originalStyles
);
3828 if (Prototype
.Browser
.IE
) {
3829 getOffsetParent
= getOffsetParent
.wrap(
3830 function(proceed
, element
) {
3831 element
= $(element
);
3833 if (isDocument(element
) || isDetached(element
) || isBody(element
) || isHtml(element
))
3834 return $(document
.body
);
3836 var position
= element
.getStyle('position');
3837 if (position
!== 'static') return proceed(element
);
3839 element
.setStyle({ position
: 'relative' });
3840 var value
= proceed(element
);
3841 element
.setStyle({ position
: position
});
3846 positionedOffset
= positionedOffset
.wrap(function(proceed
, element
) {
3847 element
= $(element
);
3848 if (!element
.parentNode
) return new Element
.Offset(0, 0);
3849 var position
= element
.getStyle('position');
3850 if (position
!== 'static') return proceed(element
);
3852 var offsetParent
= element
.getOffsetParent();
3853 if (offsetParent
&& offsetParent
.getStyle('position') === 'fixed')
3854 hasLayout(offsetParent
);
3856 element
.setStyle({ position
: 'relative' });
3857 var value
= proceed(element
);
3858 element
.setStyle({ position
: position
});
3861 } else if (Prototype
.Browser
.Webkit
) {
3862 cumulativeOffset = function(element
) {
3863 element
= $(element
);
3864 var valueT
= 0, valueL
= 0;
3866 valueT
+= element
.offsetTop
|| 0;
3867 valueL
+= element
.offsetLeft
|| 0;
3868 if (element
.offsetParent
== document
.body
)
3869 if (Element
.getStyle(element
, 'position') == 'absolute') break;
3871 element
= element
.offsetParent
;
3874 return new Element
.Offset(valueL
, valueT
);
3879 Element
.addMethods({
3880 getLayout
: getLayout
,
3882 getDimensions
: getDimensions
,
3883 getOffsetParent
: getOffsetParent
,
3884 cumulativeOffset
: cumulativeOffset
,
3885 positionedOffset
: positionedOffset
,
3886 cumulativeScrollOffset
: cumulativeScrollOffset
,
3887 viewportOffset
: viewportOffset
,
3888 absolutize
: absolutize
,
3889 relativize
: relativize
3892 function isBody(element
) {
3893 return element
.nodeName
.toUpperCase() === 'BODY';
3896 function isHtml(element
) {
3897 return element
.nodeName
.toUpperCase() === 'HTML';
3900 function isDocument(element
) {
3901 return element
.nodeType
=== Node
.DOCUMENT_NODE
;
3904 function isDetached(element
) {
3905 return element
!== document
.body
&&
3906 !Element
.descendantOf(element
, document
.body
);
3909 if ('getBoundingClientRect' in document
.documentElement
) {
3910 Element
.addMethods({
3911 viewportOffset: function(element
) {
3912 element
= $(element
);
3913 if (isDetached(element
)) return new Element
.Offset(0, 0);
3915 var rect
= element
.getBoundingClientRect(),
3916 docEl
= document
.documentElement
;
3917 return new Element
.Offset(rect
.left
- docEl
.clientLeft
,
3918 rect
.top
- docEl
.clientTop
);
3923 window
.$$ = function() {
3924 var expression
= $A(arguments
).join(', ');
3925 return Prototype
.Selector
.select(expression
, document
);
3928 Prototype
.Selector
= (function() {
3931 throw new Error('Method "Prototype.Selector.select" must be defined.');
3935 throw new Error('Method "Prototype.Selector.match" must be defined.');
3938 function find(elements
, expression
, index
) {
3940 var match
= Prototype
.Selector
.match
, length
= elements
.length
, matchIndex
= 0, i
;
3942 for (i
= 0; i
< length
; i
++) {
3943 if (match(elements
[i
], expression
) && index
== matchIndex
++) {
3944 return Element
.extend(elements
[i
]);
3949 function extendElements(elements
) {
3950 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
3951 Element
.extend(elements
[i
]);
3957 var K
= Prototype
.K
;
3963 extendElements
: (Element
.extend
=== K
) ? K
: extendElements
,
3964 extendElement
: Element
.extend
3967 Prototype
._original_property
= window
.Sizzle
;
3969 * Sizzle CSS Selector Engine - v1.0
3970 * Copyright 2009, The Dojo Foundation
3971 * Released under the MIT, BSD, and GPL Licenses.
3972 * More information: http://sizzlejs.com/
3976 var chunker
= /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
3978 toString
= Object
.prototype.toString
,
3979 hasDuplicate
= false,
3980 baseHasDuplicate
= true;
3982 [0, 0].sort(function(){
3983 baseHasDuplicate
= false;
3987 var Sizzle = function(selector
, context
, results
, seed
) {
3988 results
= results
|| [];
3989 var origContext
= context
= context
|| document
;
3991 if ( context
.nodeType
!== 1 && context
.nodeType
!== 9 ) {
3995 if ( !selector
|| typeof selector
!== "string" ) {
3999 var parts
= [], m
, set, checkSet
, check
, mode
, extra
, prune
= true, contextXML
= isXML(context
),
4002 while ( (chunker
.exec(""), m
= chunker
.exec(soFar
)) !== null ) {
4013 if ( parts
.length
> 1 && origPOS
.exec( selector
) ) {
4014 if ( parts
.length
=== 2 && Expr
.relative
[ parts
[0] ] ) {
4015 set = posProcess( parts
[0] + parts
[1], context
);
4017 set = Expr
.relative
[ parts
[0] ] ?
4019 Sizzle( parts
.shift(), context
);
4021 while ( parts
.length
) {
4022 selector
= parts
.shift();
4024 if ( Expr
.relative
[ selector
] )
4025 selector
+= parts
.shift();
4027 set = posProcess( selector
, set );
4031 if ( !seed
&& parts
.length
> 1 && context
.nodeType
=== 9 && !contextXML
&&
4032 Expr
.match
.ID
.test(parts
[0]) && !Expr
.match
.ID
.test(parts
[parts
.length
- 1]) ) {
4033 var ret
= Sizzle
.find( parts
.shift(), context
, contextXML
);
4034 context
= ret
.expr
? Sizzle
.filter( ret
.expr
, ret
.set )[0] : ret
.set[0];
4039 { expr
: parts
.pop(), set: makeArray(seed
) } :
4040 Sizzle
.find( parts
.pop(), parts
.length
=== 1 && (parts
[0] === "~" || parts
[0] === "+") && context
.parentNode
? context
.parentNode
: context
, contextXML
);
4041 set = ret
.expr
? Sizzle
.filter( ret
.expr
, ret
.set ) : ret
.set;
4043 if ( parts
.length
> 0 ) {
4044 checkSet
= makeArray(set);
4049 while ( parts
.length
) {
4050 var cur
= parts
.pop(), pop
= cur
;
4052 if ( !Expr
.relative
[ cur
] ) {
4058 if ( pop
== null ) {
4062 Expr
.relative
[ cur
]( checkSet
, pop
, contextXML
);
4065 checkSet
= parts
= [];
4074 throw "Syntax error, unrecognized expression: " + (cur
|| selector
);
4077 if ( toString
.call(checkSet
) === "[object Array]" ) {
4079 results
.push
.apply( results
, checkSet
);
4080 } else if ( context
&& context
.nodeType
=== 1 ) {
4081 for ( var i
= 0; checkSet
[i
] != null; i
++ ) {
4082 if ( checkSet
[i
] && (checkSet
[i
] === true || checkSet
[i
].nodeType
=== 1 && contains(context
, checkSet
[i
])) ) {
4083 results
.push( set[i
] );
4087 for ( var i
= 0; checkSet
[i
] != null; i
++ ) {
4088 if ( checkSet
[i
] && checkSet
[i
].nodeType
=== 1 ) {
4089 results
.push( set[i
] );
4094 makeArray( checkSet
, results
);
4098 Sizzle( extra
, origContext
, results
, seed
);
4099 Sizzle
.uniqueSort( results
);
4105 Sizzle
.uniqueSort = function(results
){
4107 hasDuplicate
= baseHasDuplicate
;
4108 results
.sort(sortOrder
);
4110 if ( hasDuplicate
) {
4111 for ( var i
= 1; i
< results
.length
; i
++ ) {
4112 if ( results
[i
] === results
[i
-1] ) {
4113 results
.splice(i
--, 1);
4122 Sizzle
.matches = function(expr
, set){
4123 return Sizzle(expr
, null, null, set);
4126 Sizzle
.find = function(expr
, context
, isXML
){
4133 for ( var i
= 0, l
= Expr
.order
.length
; i
< l
; i
++ ) {
4134 var type
= Expr
.order
[i
], match
;
4136 if ( (match
= Expr
.leftMatch
[ type
].exec( expr
)) ) {
4137 var left
= match
[1];
4140 if ( left
.substr( left
.length
- 1 ) !== "\\" ) {
4141 match
[1] = (match
[1] || "").replace(/\\/g
, "");
4142 set = Expr
.find
[ type
]( match
, context
, isXML
);
4143 if ( set != null ) {
4144 expr
= expr
.replace( Expr
.match
[ type
], "" );
4152 set = context
.getElementsByTagName("*");
4155 return {set: set, expr
: expr
};
4158 Sizzle
.filter = function(expr
, set, inplace
, not
){
4159 var old
= expr
, result
= [], curLoop
= set, match
, anyFound
,
4160 isXMLFilter
= set && set[0] && isXML(set[0]);
4162 while ( expr
&& set.length
) {
4163 for ( var type
in Expr
.filter
) {
4164 if ( (match
= Expr
.match
[ type
].exec( expr
)) != null ) {
4165 var filter
= Expr
.filter
[ type
], found
, item
;
4168 if ( curLoop
== result
) {
4172 if ( Expr
.preFilter
[ type
] ) {
4173 match
= Expr
.preFilter
[ type
]( match
, curLoop
, inplace
, result
, not
, isXMLFilter
);
4176 anyFound
= found
= true;
4177 } else if ( match
=== true ) {
4183 for ( var i
= 0; (item
= curLoop
[i
]) != null; i
++ ) {
4185 found
= filter( item
, match
, i
, curLoop
);
4186 var pass
= not
^ !!found
;
4188 if ( inplace
&& found
!= null ) {
4194 } else if ( pass
) {
4195 result
.push( item
);
4202 if ( found
!== undefined ) {
4207 expr
= expr
.replace( Expr
.match
[ type
], "" );
4218 if ( expr
== old
) {
4219 if ( anyFound
== null ) {
4220 throw "Syntax error, unrecognized expression: " + expr
;
4232 var Expr
= Sizzle
.selectors
= {
4233 order
: [ "ID", "NAME", "TAG" ],
4235 ID
: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
4236 CLASS
: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
4237 NAME
: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
4238 ATTR
: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
4239 TAG
: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
4240 CHILD
: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
4241 POS
: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
4242 PSEUDO
: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
4246 "class": "className",
4250 href: function(elem
){
4251 return elem
.getAttribute("href");
4255 "+": function(checkSet
, part
, isXML
){
4256 var isPartStr
= typeof part
=== "string",
4257 isTag
= isPartStr
&& !/\W/.test(part
),
4258 isPartStrNotTag
= isPartStr
&& !isTag
;
4260 if ( isTag
&& !isXML
) {
4261 part
= part
.toUpperCase();
4264 for ( var i
= 0, l
= checkSet
.length
, elem
; i
< l
; i
++ ) {
4265 if ( (elem
= checkSet
[i
]) ) {
4266 while ( (elem
= elem
.previousSibling
) && elem
.nodeType
!== 1 ) {}
4268 checkSet
[i
] = isPartStrNotTag
|| elem
&& elem
.nodeName
=== part
?
4274 if ( isPartStrNotTag
) {
4275 Sizzle
.filter( part
, checkSet
, true );
4278 ">": function(checkSet
, part
, isXML
){
4279 var isPartStr
= typeof part
=== "string";
4281 if ( isPartStr
&& !/\W/.test(part
) ) {
4282 part
= isXML
? part
: part
.toUpperCase();
4284 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
4285 var elem
= checkSet
[i
];
4287 var parent
= elem
.parentNode
;
4288 checkSet
[i
] = parent
.nodeName
=== part
? parent
: false;
4292 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
4293 var elem
= checkSet
[i
];
4295 checkSet
[i
] = isPartStr
?
4297 elem
.parentNode
=== part
;
4302 Sizzle
.filter( part
, checkSet
, true );
4306 "": function(checkSet
, part
, isXML
){
4307 var doneName
= done
++, checkFn
= dirCheck
;
4309 if ( !/\W/.test(part
) ) {
4310 var nodeCheck
= part
= isXML
? part
: part
.toUpperCase();
4311 checkFn
= dirNodeCheck
;
4314 checkFn("parentNode", part
, doneName
, checkSet
, nodeCheck
, isXML
);
4316 "~": function(checkSet
, part
, isXML
){
4317 var doneName
= done
++, checkFn
= dirCheck
;
4319 if ( typeof part
=== "string" && !/\W/.test(part
) ) {
4320 var nodeCheck
= part
= isXML
? part
: part
.toUpperCase();
4321 checkFn
= dirNodeCheck
;
4324 checkFn("previousSibling", part
, doneName
, checkSet
, nodeCheck
, isXML
);
4328 ID: function(match
, context
, isXML
){
4329 if ( typeof context
.getElementById
!== "undefined" && !isXML
) {
4330 var m
= context
.getElementById(match
[1]);
4331 return m
? [m
] : [];
4334 NAME: function(match
, context
, isXML
){
4335 if ( typeof context
.getElementsByName
!== "undefined" ) {
4336 var ret
= [], results
= context
.getElementsByName(match
[1]);
4338 for ( var i
= 0, l
= results
.length
; i
< l
; i
++ ) {
4339 if ( results
[i
].getAttribute("name") === match
[1] ) {
4340 ret
.push( results
[i
] );
4344 return ret
.length
=== 0 ? null : ret
;
4347 TAG: function(match
, context
){
4348 return context
.getElementsByTagName(match
[1]);
4352 CLASS: function(match
, curLoop
, inplace
, result
, not
, isXML
){
4353 match
= " " + match
[1].replace(/\\/g
, "") + " ";
4359 for ( var i
= 0, elem
; (elem
= curLoop
[i
]) != null; i
++ ) {
4361 if ( not
^ (elem
.className
&& (" " + elem
.className
+ " ").indexOf(match
) >= 0) ) {
4363 result
.push( elem
);
4364 } else if ( inplace
) {
4372 ID: function(match
){
4373 return match
[1].replace(/\\/g
, "");
4375 TAG: function(match
, curLoop
){
4376 for ( var i
= 0; curLoop
[i
] === false; i
++ ){}
4377 return curLoop
[i
] && isXML(curLoop
[i
]) ? match
[1] : match
[1].toUpperCase();
4379 CHILD: function(match
){
4380 if ( match
[1] == "nth" ) {
4381 var test
= /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
4382 match
[2] == "even" && "2n" || match
[2] == "odd" && "2n+1" ||
4383 !/\D/.test( match
[2] ) && "0n+" + match
[2] || match
[2]);
4385 match
[2] = (test
[1] + (test
[2] || 1)) - 0;
4386 match
[3] = test
[3] - 0;
4393 ATTR: function(match
, curLoop
, inplace
, result
, not
, isXML
){
4394 var name
= match
[1].replace(/\\/g
, "");
4396 if ( !isXML
&& Expr
.attrMap
[name
] ) {
4397 match
[1] = Expr
.attrMap
[name
];
4400 if ( match
[2] === "~=" ) {
4401 match
[4] = " " + match
[4] + " ";
4406 PSEUDO: function(match
, curLoop
, inplace
, result
, not
){
4407 if ( match
[1] === "not" ) {
4408 if ( ( chunker
.exec(match
[3]) || "" ).length
> 1 || /^\w/.test(match
[3]) ) {
4409 match
[3] = Sizzle(match
[3], null, null, curLoop
);
4411 var ret
= Sizzle
.filter(match
[3], curLoop
, inplace
, true ^ not
);
4413 result
.push
.apply( result
, ret
);
4417 } else if ( Expr
.match
.POS
.test( match
[0] ) || Expr
.match
.CHILD
.test( match
[0] ) ) {
4423 POS: function(match
){
4424 match
.unshift( true );
4429 enabled: function(elem
){
4430 return elem
.disabled
=== false && elem
.type
!== "hidden";
4432 disabled: function(elem
){
4433 return elem
.disabled
=== true;
4435 checked: function(elem
){
4436 return elem
.checked
=== true;
4438 selected: function(elem
){
4439 elem
.parentNode
.selectedIndex
;
4440 return elem
.selected
=== true;
4442 parent: function(elem
){
4443 return !!elem
.firstChild
;
4445 empty: function(elem
){
4446 return !elem
.firstChild
;
4448 has: function(elem
, i
, match
){
4449 return !!Sizzle( match
[3], elem
).length
;
4451 header: function(elem
){
4452 return /h\d/i.test( elem
.nodeName
);
4454 text: function(elem
){
4455 return "text" === elem
.type
;
4457 radio: function(elem
){
4458 return "radio" === elem
.type
;
4460 checkbox: function(elem
){
4461 return "checkbox" === elem
.type
;
4463 file: function(elem
){
4464 return "file" === elem
.type
;
4466 password: function(elem
){
4467 return "password" === elem
.type
;
4469 submit: function(elem
){
4470 return "submit" === elem
.type
;
4472 image: function(elem
){
4473 return "image" === elem
.type
;
4475 reset: function(elem
){
4476 return "reset" === elem
.type
;
4478 button: function(elem
){
4479 return "button" === elem
.type
|| elem
.nodeName
.toUpperCase() === "BUTTON";
4481 input: function(elem
){
4482 return /input|select|textarea|button/i.test(elem
.nodeName
);
4486 first: function(elem
, i
){
4489 last: function(elem
, i
, match
, array
){
4490 return i
=== array
.length
- 1;
4492 even: function(elem
, i
){
4495 odd: function(elem
, i
){
4498 lt: function(elem
, i
, match
){
4499 return i
< match
[3] - 0;
4501 gt: function(elem
, i
, match
){
4502 return i
> match
[3] - 0;
4504 nth: function(elem
, i
, match
){
4505 return match
[3] - 0 == i
;
4507 eq: function(elem
, i
, match
){
4508 return match
[3] - 0 == i
;
4512 PSEUDO: function(elem
, match
, i
, array
){
4513 var name
= match
[1], filter
= Expr
.filters
[ name
];
4516 return filter( elem
, i
, match
, array
);
4517 } else if ( name
=== "contains" ) {
4518 return (elem
.textContent
|| elem
.innerText
|| "").indexOf(match
[3]) >= 0;
4519 } else if ( name
=== "not" ) {
4522 for ( var i
= 0, l
= not
.length
; i
< l
; i
++ ) {
4523 if ( not
[i
] === elem
) {
4531 CHILD: function(elem
, match
){
4532 var type
= match
[1], node
= elem
;
4536 while ( (node
= node
.previousSibling
) ) {
4537 if ( node
.nodeType
=== 1 ) return false;
4539 if ( type
== 'first') return true;
4542 while ( (node
= node
.nextSibling
) ) {
4543 if ( node
.nodeType
=== 1 ) return false;
4547 var first
= match
[2], last
= match
[3];
4549 if ( first
== 1 && last
== 0 ) {
4553 var doneName
= match
[0],
4554 parent
= elem
.parentNode
;
4556 if ( parent
&& (parent
.sizcache
!== doneName
|| !elem
.nodeIndex
) ) {
4558 for ( node
= parent
.firstChild
; node
; node
= node
.nextSibling
) {
4559 if ( node
.nodeType
=== 1 ) {
4560 node
.nodeIndex
= ++count
;
4563 parent
.sizcache
= doneName
;
4566 var diff
= elem
.nodeIndex
- last
;
4570 return ( diff
% first
== 0 && diff
/ first
>= 0 );
4574 ID: function(elem
, match
){
4575 return elem
.nodeType
=== 1 && elem
.getAttribute("id") === match
;
4577 TAG: function(elem
, match
){
4578 return (match
=== "*" && elem
.nodeType
=== 1) || elem
.nodeName
=== match
;
4580 CLASS: function(elem
, match
){
4581 return (" " + (elem
.className
|| elem
.getAttribute("class")) + " ")
4582 .indexOf( match
) > -1;
4584 ATTR: function(elem
, match
){
4585 var name
= match
[1],
4586 result
= Expr
.attrHandle
[ name
] ?
4587 Expr
.attrHandle
[ name
]( elem
) :
4588 elem
[ name
] != null ?
4590 elem
.getAttribute( name
),
4591 value
= result
+ "",
4595 return result
== null ?
4600 value
.indexOf(check
) >= 0 :
4602 (" " + value
+ " ").indexOf(check
) >= 0 :
4604 value
&& result
!== false :
4608 value
.indexOf(check
) === 0 :
4610 value
.substr(value
.length
- check
.length
) === check
:
4612 value
=== check
|| value
.substr(0, check
.length
+ 1) === check
+ "-" :
4615 POS: function(elem
, match
, i
, array
){
4616 var name
= match
[2], filter
= Expr
.setFilters
[ name
];
4619 return filter( elem
, i
, match
, array
);
4625 var origPOS
= Expr
.match
.POS
;
4627 for ( var type
in Expr
.match
) {
4628 Expr
.match
[ type
] = new RegExp( Expr
.match
[ type
].source
+ /(?![^\[]*\])(?![^\(]*\))/.source
);
4629 Expr
.leftMatch
[ type
] = new RegExp( /(^(?:.|\r|\n)*?)/.source
+ Expr
.match
[ type
].source
);
4632 var makeArray = function(array
, results
) {
4633 array
= Array
.prototype.slice
.call( array
, 0 );
4636 results
.push
.apply( results
, array
);
4644 Array
.prototype.slice
.call( document
.documentElement
.childNodes
, 0 );
4647 makeArray = function(array
, results
) {
4648 var ret
= results
|| [];
4650 if ( toString
.call(array
) === "[object Array]" ) {
4651 Array
.prototype.push
.apply( ret
, array
);
4653 if ( typeof array
.length
=== "number" ) {
4654 for ( var i
= 0, l
= array
.length
; i
< l
; i
++ ) {
4655 ret
.push( array
[i
] );
4658 for ( var i
= 0; array
[i
]; i
++ ) {
4659 ret
.push( array
[i
] );
4670 if ( document
.documentElement
.compareDocumentPosition
) {
4671 sortOrder = function( a
, b
) {
4672 if ( !a
.compareDocumentPosition
|| !b
.compareDocumentPosition
) {
4674 hasDuplicate
= true;
4679 var ret
= a
.compareDocumentPosition(b
) & 4 ? -1 : a
=== b
? 0 : 1;
4681 hasDuplicate
= true;
4685 } else if ( "sourceIndex" in document
.documentElement
) {
4686 sortOrder = function( a
, b
) {
4687 if ( !a
.sourceIndex
|| !b
.sourceIndex
) {
4689 hasDuplicate
= true;
4694 var ret
= a
.sourceIndex
- b
.sourceIndex
;
4696 hasDuplicate
= true;
4700 } else if ( document
.createRange
) {
4701 sortOrder = function( a
, b
) {
4702 if ( !a
.ownerDocument
|| !b
.ownerDocument
) {
4704 hasDuplicate
= true;
4709 var aRange
= a
.ownerDocument
.createRange(), bRange
= b
.ownerDocument
.createRange();
4710 aRange
.setStart(a
, 0);
4711 aRange
.setEnd(a
, 0);
4712 bRange
.setStart(b
, 0);
4713 bRange
.setEnd(b
, 0);
4714 var ret
= aRange
.compareBoundaryPoints(Range
.START_TO_END
, bRange
);
4716 hasDuplicate
= true;
4723 var form
= document
.createElement("div"),
4724 id
= "script" + (new Date
).getTime();
4725 form
.innerHTML
= "<a name='" + id
+ "'/>";
4727 var root
= document
.documentElement
;
4728 root
.insertBefore( form
, root
.firstChild
);
4730 if ( !!document
.getElementById( id
) ) {
4731 Expr
.find
.ID = function(match
, context
, isXML
){
4732 if ( typeof context
.getElementById
!== "undefined" && !isXML
) {
4733 var m
= context
.getElementById(match
[1]);
4734 return m
? m
.id
=== match
[1] || typeof m
.getAttributeNode
!== "undefined" && m
.getAttributeNode("id").nodeValue
=== match
[1] ? [m
] : undefined : [];
4738 Expr
.filter
.ID = function(elem
, match
){
4739 var node
= typeof elem
.getAttributeNode
!== "undefined" && elem
.getAttributeNode("id");
4740 return elem
.nodeType
=== 1 && node
&& node
.nodeValue
=== match
;
4744 root
.removeChild( form
);
4745 root
= form
= null; // release memory in IE
4750 var div
= document
.createElement("div");
4751 div
.appendChild( document
.createComment("") );
4753 if ( div
.getElementsByTagName("*").length
> 0 ) {
4754 Expr
.find
.TAG = function(match
, context
){
4755 var results
= context
.getElementsByTagName(match
[1]);
4757 if ( match
[1] === "*" ) {
4760 for ( var i
= 0; results
[i
]; i
++ ) {
4761 if ( results
[i
].nodeType
=== 1 ) {
4762 tmp
.push( results
[i
] );
4773 div
.innerHTML
= "<a href='#'></a>";
4774 if ( div
.firstChild
&& typeof div
.firstChild
.getAttribute
!== "undefined" &&
4775 div
.firstChild
.getAttribute("href") !== "#" ) {
4776 Expr
.attrHandle
.href = function(elem
){
4777 return elem
.getAttribute("href", 2);
4781 div
= null; // release memory in IE
4784 if ( document
.querySelectorAll
) (function(){
4785 var oldSizzle
= Sizzle
, div
= document
.createElement("div");
4786 div
.innerHTML
= "<p class='TEST'></p>";
4788 if ( div
.querySelectorAll
&& div
.querySelectorAll(".TEST").length
=== 0 ) {
4792 Sizzle = function(query
, context
, extra
, seed
){
4793 context
= context
|| document
;
4795 if ( !seed
&& context
.nodeType
=== 9 && !isXML(context
) ) {
4797 return makeArray( context
.querySelectorAll(query
), extra
);
4801 return oldSizzle(query
, context
, extra
, seed
);
4804 for ( var prop
in oldSizzle
) {
4805 Sizzle
[ prop
] = oldSizzle
[ prop
];
4808 div
= null; // release memory in IE
4811 if ( document
.getElementsByClassName
&& document
.documentElement
.getElementsByClassName
) (function(){
4812 var div
= document
.createElement("div");
4813 div
.innerHTML
= "<div class='test e'></div><div class='test'></div>";
4815 if ( div
.getElementsByClassName("e").length
=== 0 )
4818 div
.lastChild
.className
= "e";
4820 if ( div
.getElementsByClassName("e").length
=== 1 )
4823 Expr
.order
.splice(1, 0, "CLASS");
4824 Expr
.find
.CLASS = function(match
, context
, isXML
) {
4825 if ( typeof context
.getElementsByClassName
!== "undefined" && !isXML
) {
4826 return context
.getElementsByClassName(match
[1]);
4830 div
= null; // release memory in IE
4833 function dirNodeCheck( dir
, cur
, doneName
, checkSet
, nodeCheck
, isXML
) {
4834 var sibDir
= dir
== "previousSibling" && !isXML
;
4835 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
4836 var elem
= checkSet
[i
];
4838 if ( sibDir
&& elem
.nodeType
=== 1 ){
4839 elem
.sizcache
= doneName
;
4846 if ( elem
.sizcache
=== doneName
) {
4847 match
= checkSet
[elem
.sizset
];
4851 if ( elem
.nodeType
=== 1 && !isXML
){
4852 elem
.sizcache
= doneName
;
4856 if ( elem
.nodeName
=== cur
) {
4864 checkSet
[i
] = match
;
4869 function dirCheck( dir
, cur
, doneName
, checkSet
, nodeCheck
, isXML
) {
4870 var sibDir
= dir
== "previousSibling" && !isXML
;
4871 for ( var i
= 0, l
= checkSet
.length
; i
< l
; i
++ ) {
4872 var elem
= checkSet
[i
];
4874 if ( sibDir
&& elem
.nodeType
=== 1 ) {
4875 elem
.sizcache
= doneName
;
4882 if ( elem
.sizcache
=== doneName
) {
4883 match
= checkSet
[elem
.sizset
];
4887 if ( elem
.nodeType
=== 1 ) {
4889 elem
.sizcache
= doneName
;
4892 if ( typeof cur
!== "string" ) {
4893 if ( elem
=== cur
) {
4898 } else if ( Sizzle
.filter( cur
, [elem
] ).length
> 0 ) {
4907 checkSet
[i
] = match
;
4912 var contains
= document
.compareDocumentPosition
? function(a
, b
){
4913 return a
.compareDocumentPosition(b
) & 16;
4915 return a
!== b
&& (a
.contains
? a
.contains(b
) : true);
4918 var isXML = function(elem
){
4919 return elem
.nodeType
=== 9 && elem
.documentElement
.nodeName
!== "HTML" ||
4920 !!elem
.ownerDocument
&& elem
.ownerDocument
.documentElement
.nodeName
!== "HTML";
4923 var posProcess = function(selector
, context
){
4924 var tmpSet
= [], later
= "", match
,
4925 root
= context
.nodeType
? [context
] : context
;
4927 while ( (match
= Expr
.match
.PSEUDO
.exec( selector
)) ) {
4929 selector
= selector
.replace( Expr
.match
.PSEUDO
, "" );
4932 selector
= Expr
.relative
[selector
] ? selector
+ "*" : selector
;
4934 for ( var i
= 0, l
= root
.length
; i
< l
; i
++ ) {
4935 Sizzle( selector
, root
[i
], tmpSet
);
4938 return Sizzle
.filter( later
, tmpSet
);
4942 window
.Sizzle
= Sizzle
;
4946 ;(function(engine
) {
4947 var extendElements
= Prototype
.Selector
.extendElements
;
4949 function select(selector
, scope
) {
4950 return extendElements(engine(selector
, scope
|| document
));
4953 function match(element
, selector
) {
4954 return engine
.matches(selector
, [element
]).length
== 1;
4957 Prototype
.Selector
.engine
= engine
;
4958 Prototype
.Selector
.select
= select
;
4959 Prototype
.Selector
.match
= match
;
4962 window
.Sizzle
= Prototype
._original_property
;
4963 delete Prototype
._original_property
;
4966 reset: function(form
) {
4972 serializeElements: function(elements
, options
) {
4973 if (typeof options
!= 'object') options
= { hash
: !!options
};
4974 else if (Object
.isUndefined(options
.hash
)) options
.hash
= true;
4975 var key
, value
, submitted
= false, submit
= options
.submit
, accumulator
, initial
;
4979 accumulator = function(result
, key
, value
) {
4980 if (key
in result
) {
4981 if (!Object
.isArray(result
[key
])) result
[key
] = [result
[key
]];
4982 result
[key
].push(value
);
4983 } else result
[key
] = value
;
4988 accumulator = function(result
, key
, value
) {
4989 return result
+ (result
? '&' : '') + encodeURIComponent(key
) + '=' + encodeURIComponent(value
);
4993 return elements
.inject(initial
, function(result
, element
) {
4994 if (!element
.disabled
&& element
.name
) {
4995 key
= element
.name
; value
= $(element
).getValue();
4996 if (value
!= null && element
.type
!= 'file' && (element
.type
!= 'submit' || (!submitted
&&
4997 submit
!== false && (!submit
|| key
== submit
) && (submitted
= true)))) {
4998 result
= accumulator(result
, key
, value
);
5007 serialize: function(form
, options
) {
5008 return Form
.serializeElements(Form
.getElements(form
), options
);
5011 getElements: function(form
) {
5012 var elements
= $(form
).getElementsByTagName('*'),
5015 serializers
= Form
.Element
.Serializers
;
5016 for (var i
= 0; element
= elements
[i
]; i
++) {
5019 return arr
.inject([], function(elements
, child
) {
5020 if (serializers
[child
.tagName
.toLowerCase()])
5021 elements
.push(Element
.extend(child
));
5026 getInputs: function(form
, typeName
, name
) {
5028 var inputs
= form
.getElementsByTagName('input');
5030 if (!typeName
&& !name
) return $A(inputs
).map(Element
.extend
);
5032 for (var i
= 0, matchingInputs
= [], length
= inputs
.length
; i
< length
; i
++) {
5033 var input
= inputs
[i
];
5034 if ((typeName
&& input
.type
!= typeName
) || (name
&& input
.name
!= name
))
5036 matchingInputs
.push(Element
.extend(input
));
5039 return matchingInputs
;
5042 disable: function(form
) {
5044 Form
.getElements(form
).invoke('disable');
5048 enable: function(form
) {
5050 Form
.getElements(form
).invoke('enable');
5054 findFirstElement: function(form
) {
5055 var elements
= $(form
).getElements().findAll(function(element
) {
5056 return 'hidden' != element
.type
&& !element
.disabled
;
5058 var firstByIndex
= elements
.findAll(function(element
) {
5059 return element
.hasAttribute('tabIndex') && element
.tabIndex
>= 0;
5060 }).sortBy(function(element
) { return element
.tabIndex
}).first();
5062 return firstByIndex
? firstByIndex
: elements
.find(function(element
) {
5063 return /^(?:input|select|textarea)$/i.test(element
.tagName
);
5067 focusFirstElement: function(form
) {
5069 var element
= form
.findFirstElement();
5070 if (element
) element
.activate();
5074 request: function(form
, options
) {
5075 form
= $(form
), options
= Object
.clone(options
|| { });
5077 var params
= options
.parameters
, action
= form
.readAttribute('action') || '';
5078 if (action
.blank()) action
= window
.location
.href
;
5079 options
.parameters
= form
.serialize(true);
5082 if (Object
.isString(params
)) params
= params
.toQueryParams();
5083 Object
.extend(options
.parameters
, params
);
5086 if (form
.hasAttribute('method') && !options
.method
)
5087 options
.method
= form
.method
;
5089 return new Ajax
.Request(action
, options
);
5093 /*--------------------------------------------------------------------------*/
5097 focus: function(element
) {
5102 select: function(element
) {
5103 $(element
).select();
5108 Form
.Element
.Methods
= {
5110 serialize: function(element
) {
5111 element
= $(element
);
5112 if (!element
.disabled
&& element
.name
) {
5113 var value
= element
.getValue();
5114 if (value
!= undefined) {
5116 pair
[element
.name
] = value
;
5117 return Object
.toQueryString(pair
);
5123 getValue: function(element
) {
5124 element
= $(element
);
5125 var method
= element
.tagName
.toLowerCase();
5126 return Form
.Element
.Serializers
[method
](element
);
5129 setValue: function(element
, value
) {
5130 element
= $(element
);
5131 var method
= element
.tagName
.toLowerCase();
5132 Form
.Element
.Serializers
[method
](element
, value
);
5136 clear: function(element
) {
5137 $(element
).value
= '';
5141 present: function(element
) {
5142 return $(element
).value
!= '';
5145 activate: function(element
) {
5146 element
= $(element
);
5149 if (element
.select
&& (element
.tagName
.toLowerCase() != 'input' ||
5150 !(/^(?:button|reset|submit)$/i.test(element
.type
))))
5156 disable: function(element
) {
5157 element
= $(element
);
5158 element
.disabled
= true;
5162 enable: function(element
) {
5163 element
= $(element
);
5164 element
.disabled
= false;
5169 /*--------------------------------------------------------------------------*/
5171 var Field
= Form
.Element
;
5173 var $F
= Form
.Element
.Methods
.getValue
;
5175 /*--------------------------------------------------------------------------*/
5177 Form
.Element
.Serializers
= (function() {
5178 function input(element
, value
) {
5179 switch (element
.type
.toLowerCase()) {
5182 return inputSelector(element
, value
);
5184 return valueSelector(element
, value
);
5188 function inputSelector(element
, value
) {
5189 if (Object
.isUndefined(value
))
5190 return element
.checked
? element
.value
: null;
5191 else element
.checked
= !!value
;
5194 function valueSelector(element
, value
) {
5195 if (Object
.isUndefined(value
)) return element
.value
;
5196 else element
.value
= value
;
5199 function select(element
, value
) {
5200 if (Object
.isUndefined(value
))
5201 return (element
.type
=== 'select-one' ? selectOne
: selectMany
)(element
);
5203 var opt
, currentValue
, single
= !Object
.isArray(value
);
5204 for (var i
= 0, length
= element
.length
; i
< length
; i
++) {
5205 opt
= element
.options
[i
];
5206 currentValue
= this.optionValue(opt
);
5208 if (currentValue
== value
) {
5209 opt
.selected
= true;
5213 else opt
.selected
= value
.include(currentValue
);
5217 function selectOne(element
) {
5218 var index
= element
.selectedIndex
;
5219 return index
>= 0 ? optionValue(element
.options
[index
]) : null;
5222 function selectMany(element
) {
5223 var values
, length
= element
.length
;
5224 if (!length
) return null;
5226 for (var i
= 0, values
= []; i
< length
; i
++) {
5227 var opt
= element
.options
[i
];
5228 if (opt
.selected
) values
.push(optionValue(opt
));
5233 function optionValue(opt
) {
5234 return Element
.hasAttribute(opt
, 'value') ? opt
.value
: opt
.text
;
5239 inputSelector
: inputSelector
,
5240 textarea
: valueSelector
,
5242 selectOne
: selectOne
,
5243 selectMany
: selectMany
,
5244 optionValue
: optionValue
,
5245 button
: valueSelector
5249 /*--------------------------------------------------------------------------*/
5252 Abstract
.TimedObserver
= Class
.create(PeriodicalExecuter
, {
5253 initialize: function($super, element
, frequency
, callback
) {
5254 $super(callback
, frequency
);
5255 this.element
= $(element
);
5256 this.lastValue
= this.getValue();
5259 execute: function() {
5260 var value
= this.getValue();
5261 if (Object
.isString(this.lastValue
) && Object
.isString(value
) ?
5262 this.lastValue
!= value
: String(this.lastValue
) != String(value
)) {
5263 this.callback(this.element
, value
);
5264 this.lastValue
= value
;
5269 Form
.Element
.Observer
= Class
.create(Abstract
.TimedObserver
, {
5270 getValue: function() {
5271 return Form
.Element
.getValue(this.element
);
5275 Form
.Observer
= Class
.create(Abstract
.TimedObserver
, {
5276 getValue: function() {
5277 return Form
.serialize(this.element
);
5281 /*--------------------------------------------------------------------------*/
5283 Abstract
.EventObserver
= Class
.create({
5284 initialize: function(element
, callback
) {
5285 this.element
= $(element
);
5286 this.callback
= callback
;
5288 this.lastValue
= this.getValue();
5289 if (this.element
.tagName
.toLowerCase() == 'form')
5290 this.registerFormCallbacks();
5292 this.registerCallback(this.element
);
5295 onElementEvent: function() {
5296 var value
= this.getValue();
5297 if (this.lastValue
!= value
) {
5298 this.callback(this.element
, value
);
5299 this.lastValue
= value
;
5303 registerFormCallbacks: function() {
5304 Form
.getElements(this.element
).each(this.registerCallback
, this);
5307 registerCallback: function(element
) {
5309 switch (element
.type
.toLowerCase()) {
5312 Event
.observe(element
, 'click', this.onElementEvent
.bind(this));
5315 Event
.observe(element
, 'change', this.onElementEvent
.bind(this));
5322 Form
.Element
.EventObserver
= Class
.create(Abstract
.EventObserver
, {
5323 getValue: function() {
5324 return Form
.Element
.getValue(this.element
);
5328 Form
.EventObserver
= Class
.create(Abstract
.EventObserver
, {
5329 getValue: function() {
5330 return Form
.serialize(this.element
);
5354 var docEl
= document
.documentElement
;
5355 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
= 'onmouseenter' in docEl
5356 && 'onmouseleave' in docEl
;
5360 var isIELegacyEvent = function(event
) { return false; };
5362 if (window
.attachEvent
) {
5363 if (window
.addEventListener
) {
5364 isIELegacyEvent = function(event
) {
5365 return !(event
instanceof window
.Event
);
5368 isIELegacyEvent = function(event
) { return true; };
5374 function _isButtonForDOMEvents(event
, code
) {
5375 return event
.which
? (event
.which
=== code
+ 1) : (event
.button
=== code
);
5378 var legacyButtonMap
= { 0: 1, 1: 4, 2: 2 };
5379 function _isButtonForLegacyEvents(event
, code
) {
5380 return event
.button
=== legacyButtonMap
[code
];
5383 function _isButtonForWebKit(event
, code
) {
5385 case 0: return event
.which
== 1 && !event
.metaKey
;
5386 case 1: return event
.which
== 2 || (event
.which
== 1 && event
.metaKey
);
5387 case 2: return event
.which
== 3;
5388 default: return false;
5392 if (window
.attachEvent
) {
5393 if (!window
.addEventListener
) {
5394 _isButton
= _isButtonForLegacyEvents
;
5396 _isButton = function(event
, code
) {
5397 return isIELegacyEvent(event
) ? _isButtonForLegacyEvents(event
, code
) :
5398 _isButtonForDOMEvents(event
, code
);
5401 } else if (Prototype
.Browser
.WebKit
) {
5402 _isButton
= _isButtonForWebKit
;
5404 _isButton
= _isButtonForDOMEvents
;
5407 function isLeftClick(event
) { return _isButton(event
, 0) }
5409 function isMiddleClick(event
) { return _isButton(event
, 1) }
5411 function isRightClick(event
) { return _isButton(event
, 2) }
5413 function element(event
) {
5414 event
= Event
.extend(event
);
5416 var node
= event
.target
, type
= event
.type
,
5417 currentTarget
= event
.currentTarget
;
5419 if (currentTarget
&& currentTarget
.tagName
) {
5420 if (type
=== 'load' || type
=== 'error' ||
5421 (type
=== 'click' && currentTarget
.tagName
.toLowerCase() === 'input'
5422 && currentTarget
.type
=== 'radio'))
5423 node
= currentTarget
;
5426 if (node
.nodeType
== Node
.TEXT_NODE
)
5427 node
= node
.parentNode
;
5429 return Element
.extend(node
);
5432 function findElement(event
, expression
) {
5433 var element
= Event
.element(event
);
5435 if (!expression
) return element
;
5437 if (Object
.isElement(element
) && Prototype
.Selector
.match(element
, expression
)) {
5438 return Element
.extend(element
);
5440 element
= element
.parentNode
;
5444 function pointer(event
) {
5445 return { x
: pointerX(event
), y
: pointerY(event
) };
5448 function pointerX(event
) {
5449 var docElement
= document
.documentElement
,
5450 body
= document
.body
|| { scrollLeft
: 0 };
5452 return event
.pageX
|| (event
.clientX
+
5453 (docElement
.scrollLeft
|| body
.scrollLeft
) -
5454 (docElement
.clientLeft
|| 0));
5457 function pointerY(event
) {
5458 var docElement
= document
.documentElement
,
5459 body
= document
.body
|| { scrollTop
: 0 };
5461 return event
.pageY
|| (event
.clientY
+
5462 (docElement
.scrollTop
|| body
.scrollTop
) -
5463 (docElement
.clientTop
|| 0));
5467 function stop(event
) {
5468 Event
.extend(event
);
5469 event
.preventDefault();
5470 event
.stopPropagation();
5472 event
.stopped
= true;
5477 isLeftClick
: isLeftClick
,
5478 isMiddleClick
: isMiddleClick
,
5479 isRightClick
: isRightClick
,
5482 findElement
: findElement
,
5491 var methods
= Object
.keys(Event
.Methods
).inject({ }, function(m
, name
) {
5492 m
[name
] = Event
.Methods
[name
].methodize();
5496 if (window
.attachEvent
) {
5497 function _relatedTarget(event
) {
5499 switch (event
.type
) {
5502 element
= event
.fromElement
;
5506 element
= event
.toElement
;
5511 return Element
.extend(element
);
5514 var additionalMethods
= {
5515 stopPropagation: function() { this.cancelBubble
= true },
5516 preventDefault: function() { this.returnValue
= false },
5517 inspect: function() { return '[object Event]' }
5520 Event
.extend = function(event
, element
) {
5521 if (!event
) return false;
5523 if (!isIELegacyEvent(event
)) return event
;
5525 if (event
._extendedByPrototype
) return event
;
5526 event
._extendedByPrototype
= Prototype
.emptyFunction
;
5528 var pointer
= Event
.pointer(event
);
5530 Object
.extend(event
, {
5531 target
: event
.srcElement
|| element
,
5532 relatedTarget
: _relatedTarget(event
),
5537 Object
.extend(event
, methods
);
5538 Object
.extend(event
, additionalMethods
);
5543 Event
.extend
= Prototype
.K
;
5546 if (window
.addEventListener
) {
5547 Event
.prototype = window
.Event
.prototype || document
.createEvent('HTMLEvents').__proto__
;
5548 Object
.extend(Event
.prototype, methods
);
5551 function _createResponder(element
, eventName
, handler
) {
5552 var registry
= Element
.retrieve(element
, 'prototype_event_registry');
5554 if (Object
.isUndefined(registry
)) {
5555 CACHE
.push(element
);
5556 registry
= Element
.retrieve(element
, 'prototype_event_registry', $H());
5559 var respondersForEvent
= registry
.get(eventName
);
5560 if (Object
.isUndefined(respondersForEvent
)) {
5561 respondersForEvent
= [];
5562 registry
.set(eventName
, respondersForEvent
);
5565 if (respondersForEvent
.pluck('handler').include(handler
)) return false;
5568 if (eventName
.include(":")) {
5569 responder = function(event
) {
5570 if (Object
.isUndefined(event
.eventName
))
5573 if (event
.eventName
!== eventName
)
5576 Event
.extend(event
, element
);
5577 handler
.call(element
, event
);
5580 if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
&&
5581 (eventName
=== "mouseenter" || eventName
=== "mouseleave")) {
5582 if (eventName
=== "mouseenter" || eventName
=== "mouseleave") {
5583 responder = function(event
) {
5584 Event
.extend(event
, element
);
5586 var parent
= event
.relatedTarget
;
5587 while (parent
&& parent
!== element
) {
5588 try { parent
= parent
.parentNode
; }
5589 catch(e
) { parent
= element
; }
5592 if (parent
=== element
) return;
5594 handler
.call(element
, event
);
5598 responder = function(event
) {
5599 Event
.extend(event
, element
);
5600 handler
.call(element
, event
);
5605 responder
.handler
= handler
;
5606 respondersForEvent
.push(responder
);
5610 function _destroyCache() {
5611 for (var i
= 0, length
= CACHE
.length
; i
< length
; i
++) {
5612 Event
.stopObserving(CACHE
[i
]);
5619 if (Prototype
.Browser
.IE
)
5620 window
.attachEvent('onunload', _destroyCache
);
5622 if (Prototype
.Browser
.WebKit
)
5623 window
.addEventListener('unload', Prototype
.emptyFunction
, false);
5626 var _getDOMEventName
= Prototype
.K
,
5627 translations
= { mouseenter
: "mouseover", mouseleave
: "mouseout" };
5629 if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED
) {
5630 _getDOMEventName = function(eventName
) {
5631 return (translations
[eventName
] || eventName
);
5635 function observe(element
, eventName
, handler
) {
5636 element
= $(element
);
5638 var responder
= _createResponder(element
, eventName
, handler
);
5640 if (!responder
) return element
;
5642 if (eventName
.include(':')) {
5643 if (element
.addEventListener
)
5644 element
.addEventListener("dataavailable", responder
, false);
5646 element
.attachEvent("ondataavailable", responder
);
5647 element
.attachEvent("onlosecapture", responder
);
5650 var actualEventName
= _getDOMEventName(eventName
);
5652 if (element
.addEventListener
)
5653 element
.addEventListener(actualEventName
, responder
, false);
5655 element
.attachEvent("on" + actualEventName
, responder
);
5661 function stopObserving(element
, eventName
, handler
) {
5662 element
= $(element
);
5664 var registry
= Element
.retrieve(element
, 'prototype_event_registry');
5665 if (!registry
) return element
;
5668 registry
.each( function(pair
) {
5669 var eventName
= pair
.key
;
5670 stopObserving(element
, eventName
);
5675 var responders
= registry
.get(eventName
);
5676 if (!responders
) return element
;
5679 responders
.each(function(r
) {
5680 stopObserving(element
, eventName
, r
.handler
);
5685 var i
= responders
.length
, responder
;
5687 if (responders
[i
].handler
=== handler
) {
5688 responder
= responders
[i
];
5692 if (!responder
) return element
;
5694 if (eventName
.include(':')) {
5695 if (element
.removeEventListener
)
5696 element
.removeEventListener("dataavailable", responder
, false);
5698 element
.detachEvent("ondataavailable", responder
);
5699 element
.detachEvent("onlosecapture", responder
);
5702 var actualEventName
= _getDOMEventName(eventName
);
5703 if (element
.removeEventListener
)
5704 element
.removeEventListener(actualEventName
, responder
, false);
5706 element
.detachEvent('on' + actualEventName
, responder
);
5709 registry
.set(eventName
, responders
.without(responder
));
5714 function fire(element
, eventName
, memo
, bubble
) {
5715 element
= $(element
);
5717 if (Object
.isUndefined(bubble
))
5720 if (element
== document
&& document
.createEvent
&& !element
.dispatchEvent
)
5721 element
= document
.documentElement
;
5724 if (document
.createEvent
) {
5725 event
= document
.createEvent('HTMLEvents');
5726 event
.initEvent('dataavailable', bubble
, true);
5728 event
= document
.createEventObject();
5729 event
.eventType
= bubble
? 'ondataavailable' : 'onlosecapture';
5732 event
.eventName
= eventName
;
5733 event
.memo
= memo
|| { };
5735 if (document
.createEvent
)
5736 element
.dispatchEvent(event
);
5738 element
.fireEvent(event
.eventType
, event
);
5740 return Event
.extend(event
);
5743 Event
.Handler
= Class
.create({
5744 initialize: function(element
, eventName
, selector
, callback
) {
5745 this.element
= $(element
);
5746 this.eventName
= eventName
;
5747 this.selector
= selector
;
5748 this.callback
= callback
;
5749 this.handler
= this.handleEvent
.bind(this);
5753 Event
.observe(this.element
, this.eventName
, this.handler
);
5758 Event
.stopObserving(this.element
, this.eventName
, this.handler
);
5762 handleEvent: function(event
) {
5763 var element
= Event
.findElement(event
, this.selector
);
5764 if (element
) this.callback
.call(this.element
, event
, element
);
5768 function on(element
, eventName
, selector
, callback
) {
5769 element
= $(element
);
5770 if (Object
.isFunction(selector
) && Object
.isUndefined(callback
)) {
5771 callback
= selector
, selector
= null;
5774 return new Event
.Handler(element
, eventName
, selector
, callback
).start();
5777 Object
.extend(Event
, Event
.Methods
);
5779 Object
.extend(Event
, {
5782 stopObserving
: stopObserving
,
5786 Element
.addMethods({
5791 stopObserving
: stopObserving
,
5796 Object
.extend(document
, {
5797 fire
: fire
.methodize(),
5799 observe
: observe
.methodize(),
5801 stopObserving
: stopObserving
.methodize(),
5803 p_on
: on
.methodize(),
5808 if (window
.Event
) Object
.extend(window
.Event
, Event
);
5809 else window
.Event
= Event
;
5813 /* Support for the DOMContentLoaded event is based on work by Dan Webb,
5814 Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
5818 function fireContentLoadedEvent() {
5819 if (document
.loaded
) return;
5820 if (timer
) window
.clearTimeout(timer
);
5821 document
.loaded
= true;
5822 document
.fire('dom:loaded');
5825 function checkReadyState() {
5826 if (document
.readyState
=== 'complete') {
5827 document
.stopObserving('readystatechange', checkReadyState
);
5828 fireContentLoadedEvent();
5832 function pollDoScroll() {
5833 try { document
.documentElement
.doScroll('left'); }
5835 timer
= pollDoScroll
.defer();
5838 fireContentLoadedEvent();
5841 if (document
.addEventListener
) {
5842 document
.addEventListener('DOMContentLoaded', fireContentLoadedEvent
, false);
5844 document
.observe('readystatechange', checkReadyState
);
5846 timer
= pollDoScroll
.defer();
5849 Event
.observe(window
, 'load', fireContentLoadedEvent
);
5852 Element
.addMethods();
5854 /*------------------------------- DEPRECATED -------------------------------*/
5856 Hash
.toQueryString
= Object
.toQueryString
;
5858 var Toggle
= { display
: Element
.toggle
};
5860 Element
.Methods
.childOf
= Element
.Methods
.descendantOf
;
5863 Before: function(element
, content
) {
5864 return Element
.insert(element
, {before
:content
});
5867 Top: function(element
, content
) {
5868 return Element
.insert(element
, {top
:content
});
5871 Bottom: function(element
, content
) {
5872 return Element
.insert(element
, {bottom
:content
});
5875 After: function(element
, content
) {
5876 return Element
.insert(element
, {after
:content
});
5880 var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
5883 includeScrollOffsets
: false,
5885 prepare: function() {
5886 this.deltaX
= window
.pageXOffset
5887 || document
.documentElement
.scrollLeft
5888 || document
.body
.scrollLeft
5890 this.deltaY
= window
.pageYOffset
5891 || document
.documentElement
.scrollTop
5892 || document
.body
.scrollTop
5896 within: function(element
, x
, y
) {
5897 if (this.includeScrollOffsets
)
5898 return this.withinIncludingScrolloffsets(element
, x
, y
);
5901 this.offset
= Element
.cumulativeOffset(element
);
5903 return (y
>= this.offset
[1] &&
5904 y
< this.offset
[1] + element
.offsetHeight
&&
5905 x
>= this.offset
[0] &&
5906 x
< this.offset
[0] + element
.offsetWidth
);
5909 withinIncludingScrolloffsets: function(element
, x
, y
) {
5910 var offsetcache
= Element
.cumulativeScrollOffset(element
);
5912 this.xcomp
= x
+ offsetcache
[0] - this.deltaX
;
5913 this.ycomp
= y
+ offsetcache
[1] - this.deltaY
;
5914 this.offset
= Element
.cumulativeOffset(element
);
5916 return (this.ycomp
>= this.offset
[1] &&
5917 this.ycomp
< this.offset
[1] + element
.offsetHeight
&&
5918 this.xcomp
>= this.offset
[0] &&
5919 this.xcomp
< this.offset
[0] + element
.offsetWidth
);
5922 overlap: function(mode
, element
) {
5923 if (!mode
) return 0;
5924 if (mode
== 'vertical')
5925 return ((this.offset
[1] + element
.offsetHeight
) - this.ycomp
) /
5926 element
.offsetHeight
;
5927 if (mode
== 'horizontal')
5928 return ((this.offset
[0] + element
.offsetWidth
) - this.xcomp
) /
5929 element
.offsetWidth
;
5933 cumulativeOffset
: Element
.Methods
.cumulativeOffset
,
5935 positionedOffset
: Element
.Methods
.positionedOffset
,
5937 absolutize: function(element
) {
5939 return Element
.absolutize(element
);
5942 relativize: function(element
) {
5944 return Element
.relativize(element
);
5947 realOffset
: Element
.Methods
.cumulativeScrollOffset
,
5949 offsetParent
: Element
.Methods
.getOffsetParent
,
5951 page
: Element
.Methods
.viewportOffset
,
5953 clone: function(source
, target
, options
) {
5954 options
= options
|| { };
5955 return Element
.clonePosition(target
, source
, options
);
5959 /*--------------------------------------------------------------------------*/
5961 if (!document
.getElementsByClassName
) document
.getElementsByClassName = function(instanceMethods
){
5962 function iter(name
) {
5963 return name
.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name
+ " ')]";
5966 instanceMethods
.getElementsByClassName
= Prototype
.BrowserFeatures
.XPath
?
5967 function(element
, className
) {
5968 className
= className
.toString().strip();
5969 var cond
= /\s/.test(className
) ? $w(className
).map(iter
).join('') : iter(className
);
5970 return cond
? document
._getElementsByXPath('.//*' + cond
, element
) : [];
5971 } : function(element
, className
) {
5972 className
= className
.toString().strip();
5973 var elements
= [], classNames
= (/\s/.test(className
) ? $w(className
) : null);
5974 if (!classNames
&& !className
) return elements
;
5976 var nodes
= $(element
).getElementsByTagName('*');
5977 className
= ' ' + className
+ ' ';
5979 for (var i
= 0, child
, cn
; child
= nodes
[i
]; i
++) {
5980 if (child
.className
&& (cn
= ' ' + child
.className
+ ' ') && (cn
.include(className
) ||
5981 (classNames
&& classNames
.all(function(name
) {
5982 return !name
.toString().blank() && cn
.include(' ' + name
+ ' ');
5984 elements
.push(Element
.extend(child
));
5989 return function(className
, parentElement
) {
5990 return $(parentElement
|| document
.body
).getElementsByClassName(className
);
5994 /*--------------------------------------------------------------------------*/
5996 Element
.ClassNames
= Class
.create();
5997 Element
.ClassNames
.prototype = {
5998 initialize: function(element
) {
5999 this.element
= $(element
);
6002 _each: function(iterator
) {
6003 this.element
.className
.split(/\s+/).select(function(name
) {
6004 return name
.length
> 0;
6008 set: function(className
) {
6009 this.element
.className
= className
;
6012 add: function(classNameToAdd
) {
6013 if (this.include(classNameToAdd
)) return;
6014 this.set($A(this).concat(classNameToAdd
).join(' '));
6017 remove: function(classNameToRemove
) {
6018 if (!this.include(classNameToRemove
)) return;
6019 this.set($A(this).without(classNameToRemove
).join(' '));
6022 toString: function() {
6023 return $A(this).join(' ');
6027 Object
.extend(Element
.ClassNames
.prototype, Enumerable
);
6029 /*--------------------------------------------------------------------------*/
6032 window
.Selector
= Class
.create({
6033 initialize: function(expression
) {
6034 this.expression
= expression
.strip();
6037 findElements: function(rootElement
) {
6038 return Prototype
.Selector
.select(this.expression
, rootElement
);
6041 match: function(element
) {
6042 return Prototype
.Selector
.match(element
, this.expression
);
6045 toString: function() {
6046 return this.expression
;
6049 inspect: function() {
6050 return "#<Selector: " + this.expression
+ ">";
6054 Object
.extend(Selector
, {
6055 matchElements: function(elements
, expression
) {
6056 var match
= Prototype
.Selector
.match
,
6059 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
6060 var element
= elements
[i
];
6061 if (match(element
, expression
)) {
6062 results
.push(Element
.extend(element
));
6068 findElement: function(elements
, expression
, index
) {
6070 var matchIndex
= 0, element
;
6071 for (var i
= 0, length
= elements
.length
; i
< length
; i
++) {
6072 element
= elements
[i
];
6073 if (Prototype
.Selector
.match(element
, expression
) && index
=== matchIndex
++) {
6074 return Element
.extend(element
);
6079 findChildElements: function(element
, expressions
) {
6080 var selector
= expressions
.toArray().join(', ');
6081 return Prototype
.Selector
.select(selector
, element
|| document
);