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