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