1/* Prototype JavaScript framework, version 1.7.2
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 }
60if (Prototype.Browser.MobileSafari)
61 Prototype.BrowserFeatures.SpecificElementExtensions = false;
62/* Based on Alex Arnell's inheritance implementation. */
64var 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
369Object.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;
501RegExp.prototype.match = RegExp.prototype.test;
503RegExp.escape = function(str) {
504 return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
506var 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;
542Object.extend(String, {
543 interpret: function(value) {
544 return value == null ? '' : String(value);
556Object.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 = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/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
818var 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);
852Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
856var 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,
1099function $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];
1108function $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 var some = wrapNative(Array.prototype.some);
1339 function every(iterator) {
1340 if (this == null) throw new TypeError();
1341 iterator = iterator || Prototype.K;
1342 var context = arguments[1];
1344 var object = Object(this);
1345 for (var i = 0, length = object.length >>> 0; i < length; i++) {
1346 if (i in object && !iterator.call(context, object[i], i, object)) {
1354 if (arrayProto.every) {
1355 var every = wrapNative(Array.prototype.every);
1358 var _reduce = arrayProto.reduce;
1359 function inject(memo, iterator) {
1360 iterator = iterator || Prototype.K;
1361 var context = arguments[2];
1362 return _reduce.call(this, iterator.bind(context), memo);
1365 if (!arrayProto.reduce) {
1366 var inject = Enumerable.inject;
1369 Object.extend(arrayProto, Enumerable);
1371 if (!arrayProto._reverse)
1372 arrayProto._reverse = arrayProto.reverse;
1374 Object.extend(arrayProto, {
1396 intersect: intersect,
1403 var CONCAT_ARGUMENTS_BUGGY = (function() {
1404 return [].concat(arguments)[0][0] !== 1;
1407 if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
1409 if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
1410 if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
1412function $H(object) {
1413 return new Hash(object);
1416var Hash = Class.create(Enumerable, (function() {
1417 function initialize(object) {
1418 this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1422 function _each(iterator, context) {
1424 for (var key in this._object) {
1425 var value = this._object[key], pair = [key, value];
1428 iterator.call(context, pair, i);
1433 function set(key, value) {
1434 return this._object[key] = value;
1438 if (this._object[key] !== Object.prototype[key])
1439 return this._object[key];
1442 function unset(key) {
1443 var value = this._object[key];
1444 delete this._object[key];
1448 function toObject() {
1449 return Object.clone(this._object);
1455 return this.pluck('key');
1459 return this.pluck('value');
1462 function index(value) {
1463 var match = this.detect(function(pair) {
1464 return pair.value === value;
1466 return match && match.key;
1469 function merge(object) {
1470 return this.clone().update(object);
1473 function update(object) {
1474 return new Hash(object).inject(this, function(result, pair) {
1475 result.set(pair.key, pair.value);
1480 function toQueryPair(key, value) {
1481 if (Object.isUndefined(value)) return key;
1483 value = String.interpret(value);
1485 value = value.gsub(/(\r)?\n/, '\r\n');
1486 value = encodeURIComponent(value);
1487 value = value.gsub(/%20/, '+');
1488 return key + '=' + value;
1491 function toQueryString() {
1492 return this.inject([], function(results, pair) {
1493 var key = encodeURIComponent(pair.key), values = pair.value;
1495 if (values && typeof values == 'object') {
1496 if (Object.isArray(values)) {
1497 var queryValues = [];
1498 for (var i = 0, len = values.length, value; i < len; i++) {
1500 queryValues.push(toQueryPair(key, value));
1502 return results.concat(queryValues);
1504 } else results.push(toQueryPair(key, values));
1509 function inspect() {
1510 return '#<Hash:{' + this.map(function(pair) {
1511 return pair.map(Object.inspect).join(': ');
1512 }).join(', ') + '}>';
1516 return new Hash(this);
1520 initialize: initialize,
1526 toTemplateReplacements: toObject,
1532 toQueryString: toQueryString,
1540Object.extend(Number.prototype, (function() {
1541 function toColorPart() {
1542 return this.toPaddedString(2, 16);
1549 function times(iterator, context) {
1550 $R(0, this, true).each(iterator, context);
1554 function toPaddedString(length, radix) {
1555 var string = this.toString(radix || 10);
1556 return '0'.times(length - string.length) + string;
1560 return Math.abs(this);
1564 return Math.round(this);
1568 return Math.ceil(this);
1572 return Math.floor(this);
1576 toColorPart: toColorPart,
1579 toPaddedString: toPaddedString,
1587function $R(start, end, exclusive) {
1588 return new ObjectRange(start, end, exclusive);
1591var ObjectRange = Class.create(Enumerable, (function() {
1592 function initialize(start, end, exclusive) {
1595 this.exclusive = exclusive;
1598 function _each(iterator, context) {
1599 var value = this.start, i;
1600 for (i = 0; this.include(value); i++) {
1601 iterator.call(context, value, i);
1602 value = value.succ();
1606 function include(value) {
1607 if (value < this.start)
1610 return value < this.end;
1611 return value <= this.end;
1615 initialize: initialize,
1630 for (var i = 0, length = arguments.length; i < length; i++) {
1631 var lambda = arguments[i];
1633 returnValue = lambda();
1643 getTransport: function() {
1645 function() {return new XMLHttpRequest()},
1646 function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1647 function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1651 activeRequestCount: 0
1657 _each: function(iterator, context) {
1658 this.responders._each(iterator, context);
1661 register: function(responder) {
1662 if (!this.include(responder))
1663 this.responders.push(responder);
1666 unregister: function(responder) {
1667 this.responders = this.responders.without(responder);
1670 dispatch: function(callback, request, transport, json) {
1671 this.each(function(responder) {
1672 if (Object.isFunction(responder[callback])) {
1674 responder[callback].apply(responder, [request, transport, json]);
1681Object.extend(Ajax.Responders, Enumerable);
1683Ajax.Responders.register({
1684 onCreate: function() { Ajax.activeRequestCount++ },
1685 onComplete: function() { Ajax.activeRequestCount-- }
1687Ajax.Base = Class.create({
1688 initialize: function(options) {
1692 contentType: 'application/x-www-form-urlencoded',
1698 Object.extend(this.options, options || { });
1700 this.options.method = this.options.method.toLowerCase();
1702 if (Object.isHash(this.options.parameters))
1703 this.options.parameters = this.options.parameters.toObject();
1706Ajax.Request = Class.create(Ajax.Base, {
1709 initialize: function($super, url, options) {
1711 this.transport = Ajax.getTransport();
1715 request: function(url) {
1717 this.method = this.options.method;
1718 var params = Object.isString(this.options.parameters) ?
1719 this.options.parameters :
1720 Object.toQueryString(this.options.parameters);
1722 if (!['get', 'post'].include(this.method)) {
1723 params += (params ? '&' : '') + "_method=" + this.method;
1724 this.method = 'post';
1727 if (params && this.method === 'get') {
1728 this.url += (this.url.include('?') ? '&' : '?') + params;
1731 this.parameters = params.toQueryParams();
1734 var response = new Ajax.Response(this);
1735 if (this.options.onCreate) this.options.onCreate(response);
1736 Ajax.Responders.dispatch('onCreate', this, response);
1738 this.transport.open(this.method.toUpperCase(), this.url,
1739 this.options.asynchronous);
1741 if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1743 this.transport.onreadystatechange = this.onStateChange.bind(this);
1744 this.setRequestHeaders();
1746 this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1747 this.transport.send(this.body);
1749 /* Force Firefox to handle ready state 4 for synchronous requests */
1750 if (!this.options.asynchronous && this.transport.overrideMimeType)
1751 this.onStateChange();
1755 this.dispatchException(e);
1759 onStateChange: function() {
1760 var readyState = this.transport.readyState;
1761 if (readyState > 1 && !((readyState == 4) && this._complete))
1762 this.respondToReadyState(this.transport.readyState);
1765 setRequestHeaders: function() {
1767 'X-Requested-With': 'XMLHttpRequest',
1768 'X-Prototype-Version': Prototype.Version,
1769 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1772 if (this.method == 'post') {
1773 headers['Content-type'] = this.options.contentType +
1774 (this.options.encoding ? '; charset=' + this.options.encoding : '');
1776 /* Force "Connection: close" for older Mozilla browsers to work
1777 * around a bug where XMLHttpRequest sends an incorrect
1778 * Content-length header. See Mozilla Bugzilla #246651.
1780 if (this.transport.overrideMimeType &&
1781 (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1782 headers['Connection'] = 'close';
1785 if (typeof this.options.requestHeaders == 'object') {
1786 var extras = this.options.requestHeaders;
1788 if (Object.isFunction(extras.push))
1789 for (var i = 0, length = extras.length; i < length; i += 2)
1790 headers[extras[i]] = extras[i+1];
1792 $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1795 for (var name in headers)
1796 if (headers[name] != null)
1797 this.transport.setRequestHeader(name, headers[name]);
1800 success: function() {
1801 var status = this.getStatus();
1802 return !status || (status >= 200 && status < 300) || status == 304;
1805 getStatus: function() {
1807 if (this.transport.status === 1223) return 204;
1808 return this.transport.status || 0;
1809 } catch (e) { return 0 }
1812 respondToReadyState: function(readyState) {
1813 var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
1815 if (state == 'Complete') {
1817 this._complete = true;
1818 (this.options['on' + response.status]
1819 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1820 || Prototype.emptyFunction)(response, response.headerJSON);
1822 this.dispatchException(e);
1825 var contentType = response.getHeader('Content-type');
1826 if (this.options.evalJS == 'force'
1827 || (this.options.evalJS && this.isSameOrigin() && contentType
1828 && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1829 this.evalResponse();
1833 (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1834 Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
1836 this.dispatchException(e);
1839 if (state == 'Complete') {
1840 this.transport.onreadystatechange = Prototype.emptyFunction;
1844 isSameOrigin: function() {
1845 var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1846 return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1847 protocol: location.protocol,
1848 domain: document.domain,
1849 port: location.port ? ':' + location.port : ''
1853 getHeader: function(name) {
1855 return this.transport.getResponseHeader(name) || null;
1856 } catch (e) { return null; }
1859 evalResponse: function() {
1861 return eval((this.transport.responseText || '').unfilterJSON());
1863 this.dispatchException(e);
1867 dispatchException: function(exception) {
1868 (this.options.onException || Prototype.emptyFunction)(this, exception);
1869 Ajax.Responders.dispatch('onException', this, exception);
1873Ajax.Request.Events =
1874 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1883Ajax.Response = Class.create({
1884 initialize: function(request){
1885 this.request = request;
1886 var transport = this.transport = request.transport,
1887 readyState = this.readyState = transport.readyState;
1889 if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1890 this.status = this.getStatus();
1891 this.statusText = this.getStatusText();
1892 this.responseText = String.interpret(transport.responseText);
1893 this.headerJSON = this._getHeaderJSON();
1896 if (readyState == 4) {
1897 var xml = transport.responseXML;
1898 this.responseXML = Object.isUndefined(xml) ? null : xml;
1899 this.responseJSON = this._getResponseJSON();
1907 getStatus: Ajax.Request.prototype.getStatus,
1909 getStatusText: function() {
1911 return this.transport.statusText || '';
1912 } catch (e) { return '' }
1915 getHeader: Ajax.Request.prototype.getHeader,
1917 getAllHeaders: function() {
1919 return this.getAllResponseHeaders();
1920 } catch (e) { return null }
1923 getResponseHeader: function(name) {
1924 return this.transport.getResponseHeader(name);
1927 getAllResponseHeaders: function() {
1928 return this.transport.getAllResponseHeaders();
1931 _getHeaderJSON: function() {
1932 var json = this.getHeader('X-JSON');
1933 if (!json) return null;
1936 json = decodeURIComponent(escape(json));
1941 return json.evalJSON(this.request.options.sanitizeJSON ||
1942 !this.request.isSameOrigin());
1944 this.request.dispatchException(e);
1948 _getResponseJSON: function() {
1949 var options = this.request.options;
1950 if (!options.evalJSON || (options.evalJSON != 'force' &&
1951 !(this.getHeader('Content-type') || '').include('application/json')) ||
1952 this.responseText.blank())
1955 return this.responseText.evalJSON(options.sanitizeJSON ||
1956 !this.request.isSameOrigin());
1958 this.request.dispatchException(e);
1963Ajax.Updater = Class.create(Ajax.Request, {
1964 initialize: function($super, container, url, options) {
1966 success: (container.success || container),
1967 failure: (container.failure || (container.success ? null : container))
1970 options = Object.clone(options);
1971 var onComplete = options.onComplete;
1972 options.onComplete = (function(response, json) {
1973 this.updateContent(response.responseText);
1974 if (Object.isFunction(onComplete)) onComplete(response, json);
1977 $super(url, options);
1980 updateContent: function(responseText) {
1981 var receiver = this.container[this.success() ? 'success' : 'failure'],
1982 options = this.options;
1984 if (!options.evalScripts) responseText = responseText.stripScripts();
1986 if (receiver = $(receiver)) {
1987 if (options.insertion) {
1988 if (Object.isString(options.insertion)) {
1989 var insertion = { }; insertion[options.insertion] = responseText;
1990 receiver.insert(insertion);
1992 else options.insertion(receiver, responseText);
1994 else receiver.update(responseText);
1999Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
2000 initialize: function($super, container, url, options) {
2002 this.onComplete = this.options.onComplete;
2004 this.frequency = (this.options.frequency || 2);
2005 this.decay = (this.options.decay || 1);
2008 this.container = container;
2015 this.options.onComplete = this.updateComplete.bind(this);
2016 this.onTimerEvent();
2020 this.updater.options.onComplete = undefined;
2021 clearTimeout(this.timer);
2022 (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
2025 updateComplete: function(response) {
2026 if (this.options.decay) {
2027 this.decay = (response.responseText == this.lastText ?
2028 this.decay * this.options.decay : 1);
2030 this.lastText = response.responseText;
2032 this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
2035 onTimerEvent: function() {
2036 this.updater = new Ajax.Updater(this.container, this.url, this.options);
2043 var SLICE = Array.prototype.slice;
2045 var DIV = document.createElement('div');
2048 function $(element) {
2049 if (arguments.length > 1) {
2050 for (var i = 0, elements = [], length = arguments.length; i < length; i++)
2051 elements.push($(arguments[i]));
2055 if (Object.isString(element))
2056 element = document.getElementById(element);
2057 return Element.extend(element);
2063 if (!GLOBAL.Node) GLOBAL.Node = {};
2065 if (!GLOBAL.Node.ELEMENT_NODE) {
2066 Object.extend(GLOBAL.Node, {
2070 CDATA_SECTION_NODE: 4,
2071 ENTITY_REFERENCE_NODE: 5,
2073 PROCESSING_INSTRUCTION_NODE: 7,
2076 DOCUMENT_TYPE_NODE: 10,
2077 DOCUMENT_FRAGMENT_NODE: 11,
2082 var ELEMENT_CACHE = {};
2084 function shouldUseCreationCache(tagName, attributes) {
2085 if (tagName === 'select') return false;
2086 if ('type' in attributes) return false;
2090 var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
2092 var el = document.createElement('<input name="x">');
2093 return el.tagName.toLowerCase() === 'input' && el.name === 'x';
2101 var oldElement = GLOBAL.Element;
2102 function Element(tagName, attributes) {
2103 attributes = attributes || {};
2104 tagName = tagName.toLowerCase();
2106 if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
2107 tagName = '<' + tagName + ' name="' + attributes.name + '">';
2108 delete attributes.name;
2109 return Element.writeAttribute(document.createElement(tagName), attributes);
2112 if (!ELEMENT_CACHE[tagName])
2113 ELEMENT_CACHE[tagName] = Element.extend(document.createElement(tagName));
2115 var node = shouldUseCreationCache(tagName, attributes) ?
2116 ELEMENT_CACHE[tagName].cloneNode(false) : document.createElement(tagName);
2118 return Element.writeAttribute(node, attributes);
2121 GLOBAL.Element = Element;
2123 Object.extend(GLOBAL.Element, oldElement || {});
2124 if (oldElement) GLOBAL.Element.prototype = oldElement.prototype;
2126 Element.Methods = { ByTag: {}, Simulated: {} };
2130 var INSPECT_ATTRIBUTES = { id: 'id', className: 'class' };
2131 function inspect(element) {
2132 element = $(element);
2133 var result = '<' + element.tagName.toLowerCase();
2135 var attribute, value;
2136 for (var property in INSPECT_ATTRIBUTES) {
2137 attribute = INSPECT_ATTRIBUTES[property];
2138 value = (element[property] || '').toString();
2139 if (value) result += ' ' + attribute + '=' + value.inspect(true);
2142 return result + '>';
2145 methods.inspect = inspect;
2148 function visible(element) {
2149 return $(element).style.display !== 'none';
2152 function toggle(element, bool) {
2153 element = $(element);
2154 if (Object.isUndefined(bool))
2155 bool = !Element.visible(element);
2156 Element[bool ? 'show' : 'hide'](element);
2161 function hide(element) {
2162 element = $(element);
2163 element.style.display = 'none';
2167 function show(element) {
2168 element = $(element);
2169 element.style.display = '';
2174 Object.extend(methods, {
2182 function remove(element) {
2183 element = $(element);
2184 element.parentNode.removeChild(element);
2188 var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
2189 var el = document.createElement("select"),
2191 el.innerHTML = "<option value=\"test\">test</option>";
2192 if (el.options && el.options[0]) {
2193 isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
2199 var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
2201 var el = document.createElement("table");
2202 if (el && el.tBodies) {
2203 el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
2204 var isBuggy = typeof el.tBodies[0] == "undefined";
2213 var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
2215 var el = document.createElement('div');
2216 el.innerHTML = "<link />";
2217 var isBuggy = (el.childNodes.length === 0);
2225 var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
2226 TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
2228 var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
2229 var s = document.createElement("script"),
2232 s.appendChild(document.createTextNode(""));
2233 isBuggy = !s.firstChild ||
2234 s.firstChild && s.firstChild.nodeType !== 3;
2242 function update(element, content) {
2243 element = $(element);
2245 var descendants = element.getElementsByTagName('*'),
2246 i = descendants.length;
2247 while (i--) purgeElement(descendants[i]);
2249 if (content && content.toElement)
2250 content = content.toElement();
2252 if (Object.isElement(content))
2253 return element.update().insert(content);
2256 content = Object.toHTML(content);
2257 var tagName = element.tagName.toUpperCase();
2259 if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
2260 element.text = content;
2264 if (ANY_INNERHTML_BUGGY) {
2265 if (tagName in INSERTION_TRANSLATIONS.tags) {
2266 while (element.firstChild)
2267 element.removeChild(element.firstChild);
2269 var nodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2270 for (var i = 0, node; node = nodes[i]; i++)
2271 element.appendChild(node);
2273 } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
2274 while (element.firstChild)
2275 element.removeChild(element.firstChild);
2277 var nodes = getContentFromAnonymousElement(tagName,
2278 content.stripScripts(), true);
2280 for (var i = 0, node; node = nodes[i]; i++)
2281 element.appendChild(node);
2283 element.innerHTML = content.stripScripts();
2286 element.innerHTML = content.stripScripts();
2289 content.evalScripts.bind(content).defer();
2293 function replace(element, content) {
2294 element = $(element);
2296 if (content && content.toElement) {
2297 content = content.toElement();
2298 } else if (!Object.isElement(content)) {
2299 content = Object.toHTML(content);
2300 var range = element.ownerDocument.createRange();
2301 range.selectNode(element);
2302 content.evalScripts.bind(content).defer();
2303 content = range.createContextualFragment(content.stripScripts());
2306 element.parentNode.replaceChild(content, element);
2310 var INSERTION_TRANSLATIONS = {
2311 before: function(element, node) {
2312 element.parentNode.insertBefore(node, element);
2314 top: function(element, node) {
2315 element.insertBefore(node, element.firstChild);
2317 bottom: function(element, node) {
2318 element.appendChild(node);
2320 after: function(element, node) {
2321 element.parentNode.insertBefore(node, element.nextSibling);
2325 TABLE: ['<table>', '</table>', 1],
2326 TBODY: ['<table><tbody>', '</tbody></table>', 2],
2327 TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
2328 TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2329 SELECT: ['<select>', '</select>', 1]
2333 var tags = INSERTION_TRANSLATIONS.tags;
2335 Object.extend(tags, {
2341 function replace_IE(element, content) {
2342 element = $(element);
2343 if (content && content.toElement)
2344 content = content.toElement();
2345 if (Object.isElement(content)) {
2346 element.parentNode.replaceChild(content, element);
2350 content = Object.toHTML(content);
2351 var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2353 if (tagName in INSERTION_TRANSLATIONS.tags) {
2354 var nextSibling = Element.next(element);
2355 var fragments = getContentFromAnonymousElement(
2356 tagName, content.stripScripts());
2358 parent.removeChild(element);
2362 iterator = function(node) { parent.insertBefore(node, nextSibling) };
2364 iterator = function(node) { parent.appendChild(node); }
2366 fragments.each(iterator);
2368 element.outerHTML = content.stripScripts();
2371 content.evalScripts.bind(content).defer();
2375 if ('outerHTML' in document.documentElement)
2376 replace = replace_IE;
2378 function isContent(content) {
2379 if (Object.isUndefined(content) || content === null) return false;
2381 if (Object.isString(content) || Object.isNumber(content)) return true;
2382 if (Object.isElement(content)) return true;
2383 if (content.toElement || content.toHTML) return true;
2388 function insertContentAt(element, content, position) {
2389 position = position.toLowerCase();
2390 var method = INSERTION_TRANSLATIONS[position];
2392 if (content && content.toElement) content = content.toElement();
2393 if (Object.isElement(content)) {
2394 method(element, content);
2398 content = Object.toHTML(content);
2399 var tagName = ((position === 'before' || position === 'after') ?
2400 element.parentNode : element).tagName.toUpperCase();
2402 var childNodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2404 if (position === 'top' || position === 'after') childNodes.reverse();
2406 for (var i = 0, node; node = childNodes[i]; i++)
2407 method(element, node);
2409 content.evalScripts.bind(content).defer();
2412 function insert(element, insertions) {
2413 element = $(element);
2415 if (isContent(insertions))
2416 insertions = { bottom: insertions };
2418 for (var position in insertions)
2419 insertContentAt(element, insertions[position], position);
2424 function wrap(element, wrapper, attributes) {
2425 element = $(element);
2427 if (Object.isElement(wrapper)) {
2428 $(wrapper).writeAttribute(attributes || {});
2429 } else if (Object.isString(wrapper)) {
2430 wrapper = new Element(wrapper, attributes);
2432 wrapper = new Element('div', wrapper);
2435 if (element.parentNode)
2436 element.parentNode.replaceChild(wrapper, element);
2438 wrapper.appendChild(element);
2443 function cleanWhitespace(element) {
2444 element = $(element);
2445 var node = element.firstChild;
2448 var nextNode = node.nextSibling;
2449 if (node.nodeType === Node.TEXT_NODE && !/\S/.test(node.nodeValue))
2450 element.removeChild(node);
2456 function empty(element) {
2457 return $(element).innerHTML.blank();
2460 function getContentFromAnonymousElement(tagName, html, force) {
2461 var t = INSERTION_TRANSLATIONS.tags[tagName], div = DIV;
2463 var workaround = !!t;
2464 if (!workaround && force) {
2470 div.innerHTML = ' ' + t[0] + html + t[1];
2471 div.removeChild(div.firstChild);
2472 for (var i = t[2]; i--; )
2473 div = div.firstChild;
2475 div.innerHTML = html;
2478 return $A(div.childNodes);
2481 function clone(element, deep) {
2482 if (!(element = $(element))) return;
2483 var clone = element.cloneNode(deep);
2484 if (!HAS_UNIQUE_ID_PROPERTY) {
2485 clone._prototypeUID = UNDEFINED;
2487 var descendants = Element.select(clone, '*'),
2488 i = descendants.length;
2490 descendants[i]._prototypeUID = UNDEFINED;
2493 return Element.extend(clone);
2496 function purgeElement(element) {
2497 var uid = getUniqueElementID(element);
2499 Element.stopObserving(element);
2500 if (!HAS_UNIQUE_ID_PROPERTY)
2501 element._prototypeUID = UNDEFINED;
2502 delete Element.Storage[uid];
2506 function purgeCollection(elements) {
2507 var i = elements.length;
2509 purgeElement(elements[i]);
2512 function purgeCollection_IE(elements) {
2513 var i = elements.length, element, uid;
2515 element = elements[i];
2516 uid = getUniqueElementID(element);
2517 delete Element.Storage[uid];
2518 delete Event.cache[uid];
2522 if (HAS_UNIQUE_ID_PROPERTY) {
2523 purgeCollection = purgeCollection_IE;
2527 function purge(element) {
2528 if (!(element = $(element))) return;
2529 purgeElement(element);
2531 var descendants = element.getElementsByTagName('*'),
2532 i = descendants.length;
2534 while (i--) purgeElement(descendants[i]);
2539 Object.extend(methods, {
2545 cleanWhitespace: cleanWhitespace,
2553 function recursivelyCollect(element, property, maximumLength) {
2554 element = $(element);
2555 maximumLength = maximumLength || -1;
2558 while (element = element[property]) {
2559 if (element.nodeType === Node.ELEMENT_NODE)
2560 elements.push(Element.extend(element));
2562 if (elements.length === maximumLength) break;
2569 function ancestors(element) {
2570 return recursivelyCollect(element, 'parentNode');
2573 function descendants(element) {
2574 return Element.select(element, '*');
2577 function firstDescendant(element) {
2578 element = $(element).firstChild;
2579 while (element && element.nodeType !== Node.ELEMENT_NODE)
2580 element = element.nextSibling;
2585 function immediateDescendants(element) {
2586 var results = [], child = $(element).firstChild;
2589 if (child.nodeType === Node.ELEMENT_NODE)
2590 results.push(Element.extend(child));
2592 child = child.nextSibling;
2598 function previousSiblings(element) {
2599 return recursivelyCollect(element, 'previousSibling');
2602 function nextSiblings(element) {
2603 return recursivelyCollect(element, 'nextSibling');
2606 function siblings(element) {
2607 element = $(element);
2608 var previous = previousSiblings(element),
2609 next = nextSiblings(element);
2610 return previous.reverse().concat(next);
2613 function match(element, selector) {
2614 element = $(element);
2616 if (Object.isString(selector))
2617 return Prototype.Selector.match(element, selector);
2619 return selector.match(element);
2623 function _recursivelyFind(element, property, expression, index) {
2624 element = $(element), expression = expression || 0, index = index || 0;
2625 if (Object.isNumber(expression)) {
2626 index = expression, expression = null;
2629 while (element = element[property]) {
2630 if (element.nodeType !== 1) continue;
2631 if (expression && !Prototype.Selector.match(element, expression))
2633 if (--index >= 0) continue;
2635 return Element.extend(element);
2640 function up(element, expression, index) {
2641 element = $(element);
2643 if (arguments.length === 1) return $(element.parentNode);
2644 return _recursivelyFind(element, 'parentNode', expression, index);
2647 function down(element, expression, index) {
2648 if (arguments.length === 1) return firstDescendant(element);
2649 element = $(element), expression = expression || 0, index = index || 0;
2651 if (Object.isNumber(expression))
2652 index = expression, expression = '*';
2654 var node = Prototype.Selector.select(expression, element)[index];
2655 return Element.extend(node);
2658 function previous(element, expression, index) {
2659 return _recursivelyFind(element, 'previousSibling', expression, index);
2662 function next(element, expression, index) {
2663 return _recursivelyFind(element, 'nextSibling', expression, index);
2666 function select(element) {
2667 element = $(element);
2668 var expressions = SLICE.call(arguments, 1).join(', ');
2669 return Prototype.Selector.select(expressions, element);
2672 function adjacent(element) {
2673 element = $(element);
2674 var expressions = SLICE.call(arguments, 1).join(', ');
2675 var siblings = Element.siblings(element), results = [];
2676 for (var i = 0, sibling; sibling = siblings[i]; i++) {
2677 if (Prototype.Selector.match(sibling, expressions))
2678 results.push(sibling);
2684 function descendantOf_DOM(element, ancestor) {
2685 element = $(element), ancestor = $(ancestor);
2686 while (element = element.parentNode)
2687 if (element === ancestor) return true;
2691 function descendantOf_contains(element, ancestor) {
2692 element = $(element), ancestor = $(ancestor);
2693 if (!ancestor.contains) return descendantOf_DOM(element, ancestor);
2694 return ancestor.contains(element) && ancestor !== element;
2697 function descendantOf_compareDocumentPosition(element, ancestor) {
2698 element = $(element), ancestor = $(ancestor);
2699 return (element.compareDocumentPosition(ancestor) & 8) === 8;
2703 if (DIV.compareDocumentPosition) {
2704 descendantOf = descendantOf_compareDocumentPosition;
2705 } else if (DIV.contains) {
2706 descendantOf = descendantOf_contains;
2708 descendantOf = descendantOf_DOM;
2712 Object.extend(methods, {
2713 recursivelyCollect: recursivelyCollect,
2714 ancestors: ancestors,
2715 descendants: descendants,
2716 firstDescendant: firstDescendant,
2717 immediateDescendants: immediateDescendants,
2718 previousSiblings: previousSiblings,
2719 nextSiblings: nextSiblings,
2728 descendantOf: descendantOf,
2730 getElementsBySelector: select,
2732 childElements: immediateDescendants
2737 function identify(element) {
2738 element = $(element);
2739 var id = Element.readAttribute(element, 'id');
2742 do { id = 'anonymous_element_' + idCounter++ } while ($(id));
2744 Element.writeAttribute(element, 'id', id);
2749 function readAttribute(element, name) {
2750 return $(element).getAttribute(name);
2753 function readAttribute_IE(element, name) {
2754 element = $(element);
2756 var table = ATTRIBUTE_TRANSLATIONS.read;
2757 if (table.values[name])
2758 return table.values[name](element, name);
2760 if (table.names[name]) name = table.names[name];
2762 if (name.include(':')) {
2763 if (!element.attributes || !element.attributes[name]) return null;
2764 return element.attributes[name].value;
2767 return element.getAttribute(name);
2770 function readAttribute_Opera(element, name) {
2771 if (name === 'title') return element.title;
2772 return element.getAttribute(name);
2775 var PROBLEMATIC_ATTRIBUTE_READING = (function() {
2776 DIV.setAttribute('onclick', []);
2777 var value = DIV.getAttribute('onclick');
2778 var isFunction = Object.isArray(value);
2779 DIV.removeAttribute('onclick');
2783 if (PROBLEMATIC_ATTRIBUTE_READING) {
2784 readAttribute = readAttribute_IE;
2785 } else if (Prototype.Browser.Opera) {
2786 readAttribute = readAttribute_Opera;
2790 function writeAttribute(element, name, value) {
2791 element = $(element);
2792 var attributes = {}, table = ATTRIBUTE_TRANSLATIONS.write;
2794 if (typeof name === 'object') {
2797 attributes[name] = Object.isUndefined(value) ? true : value;
2800 for (var attr in attributes) {
2801 name = table.names[attr] || attr;
2802 value = attributes[attr];
2803 if (table.values[attr])
2804 name = table.values[attr](element, value) || name;
2805 if (value === false || value === null)
2806 element.removeAttribute(name);
2807 else if (value === true)
2808 element.setAttribute(name, name);
2809 else element.setAttribute(name, value);
2815 var PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES = (function () {
2816 if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) {
2819 var checkbox = document.createElement('<input type="checkbox">');
2820 checkbox.checked = true;
2821 var node = checkbox.getAttributeNode('checked');
2822 return !node || !node.specified;
2825 function hasAttribute(element, attribute) {
2826 attribute = ATTRIBUTE_TRANSLATIONS.has[attribute] || attribute;
2827 var node = $(element).getAttributeNode(attribute);
2828 return !!(node && node.specified);
2831 function hasAttribute_IE(element, attribute) {
2832 if (attribute === 'checked') {
2833 return element.checked;
2835 return hasAttribute(element, attribute);
2838 GLOBAL.Element.Methods.Simulated.hasAttribute =
2839 PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES ?
2840 hasAttribute_IE : hasAttribute;
2842 function classNames(element) {
2843 return new Element.ClassNames(element);
2846 var regExpCache = {};
2847 function getRegExpForClassName(className) {
2848 if (regExpCache[className]) return regExpCache[className];
2850 var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
2851 regExpCache[className] = re;
2855 function hasClassName(element, className) {
2856 if (!(element = $(element))) return;
2858 var elementClassName = element.className;
2860 if (elementClassName.length === 0) return false;
2861 if (elementClassName === className) return true;
2863 return getRegExpForClassName(className).test(elementClassName);
2866 function addClassName(element, className) {
2867 if (!(element = $(element))) return;
2869 if (!hasClassName(element, className))
2870 element.className += (element.className ? ' ' : '') + className;
2875 function removeClassName(element, className) {
2876 if (!(element = $(element))) return;
2878 element.className = element.className.replace(
2879 getRegExpForClassName(className), ' ').strip();
2884 function toggleClassName(element, className, bool) {
2885 if (!(element = $(element))) return;
2887 if (Object.isUndefined(bool))
2888 bool = !hasClassName(element, className);
2890 var method = Element[bool ? 'addClassName' : 'removeClassName'];
2891 return method(element, className);
2894 var ATTRIBUTE_TRANSLATIONS = {};
2896 var classProp = 'className', forProp = 'for';
2898 DIV.setAttribute(classProp, 'x');
2899 if (DIV.className !== 'x') {
2900 DIV.setAttribute('class', 'x');
2901 if (DIV.className === 'x')
2902 classProp = 'class';
2905 var LABEL = document.createElement('label');
2906 LABEL.setAttribute(forProp, 'x');
2907 if (LABEL.htmlFor !== 'x') {
2908 LABEL.setAttribute('htmlFor', 'x');
2909 if (LABEL.htmlFor === 'x')
2910 forProp = 'htmlFor';
2914 function _getAttr(element, attribute) {
2915 return element.getAttribute(attribute);
2918 function _getAttr2(element, attribute) {
2919 return element.getAttribute(attribute, 2);
2922 function _getAttrNode(element, attribute) {
2923 var node = element.getAttributeNode(attribute);
2924 return node ? node.value : '';
2927 function _getFlag(element, attribute) {
2928 return $(element).hasAttribute(attribute) ? attribute : null;
2931 DIV.onclick = Prototype.emptyFunction;
2932 var onclickValue = DIV.getAttribute('onclick');
2936 if (String(onclickValue).indexOf('{') > -1) {
2937 _getEv = function(element, attribute) {
2938 var value = element.getAttribute(attribute);
2939 if (!value) return null;
2940 value = value.toString();
2941 value = value.split('{')[1];
2942 value = value.split('}')[0];
2943 return value.strip();
2946 else if (onclickValue === '') {
2947 _getEv = function(element, attribute) {
2948 var value = element.getAttribute(attribute);
2949 if (!value) return null;
2950 return value.strip();
2954 ATTRIBUTE_TRANSLATIONS.read = {
2957 'className': classProp,
2963 style: function(element) {
2964 return element.style.cssText.toLowerCase();
2966 title: function(element) {
2967 return element.title;
2972 ATTRIBUTE_TRANSLATIONS.write = {
2976 cellpadding: 'cellPadding',
2977 cellspacing: 'cellSpacing'
2981 checked: function(element, value) {
2982 element.checked = !!value;
2985 style: function(element, value) {
2986 element.style.cssText = value ? value : '';
2991 ATTRIBUTE_TRANSLATIONS.has = { names: {} };
2993 Object.extend(ATTRIBUTE_TRANSLATIONS.write.names,
2994 ATTRIBUTE_TRANSLATIONS.read.names);
2996 var CAMEL_CASED_ATTRIBUTE_NAMES = $w('colSpan rowSpan vAlign dateTime ' +
2997 'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
2999 for (var i = 0, attr; attr = CAMEL_CASED_ATTRIBUTE_NAMES[i]; i++) {
3000 ATTRIBUTE_TRANSLATIONS.write.names[attr.toLowerCase()] = attr;
3001 ATTRIBUTE_TRANSLATIONS.has.names[attr.toLowerCase()] = attr;
3004 Object.extend(ATTRIBUTE_TRANSLATIONS.read.values, {
3008 action: _getAttrNode,
3017 onmousedown: _getEv,
3019 onmouseover: _getEv,
3020 onmousemove: _getEv,
3034 Object.extend(methods, {
3036 readAttribute: readAttribute,
3037 writeAttribute: writeAttribute,
3038 classNames: classNames,
3039 hasClassName: hasClassName,
3040 addClassName: addClassName,
3041 removeClassName: removeClassName,
3042 toggleClassName: toggleClassName
3046 function normalizeStyleName(style) {
3047 if (style === 'float' || style === 'styleFloat')
3049 return style.camelize();
3052 function normalizeStyleName_IE(style) {
3053 if (style === 'float' || style === 'cssFloat')
3054 return 'styleFloat';
3055 return style.camelize();
3058 function setStyle(element, styles) {
3059 element = $(element);
3060 var elementStyle = element.style, match;
3062 if (Object.isString(styles)) {
3063 elementStyle.cssText += ';' + styles;
3064 if (styles.include('opacity')) {
3065 var opacity = styles.match(/opacity:\s*(\d?\.?\d*)/)[1];
3066 Element.setOpacity(element, opacity);
3071 for (var property in styles) {
3072 if (property === 'opacity') {
3073 Element.setOpacity(element, styles[property]);
3075 var value = styles[property];
3076 if (property === 'float' || property === 'cssFloat') {
3077 property = Object.isUndefined(elementStyle.styleFloat) ?
3078 'cssFloat' : 'styleFloat';
3080 elementStyle[property] = value;
3088 function getStyle(element, style) {
3089 element = $(element);
3090 style = normalizeStyleName(style);
3092 var value = element.style[style];
3093 if (!value || value === 'auto') {
3094 var css = document.defaultView.getComputedStyle(element, null);
3095 value = css ? css[style] : null;
3098 if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3099 return value === 'auto' ? null : value;
3102 function getStyle_Opera(element, style) {
3104 case 'height': case 'width':
3105 if (!Element.visible(element)) return null;
3107 var dim = parseInt(getStyle(element, style), 10);
3109 if (dim !== element['offset' + style.capitalize()])
3112 return Element.measure(element, style);
3114 default: return getStyle(element, style);
3118 function getStyle_IE(element, style) {
3119 element = $(element);
3120 style = normalizeStyleName_IE(style);
3122 var value = element.style[style];
3123 if (!value && element.currentStyle) {
3124 value = element.currentStyle[style];
3127 if (style === 'opacity' && !STANDARD_CSS_OPACITY_SUPPORTED)
3128 return getOpacity_IE(element);
3130 if (value === 'auto') {
3131 if ((style === 'width' || style === 'height') && Element.visible(element))
3132 return Element.measure(element, style) + 'px';
3139 function stripAlphaFromFilter_IE(filter) {
3140 return (filter || '').replace(/alpha\([^\)]*\)/gi, '');
3143 function hasLayout_IE(element) {
3144 if (!element.currentStyle || !element.currentStyle.hasLayout)
3145 element.style.zoom = 1;
3149 var STANDARD_CSS_OPACITY_SUPPORTED = (function() {
3150 DIV.style.cssText = "opacity:.55";
3151 return /^0.55/.test(DIV.style.opacity);
3154 function setOpacity(element, value) {
3155 element = $(element);
3156 if (value == 1 || value === '') value = '';
3157 else if (value < 0.00001) value = 0;
3158 element.style.opacity = value;
3162 function setOpacity_IE(element, value) {
3163 if (STANDARD_CSS_OPACITY_SUPPORTED)
3164 return setOpacity(element, value);
3166 element = hasLayout_IE($(element));
3167 var filter = Element.getStyle(element, 'filter'),
3168 style = element.style;
3170 if (value == 1 || value === '') {
3171 filter = stripAlphaFromFilter_IE(filter);
3172 if (filter) style.filter = filter;
3173 else style.removeAttribute('filter');
3177 if (value < 0.00001) value = 0;
3179 style.filter = stripAlphaFromFilter_IE(filter) +
3180 'alpha(opacity=' + (value * 100) + ')';
3186 function getOpacity(element) {
3187 return Element.getStyle(element, 'opacity');
3190 function getOpacity_IE(element) {
3191 if (STANDARD_CSS_OPACITY_SUPPORTED)
3192 return getOpacity(element);
3194 var filter = Element.getStyle(element, 'filter');
3195 if (filter.length === 0) return 1.0;
3196 var match = (filter || '').match(/alpha\(opacity=(.*)\)/);
3197 if (match && match[1]) return parseFloat(match[1]) / 100;
3202 Object.extend(methods, {
3205 setOpacity: setOpacity,
3206 getOpacity: getOpacity
3209 if ('styleFloat' in DIV.style) {
3210 methods.getStyle = getStyle_IE;
3211 methods.setOpacity = setOpacity_IE;
3212 methods.getOpacity = getOpacity_IE;
3217 GLOBAL.Element.Storage = { UID: 1 };
3219 function getUniqueElementID(element) {
3220 if (element === window) return 0;
3222 if (typeof element._prototypeUID === 'undefined')
3223 element._prototypeUID = Element.Storage.UID++;
3224 return element._prototypeUID;
3227 function getUniqueElementID_IE(element) {
3228 if (element === window) return 0;
3229 if (element == document) return 1;
3230 return element.uniqueID;
3233 var HAS_UNIQUE_ID_PROPERTY = ('uniqueID' in DIV);
3234 if (HAS_UNIQUE_ID_PROPERTY)
3235 getUniqueElementID = getUniqueElementID_IE;
3237 function getStorage(element) {
3238 if (!(element = $(element))) return;
3240 var uid = getUniqueElementID(element);
3242 if (!Element.Storage[uid])
3243 Element.Storage[uid] = $H();
3245 return Element.Storage[uid];
3248 function store(element, key, value) {
3249 if (!(element = $(element))) return;
3250 var storage = getStorage(element);
3251 if (arguments.length === 2) {
3252 storage.update(key);
3254 storage.set(key, value);
3259 function retrieve(element, key, defaultValue) {
3260 if (!(element = $(element))) return;
3261 var storage = getStorage(element), value = storage.get(key);
3263 if (Object.isUndefined(value)) {
3264 storage.set(key, defaultValue);
3265 value = defaultValue;
3272 Object.extend(methods, {
3273 getStorage: getStorage,
3279 var Methods = {}, ByTag = Element.Methods.ByTag,
3280 F = Prototype.BrowserFeatures;
3282 if (!F.ElementExtensions && ('__proto__' in DIV)) {
3283 GLOBAL.HTMLElement = {};
3284 GLOBAL.HTMLElement.prototype = DIV['__proto__'];
3285 F.ElementExtensions = true;
3288 function checkElementPrototypeDeficiency(tagName) {
3289 if (typeof window.Element === 'undefined') return false;
3290 if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) return false;
3291 var proto = window.Element.prototype;
3293 var id = '_' + (Math.random() + '').slice(2),
3294 el = document.createElement(tagName);
3296 var isBuggy = (el[id] !== 'x');
3305 var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY =
3306 checkElementPrototypeDeficiency('object');
3308 function extendElementWith(element, methods) {
3309 for (var property in methods) {
3310 var value = methods[property];
3311 if (Object.isFunction(value) && !(property in element))
3312 element[property] = value.methodize();
3317 function elementIsExtended(element) {
3318 var uid = getUniqueElementID(element);
3319 return (uid in EXTENDED);
3322 function extend(element) {
3323 if (!element || elementIsExtended(element)) return element;
3324 if (element.nodeType !== Node.ELEMENT_NODE || element == window)
3327 var methods = Object.clone(Methods),
3328 tagName = element.tagName.toUpperCase();
3330 if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
3332 extendElementWith(element, methods);
3333 EXTENDED[getUniqueElementID(element)] = true;
3337 function extend_IE8(element) {
3338 if (!element || elementIsExtended(element)) return element;
3340 var t = element.tagName;
3341 if (t && (/^(?:object|applet|embed)$/i.test(t))) {
3342 extendElementWith(element, Element.Methods);
3343 extendElementWith(element, Element.Methods.Simulated);
3344 extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
3350 if (F.SpecificElementExtensions) {
3351 extend = HTMLOBJECTELEMENT_PROTOTYPE_BUGGY ? extend_IE8 : Prototype.K;
3354 function addMethodsToTagName(tagName, methods) {
3355 tagName = tagName.toUpperCase();
3356 if (!ByTag[tagName]) ByTag[tagName] = {};
3357 Object.extend(ByTag[tagName], methods);
3360 function mergeMethods(destination, methods, onlyIfAbsent) {
3361 if (Object.isUndefined(onlyIfAbsent)) onlyIfAbsent = false;
3362 for (var property in methods) {
3363 var value = methods[property];
3364 if (!Object.isFunction(value)) continue;
3365 if (!onlyIfAbsent || !(property in destination))
3366 destination[property] = value.methodize();
3370 function findDOMClass(tagName) {
3373 "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3374 "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3375 "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3376 "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3377 "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3378 "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3379 "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3380 "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3381 "FrameSet", "IFRAME": "IFrame"
3383 if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
3384 if (window[klass]) return window[klass];
3385 klass = 'HTML' + tagName + 'Element';
3386 if (window[klass]) return window[klass];
3387 klass = 'HTML' + tagName.capitalize() + 'Element';
3388 if (window[klass]) return window[klass];
3390 var element = document.createElement(tagName),
3391 proto = element['__proto__'] || element.constructor.prototype;
3397 function addMethods(methods) {
3398 if (arguments.length === 0) addFormMethods();
3400 if (arguments.length === 2) {
3401 var tagName = methods;
3402 methods = arguments[1];
3406 Object.extend(Element.Methods, methods || {});
3408 if (Object.isArray(tagName)) {
3409 for (var i = 0, tag; tag = tagName[i]; i++)
3410 addMethodsToTagName(tag, methods);
3412 addMethodsToTagName(tagName, methods);
3416 var ELEMENT_PROTOTYPE = window.HTMLElement ? HTMLElement.prototype :
3419 if (F.ElementExtensions) {
3420 mergeMethods(ELEMENT_PROTOTYPE, Element.Methods);
3421 mergeMethods(ELEMENT_PROTOTYPE, Element.Methods.Simulated, true);
3424 if (F.SpecificElementExtensions) {
3425 for (var tag in Element.Methods.ByTag) {
3426 var klass = findDOMClass(tag);
3427 if (Object.isUndefined(klass)) continue;
3428 mergeMethods(klass.prototype, ByTag[tag]);
3432 Object.extend(Element, Element.Methods);
3433 Object.extend(Element, Element.Methods.Simulated);
3434 delete Element.ByTag;
3435 delete Element.Simulated;
3437 Element.extend.refresh();
3442 Object.extend(GLOBAL.Element, {
3444 addMethods: addMethods
3447 if (extend === Prototype.K) {
3448 GLOBAL.Element.extend.refresh = Prototype.emptyFunction;
3450 GLOBAL.Element.extend.refresh = function() {
3451 if (Prototype.BrowserFeatures.ElementExtensions) return;
3452 Object.extend(Methods, Element.Methods);
3453 Object.extend(Methods, Element.Methods.Simulated);
3459 function addFormMethods() {
3460 Object.extend(Form, Form.Methods);
3461 Object.extend(Form.Element, Form.Element.Methods);
3462 Object.extend(Element.Methods.ByTag, {
3463 "FORM": Object.clone(Form.Methods),
3464 "INPUT": Object.clone(Form.Element.Methods),
3465 "SELECT": Object.clone(Form.Element.Methods),
3466 "TEXTAREA": Object.clone(Form.Element.Methods),
3467 "BUTTON": Object.clone(Form.Element.Methods)
3471 Element.addMethods(methods);
3473 function destroyCache_IE() {
3475 ELEMENT_CACHE = null;
3478 if (window.attachEvent)
3479 window.attachEvent('onunload', destroyCache_IE);
3484 function toDecimal(pctString) {
3485 var match = pctString.match(/^(\d+)%?$/i);
3486 if (!match) return null;
3487 return (Number(match[1]) / 100);
3490 function getRawStyle(element, style) {
3491 element = $(element);
3493 var value = element.style[style];
3494 if (!value || value === 'auto') {
3495 var css = document.defaultView.getComputedStyle(element, null);
3496 value = css ? css[style] : null;
3499 if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3500 return value === 'auto' ? null : value;
3503 function getRawStyle_IE(element, style) {
3504 var value = element.style[style];
3505 if (!value && element.currentStyle) {
3506 value = element.currentStyle[style];
3511 function getContentWidth(element, context) {
3512 var boxWidth = element.offsetWidth;
3514 var bl = getPixelValue(element, 'borderLeftWidth', context) || 0;
3515 var br = getPixelValue(element, 'borderRightWidth', context) || 0;
3516 var pl = getPixelValue(element, 'paddingLeft', context) || 0;
3517 var pr = getPixelValue(element, 'paddingRight', context) || 0;
3519 return boxWidth - bl - br - pl - pr;
3522 if ('currentStyle' in document.documentElement) {
3523 getRawStyle = getRawStyle_IE;
3527 function getPixelValue(value, property, context) {
3529 if (Object.isElement(value)) {
3531 value = getRawStyle(element, property);
3534 if (value === null || Object.isUndefined(value)) {
3538 if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
3539 return window.parseFloat(value);
3542 var isPercentage = value.include('%'), isViewport = (context === document.viewport);
3544 if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
3545 var style = element.style.left, rStyle = element.runtimeStyle.left;
3546 element.runtimeStyle.left = element.currentStyle.left;
3547 element.style.left = value || 0;
3548 value = element.style.pixelLeft;
3549 element.style.left = style;
3550 element.runtimeStyle.left = rStyle;
3555 if (element && isPercentage) {
3556 context = context || element.parentNode;
3557 var decimal = toDecimal(value), whole = null;
3559 var isHorizontal = property.include('left') || property.include('right') ||
3560 property.include('width');
3562 var isVertical = property.include('top') || property.include('bottom') ||
3563 property.include('height');
3565 if (context === document.viewport) {
3567 whole = document.viewport.getWidth();
3568 } else if (isVertical) {
3569 whole = document.viewport.getHeight();
3573 whole = $(context).measure('width');
3574 } else if (isVertical) {
3575 whole = $(context).measure('height');
3579 return (whole === null) ? 0 : whole * decimal;
3585 function toCSSPixels(number) {
3586 if (Object.isString(number) && number.endsWith('px'))
3588 return number + 'px';
3591 function isDisplayed(element) {
3592 while (element && element.parentNode) {
3593 var display = element.getStyle('display');
3594 if (display === 'none') {
3597 element = $(element.parentNode);
3602 var hasLayout = Prototype.K;
3603 if ('currentStyle' in document.documentElement) {
3604 hasLayout = function(element) {
3605 if (!element.currentStyle.hasLayout) {
3606 element.style.zoom = 1;
3612 function cssNameFor(key) {
3613 if (key.include('border')) key = key + '-width';
3614 return key.camelize();
3617 Element.Layout = Class.create(Hash, {
3618 initialize: function($super, element, preCompute) {
3620 this.element = $(element);
3622 Element.Layout.PROPERTIES.each( function(property) {
3623 this._set(property, null);
3627 this._preComputing = true;
3629 Element.Layout.PROPERTIES.each( this._compute, this );
3631 this._preComputing = false;
3635 _set: function(property, value) {
3636 return Hash.prototype.set.call(this, property, value);
3639 set: function(property, value) {
3640 throw "Properties of Element.Layout are read-only.";
3643 get: function($super, property) {
3644 var value = $super(property);
3645 return value === null ? this._compute(property) : value;
3648 _begin: function() {
3649 if (this._isPrepared()) return;
3651 var element = this.element;
3652 if (isDisplayed(element)) {
3653 this._setPrepared(true);
3658 var originalStyles = {
3659 position: element.style.position || '',
3660 width: element.style.width || '',
3661 visibility: element.style.visibility || '',
3662 display: element.style.display || ''
3665 element.store('prototype_original_styles', originalStyles);
3667 var position = getRawStyle(element, 'position'), width = element.offsetWidth;
3669 if (width === 0 || width === null) {
3670 element.style.display = 'block';
3671 width = element.offsetWidth;
3674 var context = (position === 'fixed') ? document.viewport :
3678 visibility: 'hidden',
3682 if (position !== 'fixed') tempStyles.position = 'absolute';
3684 element.setStyle(tempStyles);
3686 var positionedWidth = element.offsetWidth, newWidth;
3687 if (width && (positionedWidth === width)) {
3688 newWidth = getContentWidth(element, context);
3689 } else if (position === 'absolute' || position === 'fixed') {
3690 newWidth = getContentWidth(element, context);
3692 var parent = element.parentNode, pLayout = $(parent).getLayout();
3694 newWidth = pLayout.get('width') -
3695 this.get('margin-left') -
3696 this.get('border-left') -
3697 this.get('padding-left') -
3698 this.get('padding-right') -
3699 this.get('border-right') -
3700 this.get('margin-right');
3703 element.setStyle({ width: newWidth + 'px' });
3705 this._setPrepared(true);
3709 var element = this.element;
3710 var originalStyles = element.retrieve('prototype_original_styles');
3711 element.store('prototype_original_styles', null);
3712 element.setStyle(originalStyles);
3713 this._setPrepared(false);
3716 _compute: function(property) {
3717 var COMPUTATIONS = Element.Layout.COMPUTATIONS;
3718 if (!(property in COMPUTATIONS)) {
3719 throw "Property not found.";
3722 return this._set(property, COMPUTATIONS[property].call(this, this.element));
3725 _isPrepared: function() {
3726 return this.element.retrieve('prototype_element_layout_prepared', false);
3729 _setPrepared: function(bool) {
3730 return this.element.store('prototype_element_layout_prepared', bool);
3733 toObject: function() {
3734 var args = $A(arguments);
3735 var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3736 args.join(' ').split(' ');
3738 keys.each( function(key) {
3739 if (!Element.Layout.PROPERTIES.include(key)) return;
3740 var value = this.get(key);
3741 if (value != null) obj[key] = value;
3746 toHash: function() {
3747 var obj = this.toObject.apply(this, arguments);
3748 return new Hash(obj);
3752 var args = $A(arguments);
3753 var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3754 args.join(' ').split(' ');
3757 keys.each( function(key) {
3758 if (!Element.Layout.PROPERTIES.include(key)) return;
3759 if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
3761 var value = this.get(key);
3762 if (value != null) css[cssNameFor(key)] = value + 'px';
3767 inspect: function() {
3768 return "#<Element.Layout>";
3772 Object.extend(Element.Layout, {
3773 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'),
3775 COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3778 'height': function(element) {
3779 if (!this._preComputing) this._begin();
3781 var bHeight = this.get('border-box-height');
3783 if (!this._preComputing) this._end();
3787 var bTop = this.get('border-top'),
3788 bBottom = this.get('border-bottom');
3790 var pTop = this.get('padding-top'),
3791 pBottom = this.get('padding-bottom');
3793 if (!this._preComputing) this._end();
3795 return bHeight - bTop - bBottom - pTop - pBottom;
3798 'width': function(element) {
3799 if (!this._preComputing) this._begin();
3801 var bWidth = this.get('border-box-width');
3803 if (!this._preComputing) this._end();
3807 var bLeft = this.get('border-left'),
3808 bRight = this.get('border-right');
3810 var pLeft = this.get('padding-left'),
3811 pRight = this.get('padding-right');
3813 if (!this._preComputing) this._end();
3814 return bWidth - bLeft - bRight - pLeft - pRight;
3817 'padding-box-height': function(element) {
3818 var height = this.get('height'),
3819 pTop = this.get('padding-top'),
3820 pBottom = this.get('padding-bottom');
3822 return height + pTop + pBottom;
3825 'padding-box-width': function(element) {
3826 var width = this.get('width'),
3827 pLeft = this.get('padding-left'),
3828 pRight = this.get('padding-right');
3830 return width + pLeft + pRight;
3833 'border-box-height': function(element) {
3834 if (!this._preComputing) this._begin();
3835 var height = element.offsetHeight;
3836 if (!this._preComputing) this._end();
3840 'border-box-width': function(element) {
3841 if (!this._preComputing) this._begin();
3842 var width = element.offsetWidth;
3843 if (!this._preComputing) this._end();
3847 'margin-box-height': function(element) {
3848 var bHeight = this.get('border-box-height'),
3849 mTop = this.get('margin-top'),
3850 mBottom = this.get('margin-bottom');
3852 if (bHeight <= 0) return 0;
3854 return bHeight + mTop + mBottom;
3857 'margin-box-width': function(element) {
3858 var bWidth = this.get('border-box-width'),
3859 mLeft = this.get('margin-left'),
3860 mRight = this.get('margin-right');
3862 if (bWidth <= 0) return 0;
3864 return bWidth + mLeft + mRight;
3867 'top': function(element) {
3868 var offset = element.positionedOffset();
3872 'bottom': function(element) {
3873 var offset = element.positionedOffset(),
3874 parent = element.getOffsetParent(),
3875 pHeight = parent.measure('height');
3877 var mHeight = this.get('border-box-height');
3879 return pHeight - mHeight - offset.top;
3882 'left': function(element) {
3883 var offset = element.positionedOffset();
3887 'right': function(element) {
3888 var offset = element.positionedOffset(),
3889 parent = element.getOffsetParent(),
3890 pWidth = parent.measure('width');
3892 var mWidth = this.get('border-box-width');
3894 return pWidth - mWidth - offset.left;
3897 'padding-top': function(element) {
3898 return getPixelValue(element, 'paddingTop');
3901 'padding-bottom': function(element) {
3902 return getPixelValue(element, 'paddingBottom');
3905 'padding-left': function(element) {
3906 return getPixelValue(element, 'paddingLeft');
3909 'padding-right': function(element) {
3910 return getPixelValue(element, 'paddingRight');
3913 'border-top': function(element) {
3914 return getPixelValue(element, 'borderTopWidth');
3917 'border-bottom': function(element) {
3918 return getPixelValue(element, 'borderBottomWidth');
3921 'border-left': function(element) {
3922 return getPixelValue(element, 'borderLeftWidth');
3925 'border-right': function(element) {
3926 return getPixelValue(element, 'borderRightWidth');
3929 'margin-top': function(element) {
3930 return getPixelValue(element, 'marginTop');
3933 'margin-bottom': function(element) {
3934 return getPixelValue(element, 'marginBottom');
3937 'margin-left': function(element) {
3938 return getPixelValue(element, 'marginLeft');
3941 'margin-right': function(element) {
3942 return getPixelValue(element, 'marginRight');
3947 if ('getBoundingClientRect' in document.documentElement) {
3948 Object.extend(Element.Layout.COMPUTATIONS, {
3949 'right': function(element) {
3950 var parent = hasLayout(element.getOffsetParent());
3951 var rect = element.getBoundingClientRect(),
3952 pRect = parent.getBoundingClientRect();
3954 return (pRect.right - rect.right).round();
3957 'bottom': function(element) {
3958 var parent = hasLayout(element.getOffsetParent());
3959 var rect = element.getBoundingClientRect(),
3960 pRect = parent.getBoundingClientRect();
3962 return (pRect.bottom - rect.bottom).round();
3967 Element.Offset = Class.create({
3968 initialize: function(left, top) {
3969 this.left = left.round();
3970 this.top = top.round();
3972 this[0] = this.left;
3976 relativeTo: function(offset) {
3977 return new Element.Offset(
3978 this.left - offset.left,
3979 this.top - offset.top
3983 inspect: function() {
3984 return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3987 toString: function() {
3988 return "[#{left}, #{top}]".interpolate(this);
3991 toArray: function() {
3992 return [this.left, this.top];
3996 function getLayout(element, preCompute) {
3997 return new Element.Layout(element, preCompute);
4000 function measure(element, property) {
4001 return $(element).getLayout().get(property);
4004 function getHeight(element) {
4005 return Element.getDimensions(element).height;
4008 function getWidth(element) {
4009 return Element.getDimensions(element).width;
4012 function getDimensions(element) {
4013 element = $(element);
4014 var display = Element.getStyle(element, 'display');
4016 if (display && display !== 'none') {
4017 return { width: element.offsetWidth, height: element.offsetHeight };
4020 var style = element.style;
4021 var originalStyles = {
4022 visibility: style.visibility,
4023 position: style.position,
4024 display: style.display
4028 visibility: 'hidden',
4032 if (originalStyles.position !== 'fixed')
4033 newStyles.position = 'absolute';
4035 Element.setStyle(element, newStyles);
4038 width: element.offsetWidth,
4039 height: element.offsetHeight
4042 Element.setStyle(element, originalStyles);
4047 function getOffsetParent(element) {
4048 element = $(element);
4050 if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4051 return $(document.body);
4053 var isInline = (Element.getStyle(element, 'display') === 'inline');
4054 if (!isInline && element.offsetParent) return $(element.offsetParent);
4056 while ((element = element.parentNode) && element !== document.body) {
4057 if (Element.getStyle(element, 'position') !== 'static') {
4058 return isHtml(element) ? $(document.body) : $(element);
4062 return $(document.body);
4066 function cumulativeOffset(element) {
4067 element = $(element);
4068 var valueT = 0, valueL = 0;
4069 if (element.parentNode) {
4071 valueT += element.offsetTop || 0;
4072 valueL += element.offsetLeft || 0;
4073 element = element.offsetParent;
4076 return new Element.Offset(valueL, valueT);
4079 function positionedOffset(element) {
4080 element = $(element);
4082 var layout = element.getLayout();
4084 var valueT = 0, valueL = 0;
4086 valueT += element.offsetTop || 0;
4087 valueL += element.offsetLeft || 0;
4088 element = element.offsetParent;
4090 if (isBody(element)) break;
4091 var p = Element.getStyle(element, 'position');
4092 if (p !== 'static') break;
4096 valueL -= layout.get('margin-top');
4097 valueT -= layout.get('margin-left');
4099 return new Element.Offset(valueL, valueT);
4102 function cumulativeScrollOffset(element) {
4103 var valueT = 0, valueL = 0;
4105 if (element === document.body) {
4106 var bodyScrollNode = document.documentElement || document.body.parentNode || document.body;
4107 valueT += !Object.isUndefined(window.pageYOffset) ? window.pageYOffset : bodyScrollNode.scrollTop || 0;
4108 valueL += !Object.isUndefined(window.pageXOffset) ? window.pageXOffset : bodyScrollNode.scrollLeft || 0;
4111 valueT += element.scrollTop || 0;
4112 valueL += element.scrollLeft || 0;
4113 element = element.parentNode;
4116 return new Element.Offset(valueL, valueT);
4119 function viewportOffset(forElement) {
4120 var valueT = 0, valueL = 0, docBody = document.body;
4122 forElement = $(forElement);
4123 var element = forElement;
4125 valueT += element.offsetTop || 0;
4126 valueL += element.offsetLeft || 0;
4127 if (element.offsetParent == docBody &&
4128 Element.getStyle(element, 'position') == 'absolute') break;
4129 } while (element = element.offsetParent);
4131 element = forElement;
4133 if (element != docBody) {
4134 valueT -= element.scrollTop || 0;
4135 valueL -= element.scrollLeft || 0;
4137 } while (element = element.parentNode);
4138 return new Element.Offset(valueL, valueT);
4141 function absolutize(element) {
4142 element = $(element);
4144 if (Element.getStyle(element, 'position') === 'absolute') {
4148 var offsetParent = getOffsetParent(element);
4149 var eOffset = element.viewportOffset(),
4150 pOffset = offsetParent.viewportOffset();
4152 var offset = eOffset.relativeTo(pOffset);
4153 var layout = element.getLayout();
4155 element.store('prototype_absolutize_original_styles', {
4156 position: element.getStyle('position'),
4157 left: element.getStyle('left'),
4158 top: element.getStyle('top'),
4159 width: element.getStyle('width'),
4160 height: element.getStyle('height')
4164 position: 'absolute',
4165 top: offset.top + 'px',
4166 left: offset.left + 'px',
4167 width: layout.get('width') + 'px',
4168 height: layout.get('height') + 'px'
4174 function relativize(element) {
4175 element = $(element);
4176 if (Element.getStyle(element, 'position') === 'relative') {
4180 var originalStyles =
4181 element.retrieve('prototype_absolutize_original_styles');
4183 if (originalStyles) element.setStyle(originalStyles);
4188 function scrollTo(element) {
4189 element = $(element);
4190 var pos = Element.cumulativeOffset(element);
4191 window.scrollTo(pos.left, pos.top);
4196 function makePositioned(element) {
4197 element = $(element);
4198 var position = Element.getStyle(element, 'position'), styles = {};
4199 if (position === 'static' || !position) {
4200 styles.position = 'relative';
4201 if (Prototype.Browser.Opera) {
4205 Element.setStyle(element, styles);
4206 Element.store(element, 'prototype_made_positioned', true);
4211 function undoPositioned(element) {
4212 element = $(element);
4213 var storage = Element.getStorage(element),
4214 madePositioned = storage.get('prototype_made_positioned');
4216 if (madePositioned) {
4217 storage.unset('prototype_made_positioned');
4218 Element.setStyle(element, {
4229 function makeClipping(element) {
4230 element = $(element);
4232 var storage = Element.getStorage(element),
4233 madeClipping = storage.get('prototype_made_clipping');
4235 if (Object.isUndefined(madeClipping)) {
4236 var overflow = Element.getStyle(element, 'overflow');
4237 storage.set('prototype_made_clipping', overflow);
4238 if (overflow !== 'hidden')
4239 element.style.overflow = 'hidden';
4245 function undoClipping(element) {
4246 element = $(element);
4247 var storage = Element.getStorage(element),
4248 overflow = storage.get('prototype_made_clipping');
4250 if (!Object.isUndefined(overflow)) {
4251 storage.unset('prototype_made_clipping');
4252 element.style.overflow = overflow || '';
4258 function clonePosition(element, source, options) {
4259 options = Object.extend({
4269 element = $(element);
4270 var p, delta, layout, styles = {};
4272 if (options.setLeft || options.setTop) {
4273 p = Element.viewportOffset(source);
4275 if (Element.getStyle(element, 'position') === 'absolute') {
4276 var parent = Element.getOffsetParent(element);
4277 if (parent !== document.body) delta = Element.viewportOffset(parent);
4281 if (options.setWidth || options.setHeight) {
4282 layout = Element.getLayout(source);
4285 if (options.setLeft)
4286 styles.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
4288 styles.top = (p[1] - delta[1] + options.offsetTop) + 'px';
4290 if (options.setWidth)
4291 styles.width = layout.get('border-box-width') + 'px';
4292 if (options.setHeight)
4293 styles.height = layout.get('border-box-height') + 'px';
4295 return Element.setStyle(element, styles);
4299 if (Prototype.Browser.IE) {
4300 getOffsetParent = getOffsetParent.wrap(
4301 function(proceed, element) {
4302 element = $(element);
4304 if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4305 return $(document.body);
4307 var position = element.getStyle('position');
4308 if (position !== 'static') return proceed(element);
4310 element.setStyle({ position: 'relative' });
4311 var value = proceed(element);
4312 element.setStyle({ position: position });
4317 positionedOffset = positionedOffset.wrap(function(proceed, element) {
4318 element = $(element);
4319 if (!element.parentNode) return new Element.Offset(0, 0);
4320 var position = element.getStyle('position');
4321 if (position !== 'static') return proceed(element);
4323 var offsetParent = element.getOffsetParent();
4324 if (offsetParent && offsetParent.getStyle('position') === 'fixed')
4325 hasLayout(offsetParent);
4327 element.setStyle({ position: 'relative' });
4328 var value = proceed(element);
4329 element.setStyle({ position: position });
4332 } else if (Prototype.Browser.Webkit) {
4333 cumulativeOffset = function(element) {
4334 element = $(element);
4335 var valueT = 0, valueL = 0;
4337 valueT += element.offsetTop || 0;
4338 valueL += element.offsetLeft || 0;
4339 if (element.offsetParent == document.body) {
4340 if (Element.getStyle(element, 'position') == 'absolute') break;
4343 element = element.offsetParent;
4346 return new Element.Offset(valueL, valueT);
4351 Element.addMethods({
4352 getLayout: getLayout,
4355 getHeight: getHeight,
4356 getDimensions: getDimensions,
4357 getOffsetParent: getOffsetParent,
4358 cumulativeOffset: cumulativeOffset,
4359 positionedOffset: positionedOffset,
4360 cumulativeScrollOffset: cumulativeScrollOffset,
4361 viewportOffset: viewportOffset,
4362 absolutize: absolutize,
4363 relativize: relativize,
4365 makePositioned: makePositioned,
4366 undoPositioned: undoPositioned,
4367 makeClipping: makeClipping,
4368 undoClipping: undoClipping,
4369 clonePosition: clonePosition
4372 function isBody(element) {
4373 return element.nodeName.toUpperCase() === 'BODY';
4376 function isHtml(element) {
4377 return element.nodeName.toUpperCase() === 'HTML';
4380 function isDocument(element) {
4381 return element.nodeType === Node.DOCUMENT_NODE;
4384 function isDetached(element) {
4385 return element !== document.body &&
4386 !Element.descendantOf(element, document.body);
4389 if ('getBoundingClientRect' in document.documentElement) {
4390 Element.addMethods({
4391 viewportOffset: function(element) {
4392 element = $(element);
4393 if (isDetached(element)) return new Element.Offset(0, 0);
4395 var rect = element.getBoundingClientRect(),
4396 docEl = document.documentElement;
4397 return new Element.Offset(rect.left - docEl.clientLeft,
4398 rect.top - docEl.clientTop);
4408 var IS_OLD_OPERA = Prototype.Browser.Opera &&
4409 (window.parseFloat(window.opera.version()) < 9.5);
4411 function getRootElement() {
4412 if (ROOT) return ROOT;
4413 ROOT = IS_OLD_OPERA ? document.body : document.documentElement;
4417 function getDimensions() {
4418 return { width: this.getWidth(), height: this.getHeight() };
4421 function getWidth() {
4422 return getRootElement().clientWidth;
4425 function getHeight() {
4426 return getRootElement().clientHeight;
4429 function getScrollOffsets() {
4430 var x = window.pageXOffset || document.documentElement.scrollLeft ||
4431 document.body.scrollLeft;
4432 var y = window.pageYOffset || document.documentElement.scrollTop ||
4433 document.body.scrollTop;
4435 return new Element.Offset(x, y);
4438 document.viewport = {
4439 getDimensions: getDimensions,
4441 getHeight: getHeight,
4442 getScrollOffsets: getScrollOffsets
4446window.$$ = function() {
4447 var expression = $A(arguments).join(', ');
4448 return Prototype.Selector.select(expression, document);
4451Prototype.Selector = (function() {
4454 throw new Error('Method "Prototype.Selector.select" must be defined.');
4458 throw new Error('Method "Prototype.Selector.match" must be defined.');
4461 function find(elements, expression, index) {
4463 var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
4465 for (i = 0; i < length; i++) {
4466 if (match(elements[i], expression) && index == matchIndex++) {
4467 return Element.extend(elements[i]);
4472 function extendElements(elements) {
4473 for (var i = 0, length = elements.length; i < length; i++) {
4474 Element.extend(elements[i]);
4480 var K = Prototype.K;
4486 extendElements: (Element.extend === K) ? K : extendElements,
4487 extendElement: Element.extend
4490Prototype._original_property = window.Sizzle;
4492 * Sizzle CSS Selector Engine v@VERSION
4493 * http://sizzlejs.com/
4495 * Copyright 2013 jQuery Foundation, Inc. and other contributors
4496 * Released under the MIT license
4497 * http://jquery.org/license
4501(function( window ) {
4523 expando = "sizzle" + -(new Date()),
4524 preferredDoc = window.document,
4527 classCache = createCache(),
4528 tokenCache = createCache(),
4529 compilerCache = createCache(),
4530 sortOrder = function( a, b ) {
4532 hasDuplicate = true;
4537 strundefined = typeof undefined,
4538 MAX_NEGATIVE = 1 << 31,
4540 hasOwn = ({}).hasOwnProperty,
4543 push_native = arr.push,
4546 indexOf = arr.indexOf || function( elem ) {
4549 for ( ; i < len; i++ ) {
4550 if ( this[i] === elem ) {
4557 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
4560 whitespace = "[\\x20\\t\\r\\n\\f]",
4561 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
4563 identifier = characterEncoding.replace( "w", "w#" ),
4565 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
4566 "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
4568 pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
4570 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
4572 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
4573 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
4575 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
4577 rpseudo = new RegExp( pseudos ),
4578 ridentifier = new RegExp( "^" + identifier + "$" ),
4581 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
4582 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
4583 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
4584 "ATTR": new RegExp( "^" + attributes ),
4585 "PSEUDO": new RegExp( "^" + pseudos ),
4586 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
4587 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
4588 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
4589 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
4590 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
4591 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
4594 rinputs = /^(?:input|select|textarea|button)$/i,
4597 rnative = /^[^{]+\{\s*\[native \w/,
4599 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
4604 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
4605 funescape = function( _, escaped, escapedWhitespace ) {
4606 var high = "0x" + escaped - 0x10000;
4607 return high !== high || escapedWhitespace ?
4610 String.fromCharCode( high + 0x10000 ) :
4611 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
4616 (arr = slice.call( preferredDoc.childNodes )),
4617 preferredDoc.childNodes
4619 arr[ preferredDoc.childNodes.length ].nodeType;
4621 push = { apply: arr.length ?
4623 function( target, els ) {
4624 push_native.apply( target, slice.call(els) );
4627 function( target, els ) {
4628 var j = target.length,
4630 while ( (target[j++] = els[i++]) ) {}
4631 target.length = j - 1;
4636function Sizzle( selector, context, results, seed ) {
4637 var match, elem, m, nodeType,
4638 i, groups, old, nid, newContext, newSelector;
4640 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
4641 setDocument( context );
4644 context = context || document;
4645 results = results || [];
4647 if ( !selector || typeof selector !== "string" ) {
4651 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
4655 if ( documentIsHTML && !seed ) {
4657 if ( (match = rquickExpr.exec( selector )) ) {
4658 if ( (m = match[1]) ) {
4659 if ( nodeType === 9 ) {
4660 elem = context.getElementById( m );
4661 if ( elem && elem.parentNode ) {
4662 if ( elem.id === m ) {
4663 results.push( elem );
4670 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
4671 contains( context, elem ) && elem.id === m ) {
4672 results.push( elem );
4677 } else if ( match[2] ) {
4678 push.apply( results, context.getElementsByTagName( selector ) );
4681 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
4682 push.apply( results, context.getElementsByClassName( m ) );
4687 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
4688 nid = old = expando;
4689 newContext = context;
4690 newSelector = nodeType === 9 && selector;
4692 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
4693 groups = tokenize( selector );
4695 if ( (old = context.getAttribute("id")) ) {
4696 nid = old.replace( rescape, "\\$&" );
4698 context.setAttribute( "id", nid );
4700 nid = "[id='" + nid + "'] ";
4704 groups[i] = nid + toSelector( groups[i] );
4706 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
4707 newSelector = groups.join(",");
4710 if ( newSelector ) {
4712 push.apply( results,
4713 newContext.querySelectorAll( newSelector )
4719 context.removeAttribute("id");
4726 return select( selector.replace( rtrim, "$1" ), context, results, seed );
4730 * Create key-value caches of limited size
4731 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
4732 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
4733 * deleting the oldest entry
4735function createCache() {
4738 function cache( key, value ) {
4739 if ( keys.push( key + " " ) > Expr.cacheLength ) {
4740 delete cache[ keys.shift() ];
4742 return (cache[ key + " " ] = value);
4748 * Mark a function for special use by Sizzle
4749 * @param {Function} fn The function to mark
4751function markFunction( fn ) {
4752 fn[ expando ] = true;
4757 * Support testing using an element
4758 * @param {Function} fn Passed the created div and expects a boolean result
4760function assert( fn ) {
4761 var div = document.createElement("div");
4768 if ( div.parentNode ) {
4769 div.parentNode.removeChild( div );
4776 * Adds the same handler for all of the specified attrs
4777 * @param {String} attrs Pipe-separated list of attributes
4778 * @param {Function} handler The method that will be applied
4780function addHandle( attrs, handler ) {
4781 var arr = attrs.split("|"),
4785 Expr.attrHandle[ arr[i] ] = handler;
4790 * Checks document order of two siblings
4791 * @param {Element} a
4792 * @param {Element} b
4793 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
4795function siblingCheck( a, b ) {
4797 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
4798 ( ~b.sourceIndex || MAX_NEGATIVE ) -
4799 ( ~a.sourceIndex || MAX_NEGATIVE );
4806 while ( (cur = cur.nextSibling) ) {
4817 * Returns a function to use in pseudos for input types
4818 * @param {String} type
4820function createInputPseudo( type ) {
4821 return function( elem ) {
4822 var name = elem.nodeName.toLowerCase();
4823 return name === "input" && elem.type === type;
4828 * Returns a function to use in pseudos for buttons
4829 * @param {String} type
4831function createButtonPseudo( type ) {
4832 return function( elem ) {
4833 var name = elem.nodeName.toLowerCase();
4834 return (name === "input" || name === "button") && elem.type === type;
4839 * Returns a function to use in pseudos for positionals
4840 * @param {Function} fn
4842function createPositionalPseudo( fn ) {
4843 return markFunction(function( argument ) {
4844 argument = +argument;
4845 return markFunction(function( seed, matches ) {
4847 matchIndexes = fn( [], seed.length, argument ),
4848 i = matchIndexes.length;
4851 if ( seed[ (j = matchIndexes[i]) ] ) {
4852 seed[j] = !(matches[j] = seed[j]);
4860 * Checks a node for validity as a Sizzle context
4861 * @param {Element|Object=} context
4862 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
4864function testContext( context ) {
4865 return context && typeof context.getElementsByTagName !== strundefined && context;
4868support = Sizzle.support = {};
4872 * @param {Element|Object} elem An element or a document
4873 * @returns {Boolean} True iff elem is a non-HTML XML node
4875isXML = Sizzle.isXML = function( elem ) {
4876 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4877 return documentElement ? documentElement.nodeName !== "HTML" : false;
4881 * Sets document-related variables once based on the current document
4882 * @param {Element|Object} [doc] An element or document object to use to set the document
4883 * @returns {Object} Returns the current document
4885setDocument = Sizzle.setDocument = function( node ) {
4887 doc = node ? node.ownerDocument || node : preferredDoc,
4888 parent = doc.defaultView;
4890 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4895 docElem = doc.documentElement;
4897 documentIsHTML = !isXML( doc );
4899 if ( parent && parent !== parent.top ) {
4900 if ( parent.addEventListener ) {
4901 parent.addEventListener( "unload", function() {
4904 } else if ( parent.attachEvent ) {
4905 parent.attachEvent( "onunload", function() {
4912 ---------------------------------------------------------------------- */
4914 support.attributes = assert(function( div ) {
4915 div.className = "i";
4916 return !div.getAttribute("className");
4920 ---------------------------------------------------------------------- */
4922 support.getElementsByTagName = assert(function( div ) {
4923 div.appendChild( doc.createComment("") );
4924 return !div.getElementsByTagName("*").length;
4927 support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
4928 div.innerHTML = "<div class='a'></div><div class='a i'></div>";
4930 div.firstChild.className = "i";
4931 return div.getElementsByClassName("i").length === 2;
4934 support.getById = assert(function( div ) {
4935 docElem.appendChild( div ).id = expando;
4936 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
4939 if ( support.getById ) {
4940 Expr.find["ID"] = function( id, context ) {
4941 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
4942 var m = context.getElementById( id );
4943 return m && m.parentNode ? [m] : [];
4946 Expr.filter["ID"] = function( id ) {
4947 var attrId = id.replace( runescape, funescape );
4948 return function( elem ) {
4949 return elem.getAttribute("id") === attrId;
4953 delete Expr.find["ID"];
4955 Expr.filter["ID"] = function( id ) {
4956 var attrId = id.replace( runescape, funescape );
4957 return function( elem ) {
4958 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
4959 return node && node.value === attrId;
4964 Expr.find["TAG"] = support.getElementsByTagName ?
4965 function( tag, context ) {
4966 if ( typeof context.getElementsByTagName !== strundefined ) {
4967 return context.getElementsByTagName( tag );
4970 function( tag, context ) {
4974 results = context.getElementsByTagName( tag );
4976 if ( tag === "*" ) {
4977 while ( (elem = results[i++]) ) {
4978 if ( elem.nodeType === 1 ) {
4988 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
4989 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
4990 return context.getElementsByClassName( className );
4994 /* QSA/matchesSelector
4995 ---------------------------------------------------------------------- */
5002 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
5003 assert(function( div ) {
5004 div.innerHTML = "<select t=''><option selected=''></option></select>";
5006 if ( div.querySelectorAll("[t^='']").length ) {
5007 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
5010 if ( !div.querySelectorAll("[selected]").length ) {
5011 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
5014 if ( !div.querySelectorAll(":checked").length ) {
5015 rbuggyQSA.push(":checked");
5019 assert(function( div ) {
5020 var input = doc.createElement("input");
5021 input.setAttribute( "type", "hidden" );
5022 div.appendChild( input ).setAttribute( "name", "D" );
5024 if ( div.querySelectorAll("[name=d]").length ) {
5025 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
5028 if ( !div.querySelectorAll(":enabled").length ) {
5029 rbuggyQSA.push( ":enabled", ":disabled" );
5032 div.querySelectorAll("*,:x");
5033 rbuggyQSA.push(",.*:");
5037 if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
5038 docElem.mozMatchesSelector ||
5039 docElem.oMatchesSelector ||
5040 docElem.msMatchesSelector) )) ) {
5042 assert(function( div ) {
5043 support.disconnectedMatch = matches.call( div, "div" );
5045 matches.call( div, "[s!='']:x" );
5046 rbuggyMatches.push( "!=", pseudos );
5050 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
5051 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
5054 ---------------------------------------------------------------------- */
5055 hasCompare = rnative.test( docElem.compareDocumentPosition );
5057 contains = hasCompare || rnative.test( docElem.contains ) ?
5059 var adown = a.nodeType === 9 ? a.documentElement : a,
5060 bup = b && b.parentNode;
5061 return a === bup || !!( bup && bup.nodeType === 1 && (
5063 adown.contains( bup ) :
5064 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
5069 while ( (b = b.parentNode) ) {
5079 ---------------------------------------------------------------------- */
5081 sortOrder = hasCompare ?
5085 hasDuplicate = true;
5089 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
5094 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
5095 a.compareDocumentPosition( b ) :
5100 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
5102 if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
5105 if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
5110 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5114 return compare & 4 ? -1 : 1;
5118 hasDuplicate = true;
5129 if ( !aup || !bup ) {
5130 return a === doc ? -1 :
5135 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5138 } else if ( aup === bup ) {
5139 return siblingCheck( a, b );
5143 while ( (cur = cur.parentNode) ) {
5147 while ( (cur = cur.parentNode) ) {
5151 while ( ap[i] === bp[i] ) {
5156 siblingCheck( ap[i], bp[i] ) :
5158 ap[i] === preferredDoc ? -1 :
5159 bp[i] === preferredDoc ? 1 :
5166Sizzle.matches = function( expr, elements ) {
5167 return Sizzle( expr, null, null, elements );
5170Sizzle.matchesSelector = function( elem, expr ) {
5171 if ( ( elem.ownerDocument || elem ) !== document ) {
5172 setDocument( elem );
5175 expr = expr.replace( rattributeQuotes, "='$1']" );
5177 if ( support.matchesSelector && documentIsHTML &&
5178 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
5179 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
5182 var ret = matches.call( elem, expr );
5184 if ( ret || support.disconnectedMatch ||
5185 elem.document && elem.document.nodeType !== 11 ) {
5191 return Sizzle( expr, document, null, [elem] ).length > 0;
5194Sizzle.contains = function( context, elem ) {
5195 if ( ( context.ownerDocument || context ) !== document ) {
5196 setDocument( context );
5198 return contains( context, elem );
5201Sizzle.attr = function( elem, name ) {
5202 if ( ( elem.ownerDocument || elem ) !== document ) {
5203 setDocument( elem );
5206 var fn = Expr.attrHandle[ name.toLowerCase() ],
5207 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
5208 fn( elem, name, !documentIsHTML ) :
5211 return val !== undefined ?
5213 support.attributes || !documentIsHTML ?
5214 elem.getAttribute( name ) :
5215 (val = elem.getAttributeNode(name)) && val.specified ?
5220Sizzle.error = function( msg ) {
5221 throw new Error( "Syntax error, unrecognized expression: " + msg );
5225 * Document sorting and removing duplicates
5226 * @param {ArrayLike} results
5228Sizzle.uniqueSort = function( results ) {
5234 hasDuplicate = !support.detectDuplicates;
5235 sortInput = !support.sortStable && results.slice( 0 );
5236 results.sort( sortOrder );
5238 if ( hasDuplicate ) {
5239 while ( (elem = results[i++]) ) {
5240 if ( elem === results[ i ] ) {
5241 j = duplicates.push( i );
5245 results.splice( duplicates[ j ], 1 );
5255 * Utility function for retrieving the text value of an array of DOM nodes
5256 * @param {Array|Element} elem
5258getText = Sizzle.getText = function( elem ) {
5262 nodeType = elem.nodeType;
5265 while ( (node = elem[i++]) ) {
5266 ret += getText( node );
5268 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
5269 if ( typeof elem.textContent === "string" ) {
5270 return elem.textContent;
5272 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5273 ret += getText( elem );
5276 } else if ( nodeType === 3 || nodeType === 4 ) {
5277 return elem.nodeValue;
5283Expr = Sizzle.selectors = {
5287 createPseudo: markFunction,
5296 ">": { dir: "parentNode", first: true },
5297 " ": { dir: "parentNode" },
5298 "+": { dir: "previousSibling", first: true },
5299 "~": { dir: "previousSibling" }
5303 "ATTR": function( match ) {
5304 match[1] = match[1].replace( runescape, funescape );
5306 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
5308 if ( match[2] === "~=" ) {
5309 match[3] = " " + match[3] + " ";
5312 return match.slice( 0, 4 );
5315 "CHILD": function( match ) {
5316 /* matches from matchExpr["CHILD"]
5317 1 type (only|nth|...)
5318 2 what (child|of-type)
5319 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
5320 4 xn-component of xn+y argument ([+-]?\d*n|)
5321 5 sign of xn-component
5323 7 sign of y-component
5326 match[1] = match[1].toLowerCase();
5328 if ( match[1].slice( 0, 3 ) === "nth" ) {
5330 Sizzle.error( match[0] );
5333 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
5334 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
5336 } else if ( match[3] ) {
5337 Sizzle.error( match[0] );
5343 "PSEUDO": function( match ) {
5345 unquoted = !match[5] && match[2];
5347 if ( matchExpr["CHILD"].test( match[0] ) ) {
5351 if ( match[3] && match[4] !== undefined ) {
5352 match[2] = match[4];
5354 } else if ( unquoted && rpseudo.test( unquoted ) &&
5355 (excess = tokenize( unquoted, true )) &&
5356 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
5358 match[0] = match[0].slice( 0, excess );
5359 match[2] = unquoted.slice( 0, excess );
5362 return match.slice( 0, 3 );
5368 "TAG": function( nodeNameSelector ) {
5369 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
5370 return nodeNameSelector === "*" ?
5371 function() { return true; } :
5373 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
5377 "CLASS": function( className ) {
5378 var pattern = classCache[ className + " " ];
5381 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
5382 classCache( className, function( elem ) {
5383 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
5387 "ATTR": function( name, operator, check ) {
5388 return function( elem ) {
5389 var result = Sizzle.attr( elem, name );
5391 if ( result == null ) {
5392 return operator === "!=";
5400 return operator === "=" ? result === check :
5401 operator === "!=" ? result !== check :
5402 operator === "^=" ? check && result.indexOf( check ) === 0 :
5403 operator === "*=" ? check && result.indexOf( check ) > -1 :
5404 operator === "$=" ? check && result.slice( -check.length ) === check :
5405 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
5406 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
5411 "CHILD": function( type, what, argument, first, last ) {
5412 var simple = type.slice( 0, 3 ) !== "nth",
5413 forward = type.slice( -4 ) !== "last",
5414 ofType = what === "of-type";
5416 return first === 1 && last === 0 ?
5419 return !!elem.parentNode;
5422 function( elem, context, xml ) {
5423 var cache, outerCache, node, diff, nodeIndex, start,
5424 dir = simple !== forward ? "nextSibling" : "previousSibling",
5425 parent = elem.parentNode,
5426 name = ofType && elem.nodeName.toLowerCase(),
5427 useCache = !xml && !ofType;
5434 while ( (node = node[ dir ]) ) {
5435 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
5439 start = dir = type === "only" && !start && "nextSibling";
5444 start = [ forward ? parent.firstChild : parent.lastChild ];
5446 if ( forward && useCache ) {
5447 outerCache = parent[ expando ] || (parent[ expando ] = {});
5448 cache = outerCache[ type ] || [];
5449 nodeIndex = cache[0] === dirruns && cache[1];
5450 diff = cache[0] === dirruns && cache[2];
5451 node = nodeIndex && parent.childNodes[ nodeIndex ];
5453 while ( (node = ++nodeIndex && node && node[ dir ] ||
5455 (diff = nodeIndex = 0) || start.pop()) ) {
5457 if ( node.nodeType === 1 && ++diff && node === elem ) {
5458 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
5463 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
5467 while ( (node = ++nodeIndex && node && node[ dir ] ||
5468 (diff = nodeIndex = 0) || start.pop()) ) {
5470 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
5472 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
5475 if ( node === elem ) {
5483 return diff === first || ( diff % first === 0 && diff / first >= 0 );
5488 "PSEUDO": function( pseudo, argument ) {
5490 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
5491 Sizzle.error( "unsupported pseudo: " + pseudo );
5493 if ( fn[ expando ] ) {
5494 return fn( argument );
5497 if ( fn.length > 1 ) {
5498 args = [ pseudo, pseudo, "", argument ];
5499 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
5500 markFunction(function( seed, matches ) {
5502 matched = fn( seed, argument ),
5505 idx = indexOf.call( seed, matched[i] );
5506 seed[ idx ] = !( matches[ idx ] = matched[i] );
5510 return fn( elem, 0, args );
5519 "not": markFunction(function( selector ) {
5522 matcher = compile( selector.replace( rtrim, "$1" ) );
5524 return matcher[ expando ] ?
5525 markFunction(function( seed, matches, context, xml ) {
5527 unmatched = matcher( seed, null, xml, [] ),
5531 if ( (elem = unmatched[i]) ) {
5532 seed[i] = !(matches[i] = elem);
5536 function( elem, context, xml ) {
5538 matcher( input, null, xml, results );
5539 return !results.pop();
5543 "has": markFunction(function( selector ) {
5544 return function( elem ) {
5545 return Sizzle( selector, elem ).length > 0;
5549 "contains": markFunction(function( text ) {
5550 return function( elem ) {
5551 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
5555 "lang": markFunction( function( lang ) {
5556 if ( !ridentifier.test(lang || "") ) {
5557 Sizzle.error( "unsupported lang: " + lang );
5559 lang = lang.replace( runescape, funescape ).toLowerCase();
5560 return function( elem ) {
5563 if ( (elemLang = documentIsHTML ?
5565 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
5567 elemLang = elemLang.toLowerCase();
5568 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
5570 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
5575 "target": function( elem ) {
5576 var hash = window.location && window.location.hash;
5577 return hash && hash.slice( 1 ) === elem.id;
5580 "root": function( elem ) {
5581 return elem === docElem;
5584 "focus": function( elem ) {
5585 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
5588 "enabled": function( elem ) {
5589 return elem.disabled === false;
5592 "disabled": function( elem ) {
5593 return elem.disabled === true;
5596 "checked": function( elem ) {
5597 var nodeName = elem.nodeName.toLowerCase();
5598 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
5601 "selected": function( elem ) {
5602 if ( elem.parentNode ) {
5603 elem.parentNode.selectedIndex;
5606 return elem.selected === true;
5609 "empty": function( elem ) {
5610 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5611 if ( elem.nodeType < 6 ) {
5618 "parent": function( elem ) {
5619 return !Expr.pseudos["empty"]( elem );
5622 "header": function( elem ) {
5623 return rheader.test( elem.nodeName );
5626 "input": function( elem ) {
5627 return rinputs.test( elem.nodeName );
5630 "button": function( elem ) {
5631 var name = elem.nodeName.toLowerCase();
5632 return name === "input" && elem.type === "button" || name === "button";
5635 "text": function( elem ) {
5637 return elem.nodeName.toLowerCase() === "input" &&
5638 elem.type === "text" &&
5640 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
5643 "first": createPositionalPseudo(function() {
5647 "last": createPositionalPseudo(function( matchIndexes, length ) {
5648 return [ length - 1 ];
5651 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
5652 return [ argument < 0 ? argument + length : argument ];
5655 "even": createPositionalPseudo(function( matchIndexes, length ) {
5657 for ( ; i < length; i += 2 ) {
5658 matchIndexes.push( i );
5660 return matchIndexes;
5663 "odd": createPositionalPseudo(function( matchIndexes, length ) {
5665 for ( ; i < length; i += 2 ) {
5666 matchIndexes.push( i );
5668 return matchIndexes;
5671 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5672 var i = argument < 0 ? argument + length : argument;
5673 for ( ; --i >= 0; ) {
5674 matchIndexes.push( i );
5676 return matchIndexes;
5679 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5680 var i = argument < 0 ? argument + length : argument;
5681 for ( ; ++i < length; ) {
5682 matchIndexes.push( i );
5684 return matchIndexes;
5689Expr.pseudos["nth"] = Expr.pseudos["eq"];
5691for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5692 Expr.pseudos[ i ] = createInputPseudo( i );
5694for ( i in { submit: true, reset: true } ) {
5695 Expr.pseudos[ i ] = createButtonPseudo( i );
5698function setFilters() {}
5699setFilters.prototype = Expr.filters = Expr.pseudos;
5700Expr.setFilters = new setFilters();
5702function tokenize( selector, parseOnly ) {
5703 var matched, match, tokens, type,
5704 soFar, groups, preFilters,
5705 cached = tokenCache[ selector + " " ];
5708 return parseOnly ? 0 : cached.slice( 0 );
5713 preFilters = Expr.preFilter;
5717 if ( !matched || (match = rcomma.exec( soFar )) ) {
5719 soFar = soFar.slice( match[0].length ) || soFar;
5721 groups.push( (tokens = []) );
5726 if ( (match = rcombinators.exec( soFar )) ) {
5727 matched = match.shift();
5730 type: match[0].replace( rtrim, " " )
5732 soFar = soFar.slice( matched.length );
5735 for ( type in Expr.filter ) {
5736 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5737 (match = preFilters[ type ]( match ))) ) {
5738 matched = match.shift();
5744 soFar = soFar.slice( matched.length );
5756 Sizzle.error( selector ) :
5757 tokenCache( selector, groups ).slice( 0 );
5760function toSelector( tokens ) {
5762 len = tokens.length,
5764 for ( ; i < len; i++ ) {
5765 selector += tokens[i].value;
5770function addCombinator( matcher, combinator, base ) {
5771 var dir = combinator.dir,
5772 checkNonElements = base && dir === "parentNode",
5775 return combinator.first ?
5776 function( elem, context, xml ) {
5777 while ( (elem = elem[ dir ]) ) {
5778 if ( elem.nodeType === 1 || checkNonElements ) {
5779 return matcher( elem, context, xml );
5784 function( elem, context, xml ) {
5785 var oldCache, outerCache,
5786 newCache = [ dirruns, doneName ];
5789 while ( (elem = elem[ dir ]) ) {
5790 if ( elem.nodeType === 1 || checkNonElements ) {
5791 if ( matcher( elem, context, xml ) ) {
5797 while ( (elem = elem[ dir ]) ) {
5798 if ( elem.nodeType === 1 || checkNonElements ) {
5799 outerCache = elem[ expando ] || (elem[ expando ] = {});
5800 if ( (oldCache = outerCache[ dir ]) &&
5801 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
5803 return (newCache[ 2 ] = oldCache[ 2 ]);
5805 outerCache[ dir ] = newCache;
5807 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
5817function elementMatcher( matchers ) {
5818 return matchers.length > 1 ?
5819 function( elem, context, xml ) {
5820 var i = matchers.length;
5822 if ( !matchers[i]( elem, context, xml ) ) {
5831function multipleContexts( selector, contexts, results ) {
5833 len = contexts.length;
5834 for ( ; i < len; i++ ) {
5835 Sizzle( selector, contexts[i], results );
5840function condense( unmatched, map, filter, context, xml ) {
5844 len = unmatched.length,
5845 mapped = map != null;
5847 for ( ; i < len; i++ ) {
5848 if ( (elem = unmatched[i]) ) {
5849 if ( !filter || filter( elem, context, xml ) ) {
5850 newUnmatched.push( elem );
5858 return newUnmatched;
5861function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5862 if ( postFilter && !postFilter[ expando ] ) {
5863 postFilter = setMatcher( postFilter );
5865 if ( postFinder && !postFinder[ expando ] ) {
5866 postFinder = setMatcher( postFinder, postSelector );
5868 return markFunction(function( seed, results, context, xml ) {
5872 preexisting = results.length,
5874 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5876 matcherIn = preFilter && ( seed || !selector ) ?
5877 condense( elems, preMap, preFilter, context, xml ) :
5880 matcherOut = matcher ?
5881 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5889 matcher( matcherIn, matcherOut, context, xml );
5893 temp = condense( matcherOut, postMap );
5894 postFilter( temp, [], context, xml );
5898 if ( (elem = temp[i]) ) {
5899 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5905 if ( postFinder || preFilter ) {
5908 i = matcherOut.length;
5910 if ( (elem = matcherOut[i]) ) {
5911 temp.push( (matcherIn[i] = elem) );
5914 postFinder( null, (matcherOut = []), temp, xml );
5917 i = matcherOut.length;
5919 if ( (elem = matcherOut[i]) &&
5920 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5922 seed[temp] = !(results[temp] = elem);
5928 matcherOut = condense(
5929 matcherOut === results ?
5930 matcherOut.splice( preexisting, matcherOut.length ) :
5934 postFinder( null, results, matcherOut, xml );
5936 push.apply( results, matcherOut );
5942function matcherFromTokens( tokens ) {
5943 var checkContext, matcher, j,
5944 len = tokens.length,
5945 leadingRelative = Expr.relative[ tokens[0].type ],
5946 implicitRelative = leadingRelative || Expr.relative[" "],
5947 i = leadingRelative ? 1 : 0,
5949 matchContext = addCombinator( function( elem ) {
5950 return elem === checkContext;
5951 }, implicitRelative, true ),
5952 matchAnyContext = addCombinator( function( elem ) {
5953 return indexOf.call( checkContext, elem ) > -1;
5954 }, implicitRelative, true ),
5955 matchers = [ function( elem, context, xml ) {
5956 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
5957 (checkContext = context).nodeType ?
5958 matchContext( elem, context, xml ) :
5959 matchAnyContext( elem, context, xml ) );
5962 for ( ; i < len; i++ ) {
5963 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
5964 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
5966 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
5968 if ( matcher[ expando ] ) {
5970 for ( ; j < len; j++ ) {
5971 if ( Expr.relative[ tokens[j].type ] ) {
5976 i > 1 && elementMatcher( matchers ),
5977 i > 1 && toSelector(
5978 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
5979 ).replace( rtrim, "$1" ),
5981 i < j && matcherFromTokens( tokens.slice( i, j ) ),
5982 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
5983 j < len && toSelector( tokens )
5986 matchers.push( matcher );
5990 return elementMatcher( matchers );
5993function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
5994 var bySet = setMatchers.length > 0,
5995 byElement = elementMatchers.length > 0,
5996 superMatcher = function( seed, context, xml, results, outermost ) {
5997 var elem, j, matcher,
6000 unmatched = seed && [],
6002 contextBackup = outermostContext,
6003 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
6004 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
6008 outermostContext = context !== document && context;
6011 for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
6012 if ( byElement && elem ) {
6014 while ( (matcher = elementMatchers[j++]) ) {
6015 if ( matcher( elem, context, xml ) ) {
6016 results.push( elem );
6021 dirruns = dirrunsUnique;
6026 if ( (elem = !matcher && elem) ) {
6031 unmatched.push( elem );
6037 if ( bySet && i !== matchedCount ) {
6039 while ( (matcher = setMatchers[j++]) ) {
6040 matcher( unmatched, setMatched, context, xml );
6044 if ( matchedCount > 0 ) {
6046 if ( !(unmatched[i] || setMatched[i]) ) {
6047 setMatched[i] = pop.call( results );
6052 setMatched = condense( setMatched );
6055 push.apply( results, setMatched );
6057 if ( outermost && !seed && setMatched.length > 0 &&
6058 ( matchedCount + setMatchers.length ) > 1 ) {
6060 Sizzle.uniqueSort( results );
6065 dirruns = dirrunsUnique;
6066 outermostContext = contextBackup;
6073 markFunction( superMatcher ) :
6077compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
6080 elementMatchers = [],
6081 cached = compilerCache[ selector + " " ];
6085 match = tokenize( selector );
6089 cached = matcherFromTokens( match[i] );
6090 if ( cached[ expando ] ) {
6091 setMatchers.push( cached );
6093 elementMatchers.push( cached );
6097 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
6099 cached.selector = selector;
6105 * A low-level selection function that works with Sizzle's compiled
6106 * selector functions
6107 * @param {String|Function} selector A selector or a pre-compiled
6108 * selector function built with Sizzle.compile
6109 * @param {Element} context
6110 * @param {Array} [results]
6111 * @param {Array} [seed] A set of elements to match against
6113select = Sizzle.select = function( selector, context, results, seed ) {
6114 var i, tokens, token, type, find,
6115 compiled = typeof selector === "function" && selector,
6116 match = !seed && tokenize( (selector = compiled.selector || selector) );
6118 results = results || [];
6120 if ( match.length === 1 ) {
6122 tokens = match[0] = match[0].slice( 0 );
6123 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
6124 support.getById && context.nodeType === 9 && documentIsHTML &&
6125 Expr.relative[ tokens[1].type ] ) {
6127 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
6131 } else if ( compiled ) {
6132 context = context.parentNode;
6135 selector = selector.slice( tokens.shift().value.length );
6138 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
6142 if ( Expr.relative[ (type = token.type) ] ) {
6145 if ( (find = Expr.find[ type ]) ) {
6147 token.matches[0].replace( runescape, funescape ),
6148 rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
6151 tokens.splice( i, 1 );
6152 selector = seed.length && toSelector( tokens );
6154 push.apply( results, seed );
6164 ( compiled || compile( selector, match ) )(
6169 rsibling.test( selector ) && testContext( context.parentNode ) || context
6175support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
6177support.detectDuplicates = !!hasDuplicate;
6181support.sortDetached = assert(function( div1 ) {
6182 return div1.compareDocumentPosition( document.createElement("div") ) & 1;
6185if ( !assert(function( div ) {
6186 div.innerHTML = "<a href='#'></a>";
6187 return div.firstChild.getAttribute("href") === "#" ;
6189 addHandle( "type|href|height|width", function( elem, name, isXML ) {
6191 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
6196if ( !support.attributes || !assert(function( div ) {
6197 div.innerHTML = "<input/>";
6198 div.firstChild.setAttribute( "value", "" );
6199 return div.firstChild.getAttribute( "value" ) === "";
6201 addHandle( "value", function( elem, name, isXML ) {
6202 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
6203 return elem.defaultValue;
6208if ( !assert(function( div ) {
6209 return div.getAttribute("disabled") == null;
6211 addHandle( booleans, function( elem, name, isXML ) {
6214 return elem[ name ] === true ? name.toLowerCase() :
6215 (val = elem.getAttributeNode( name )) && val.specified ?
6222if ( typeof define === "function" && define.amd ) {
6223 define(function() { return Sizzle; });
6224} else if ( typeof module !== "undefined" && module.exports ) {
6225 module.exports = Sizzle;
6227 window.Sizzle = Sizzle;
6233 var extendElements = Prototype.Selector.extendElements;
6235 function select(selector, scope) {
6236 return extendElements(engine(selector, scope || document));
6239 function match(element, selector) {
6240 return engine.matches(selector, [element]).length == 1;
6243 Prototype.Selector.engine = engine;
6244 Prototype.Selector.select = select;
6245 Prototype.Selector.match = match;
6248window.Sizzle = Prototype._original_property;
6249delete Prototype._original_property;
6252 reset: function(form) {
6258 serializeElements: function(elements, options) {
6259 if (typeof options != 'object') options = { hash: !!options };
6260 else if (Object.isUndefined(options.hash)) options.hash = true;
6261 var key, value, submitted = false, submit = options.submit, accumulator, initial;
6265 accumulator = function(result, key, value) {
6266 if (key in result) {
6267 if (!Object.isArray(result[key])) result[key] = [result[key]];
6268 result[key] = result[key].concat(value);
6269 } else result[key] = value;
6274 accumulator = function(result, key, values) {
6275 if (!Object.isArray(values)) {values = [values];}
6276 if (!values.length) {return result;}
6277 var encodedKey = encodeURIComponent(key).gsub(/%20/, '+');
6278 return result + (result ? "&" : "") + values.map(function (value) {
6279 value = value.gsub(/(\r)?\n/, '\r\n');
6280 value = encodeURIComponent(value);
6281 value = value.gsub(/%20/, '+');
6282 return encodedKey + "=" + value;
6287 return elements.inject(initial, function(result, element) {
6288 if (!element.disabled && element.name) {
6289 key = element.name; value = $(element).getValue();
6290 if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
6291 submit !== false && (!submit || key == submit) && (submitted = true)))) {
6292 result = accumulator(result, key, value);
6301 serialize: function(form, options) {
6302 return Form.serializeElements(Form.getElements(form), options);
6306 getElements: function(form) {
6307 var elements = $(form).getElementsByTagName('*');
6308 var element, results = [], serializers = Form.Element.Serializers;
6310 for (var i = 0; element = elements[i]; i++) {
6311 if (serializers[element.tagName.toLowerCase()])
6312 results.push(Element.extend(element));
6317 getInputs: function(form, typeName, name) {
6319 var inputs = form.getElementsByTagName('input');
6321 if (!typeName && !name) return $A(inputs).map(Element.extend);
6323 for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
6324 var input = inputs[i];
6325 if ((typeName && input.type != typeName) || (name && input.name != name))
6327 matchingInputs.push(Element.extend(input));
6330 return matchingInputs;
6333 disable: function(form) {
6335 Form.getElements(form).invoke('disable');
6339 enable: function(form) {
6341 Form.getElements(form).invoke('enable');
6345 findFirstElement: function(form) {
6346 var elements = $(form).getElements().findAll(function(element) {
6347 return 'hidden' != element.type && !element.disabled;
6349 var firstByIndex = elements.findAll(function(element) {
6350 return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
6351 }).sortBy(function(element) { return element.tabIndex }).first();
6353 return firstByIndex ? firstByIndex : elements.find(function(element) {
6354 return /^(?:input|select|textarea)$/i.test(element.tagName);
6358 focusFirstElement: function(form) {
6360 var element = form.findFirstElement();
6361 if (element) element.activate();
6365 request: function(form, options) {
6366 form = $(form), options = Object.clone(options || { });
6368 var params = options.parameters, action = form.readAttribute('action') || '';
6369 if (action.blank()) action = window.location.href;
6370 options.parameters = form.serialize(true);
6373 if (Object.isString(params)) params = params.toQueryParams();
6374 Object.extend(options.parameters, params);
6377 if (form.hasAttribute('method') && !options.method)
6378 options.method = form.method;
6380 return new Ajax.Request(action, options);
6384/*--------------------------------------------------------------------------*/
6388 focus: function(element) {
6393 select: function(element) {
6394 $(element).select();
6399Form.Element.Methods = {
6401 serialize: function(element) {
6402 element = $(element);
6403 if (!element.disabled && element.name) {
6404 var value = element.getValue();
6405 if (value != undefined) {
6407 pair[element.name] = value;
6408 return Object.toQueryString(pair);
6414 getValue: function(element) {
6415 element = $(element);
6416 var method = element.tagName.toLowerCase();
6417 return Form.Element.Serializers[method](element);
6420 setValue: function(element, value) {
6421 element = $(element);
6422 var method = element.tagName.toLowerCase();
6423 Form.Element.Serializers[method](element, value);
6427 clear: function(element) {
6428 $(element).value = '';
6432 present: function(element) {
6433 return $(element).value != '';
6436 activate: function(element) {
6437 element = $(element);
6440 if (element.select && (element.tagName.toLowerCase() != 'input' ||
6441 !(/^(?:button|reset|submit)$/i.test(element.type))))
6447 disable: function(element) {
6448 element = $(element);
6449 element.disabled = true;
6453 enable: function(element) {
6454 element = $(element);
6455 element.disabled = false;
6460/*--------------------------------------------------------------------------*/
6462var Field = Form.Element;
6464var $F = Form.Element.Methods.getValue;
6466/*--------------------------------------------------------------------------*/
6468Form.Element.Serializers = (function() {
6469 function input(element, value) {
6470 switch (element.type.toLowerCase()) {
6473 return inputSelector(element, value);
6475 return valueSelector(element, value);
6479 function inputSelector(element, value) {
6480 if (Object.isUndefined(value))
6481 return element.checked ? element.value : null;
6482 else element.checked = !!value;
6485 function valueSelector(element, value) {
6486 if (Object.isUndefined(value)) return element.value;
6487 else element.value = value;
6490 function select(element, value) {
6491 if (Object.isUndefined(value))
6492 return (element.type === 'select-one' ? selectOne : selectMany)(element);
6494 var opt, currentValue, single = !Object.isArray(value);
6495 for (var i = 0, length = element.length; i < length; i++) {
6496 opt = element.options[i];
6497 currentValue = this.optionValue(opt);
6499 if (currentValue == value) {
6500 opt.selected = true;
6504 else opt.selected = value.include(currentValue);
6508 function selectOne(element) {
6509 var index = element.selectedIndex;
6510 return index >= 0 ? optionValue(element.options[index]) : null;
6513 function selectMany(element) {
6514 var values, length = element.length;
6515 if (!length) return null;
6517 for (var i = 0, values = []; i < length; i++) {
6518 var opt = element.options[i];
6519 if (opt.selected) values.push(optionValue(opt));
6524 function optionValue(opt) {
6525 return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
6530 inputSelector: inputSelector,
6531 textarea: valueSelector,
6533 selectOne: selectOne,
6534 selectMany: selectMany,
6535 optionValue: optionValue,
6536 button: valueSelector
6540/*--------------------------------------------------------------------------*/
6543Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
6544 initialize: function($super, element, frequency, callback) {
6545 $super(callback, frequency);
6546 this.element = $(element);
6547 this.lastValue = this.getValue();
6550 execute: function() {
6551 var value = this.getValue();
6552 if (Object.isString(this.lastValue) && Object.isString(value) ?
6553 this.lastValue != value : String(this.lastValue) != String(value)) {
6554 this.callback(this.element, value);
6555 this.lastValue = value;
6560Form.Element.Observer = Class.create(Abstract.TimedObserver, {
6561 getValue: function() {
6562 return Form.Element.getValue(this.element);
6566Form.Observer = Class.create(Abstract.TimedObserver, {
6567 getValue: function() {
6568 return Form.serialize(this.element);
6572/*--------------------------------------------------------------------------*/
6574Abstract.EventObserver = Class.create({
6575 initialize: function(element, callback) {
6576 this.element = $(element);
6577 this.callback = callback;
6579 this.lastValue = this.getValue();
6580 if (this.element.tagName.toLowerCase() == 'form')
6581 this.registerFormCallbacks();
6583 this.registerCallback(this.element);
6586 onElementEvent: function() {
6587 var value = this.getValue();
6588 if (this.lastValue != value) {
6589 this.callback(this.element, value);
6590 this.lastValue = value;
6594 registerFormCallbacks: function() {
6595 Form.getElements(this.element).each(this.registerCallback, this);
6598 registerCallback: function(element) {
6600 switch (element.type.toLowerCase()) {
6603 Event.observe(element, 'click', this.onElementEvent.bind(this));
6606 Event.observe(element, 'change', this.onElementEvent.bind(this));
6613Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
6614 getValue: function() {
6615 return Form.Element.getValue(this.element);
6619Form.EventObserver = Class.create(Abstract.EventObserver, {
6620 getValue: function() {
6621 return Form.serialize(this.element);
6625 var DIV = document.createElement('div');
6626 var docEl = document.documentElement;
6627 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
6628 && 'onmouseleave' in docEl;
6648 var isIELegacyEvent = function(event) { return false; };
6650 if (window.attachEvent) {
6651 if (window.addEventListener) {
6652 isIELegacyEvent = function(event) {
6653 return !(event instanceof window.Event);
6656 isIELegacyEvent = function(event) { return true; };
6662 function _isButtonForDOMEvents(event, code) {
6663 return event.which ? (event.which === code + 1) : (event.button === code);
6666 var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
6667 function _isButtonForLegacyEvents(event, code) {
6668 return event.button === legacyButtonMap[code];
6671 function _isButtonForWebKit(event, code) {
6673 case 0: return event.which == 1 && !event.metaKey;
6674 case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
6675 case 2: return event.which == 3;
6676 default: return false;
6680 if (window.attachEvent) {
6681 if (!window.addEventListener) {
6682 _isButton = _isButtonForLegacyEvents;
6684 _isButton = function(event, code) {
6685 return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
6686 _isButtonForDOMEvents(event, code);
6689 } else if (Prototype.Browser.WebKit) {
6690 _isButton = _isButtonForWebKit;
6692 _isButton = _isButtonForDOMEvents;
6695 function isLeftClick(event) { return _isButton(event, 0) }
6697 function isMiddleClick(event) { return _isButton(event, 1) }
6699 function isRightClick(event) { return _isButton(event, 2) }
6701 function element(event) {
6702 return Element.extend(_element(event));
6705 function _element(event) {
6706 event = Event.extend(event);
6708 var node = event.target, type = event.type,
6709 currentTarget = event.currentTarget;
6711 if (currentTarget && currentTarget.tagName) {
6712 if (type === 'load' || type === 'error' ||
6713 (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
6714 && currentTarget.type === 'radio'))
6715 node = currentTarget;
6718 return node.nodeType == Node.TEXT_NODE ? node.parentNode : node;
6721 function findElement(event, expression) {
6722 var element = _element(event), selector = Prototype.Selector;
6723 if (!expression) return Element.extend(element);
6725 if (Object.isElement(element) && selector.match(element, expression))
6726 return Element.extend(element);
6727 element = element.parentNode;
6731 function pointer(event) {
6732 return { x: pointerX(event), y: pointerY(event) };
6735 function pointerX(event) {
6736 var docElement = document.documentElement,
6737 body = document.body || { scrollLeft: 0 };
6739 return event.pageX || (event.clientX +
6740 (docElement.scrollLeft || body.scrollLeft) -
6741 (docElement.clientLeft || 0));
6744 function pointerY(event) {
6745 var docElement = document.documentElement,
6746 body = document.body || { scrollTop: 0 };
6748 return event.pageY || (event.clientY +
6749 (docElement.scrollTop || body.scrollTop) -
6750 (docElement.clientTop || 0));
6754 function stop(event) {
6755 Event.extend(event);
6756 event.preventDefault();
6757 event.stopPropagation();
6759 event.stopped = true;
6764 isLeftClick: isLeftClick,
6765 isMiddleClick: isMiddleClick,
6766 isRightClick: isRightClick,
6769 findElement: findElement,
6778 var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
6779 m[name] = Event.Methods[name].methodize();
6783 if (window.attachEvent) {
6784 function _relatedTarget(event) {
6786 switch (event.type) {
6789 element = event.fromElement;
6793 element = event.toElement;
6798 return Element.extend(element);
6801 var additionalMethods = {
6802 stopPropagation: function() { this.cancelBubble = true },
6803 preventDefault: function() { this.returnValue = false },
6804 inspect: function() { return '[object Event]' }
6807 Event.extend = function(event, element) {
6808 if (!event) return false;
6810 if (!isIELegacyEvent(event)) return event;
6812 if (event._extendedByPrototype) return event;
6813 event._extendedByPrototype = Prototype.emptyFunction;
6815 var pointer = Event.pointer(event);
6817 Object.extend(event, {
6818 target: event.srcElement || element,
6819 relatedTarget: _relatedTarget(event),
6824 Object.extend(event, methods);
6825 Object.extend(event, additionalMethods);
6830 Event.extend = Prototype.K;
6833 if (window.addEventListener) {
6834 Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
6835 Object.extend(Event.prototype, methods);
6838 var EVENT_TRANSLATIONS = {
6839 mouseenter: 'mouseover',
6840 mouseleave: 'mouseout'
6843 function getDOMEventName(eventName) {
6844 return EVENT_TRANSLATIONS[eventName] || eventName;
6847 if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED)
6848 getDOMEventName = Prototype.K;
6850 function getUniqueElementID(element) {
6851 if (element === window) return 0;
6853 if (typeof element._prototypeUID === 'undefined')
6854 element._prototypeUID = Element.Storage.UID++;
6855 return element._prototypeUID;
6858 function getUniqueElementID_IE(element) {
6859 if (element === window) return 0;
6860 if (element == document) return 1;
6861 return element.uniqueID;
6864 if ('uniqueID' in DIV)
6865 getUniqueElementID = getUniqueElementID_IE;
6867 function isCustomEvent(eventName) {
6868 return eventName.include(':');
6871 Event._isCustomEvent = isCustomEvent;
6873 function getRegistryForElement(element, uid) {
6874 var CACHE = GLOBAL.Event.cache;
6875 if (Object.isUndefined(uid))
6876 uid = getUniqueElementID(element);
6877 if (!CACHE[uid]) CACHE[uid] = { element: element };
6881 function destroyRegistryForElement(element, uid) {
6882 if (Object.isUndefined(uid))
6883 uid = getUniqueElementID(element);
6884 delete GLOBAL.Event.cache[uid];
6888 function register(element, eventName, handler) {
6889 var registry = getRegistryForElement(element);
6890 if (!registry[eventName]) registry[eventName] = [];
6891 var entries = registry[eventName];
6893 var i = entries.length;
6895 if (entries[i].handler === handler) return null;
6897 var uid = getUniqueElementID(element);
6898 var responder = GLOBAL.Event._createResponder(uid, eventName, handler);
6900 responder: responder,
6904 entries.push(entry);
6908 function unregister(element, eventName, handler) {
6909 var registry = getRegistryForElement(element);
6910 var entries = registry[eventName];
6911 if (!entries) return;
6913 var i = entries.length, entry;
6915 if (entries[i].handler === handler) {
6923 var index = entries.indexOf(entry);
6924 entries.splice(index, 1);
6930 function observe(element, eventName, handler) {
6931 element = $(element);
6932 var entry = register(element, eventName, handler);
6934 if (entry === null) return element;
6936 var responder = entry.responder;
6937 if (isCustomEvent(eventName))
6938 observeCustomEvent(element, eventName, responder);
6940 observeStandardEvent(element, eventName, responder);
6945 function observeStandardEvent(element, eventName, responder) {
6946 var actualEventName = getDOMEventName(eventName);
6947 if (element.addEventListener) {
6948 element.addEventListener(actualEventName, responder, false);
6950 element.attachEvent('on' + actualEventName, responder);
6954 function observeCustomEvent(element, eventName, responder) {
6955 if (element.addEventListener) {
6956 element.addEventListener('dataavailable', responder, false);
6958 element.attachEvent('ondataavailable', responder);
6959 element.attachEvent('onlosecapture', responder);
6963 function stopObserving(element, eventName, handler) {
6964 element = $(element);
6965 var handlerGiven = !Object.isUndefined(handler),
6966 eventNameGiven = !Object.isUndefined(eventName);
6968 if (!eventNameGiven && !handlerGiven) {
6969 stopObservingElement(element);
6973 if (!handlerGiven) {
6974 stopObservingEventName(element, eventName);
6978 var entry = unregister(element, eventName, handler);
6980 if (!entry) return element;
6981 removeEvent(element, eventName, entry.responder);
6985 function stopObservingStandardEvent(element, eventName, responder) {
6986 var actualEventName = getDOMEventName(eventName);
6987 if (element.removeEventListener) {
6988 element.removeEventListener(actualEventName, responder, false);
6990 element.detachEvent('on' + actualEventName, responder);
6994 function stopObservingCustomEvent(element, eventName, responder) {
6995 if (element.removeEventListener) {
6996 element.removeEventListener('dataavailable', responder, false);
6998 element.detachEvent('ondataavailable', responder);
6999 element.detachEvent('onlosecapture', responder);
7005 function stopObservingElement(element) {
7006 var uid = getUniqueElementID(element), registry = GLOBAL.Event.cache[uid];
7007 if (!registry) return;
7009 destroyRegistryForElement(element, uid);
7012 for (var eventName in registry) {
7013 if (eventName === 'element') continue;
7015 entries = registry[eventName];
7018 removeEvent(element, eventName, entries[i].responder);
7022 function stopObservingEventName(element, eventName) {
7023 var registry = getRegistryForElement(element);
7024 var entries = registry[eventName];
7025 if (!entries) return;
7026 delete registry[eventName];
7028 var i = entries.length;
7030 removeEvent(element, eventName, entries[i].responder);
7034 function removeEvent(element, eventName, handler) {
7035 if (isCustomEvent(eventName))
7036 stopObservingCustomEvent(element, eventName, handler);
7038 stopObservingStandardEvent(element, eventName, handler);
7043 function getFireTarget(element) {
7044 if (element !== document) return element;
7045 if (document.createEvent && !element.dispatchEvent)
7046 return document.documentElement;
7050 function fire(element, eventName, memo, bubble) {
7051 element = getFireTarget($(element));
7052 if (Object.isUndefined(bubble)) bubble = true;
7055 var event = fireEvent(element, eventName, memo, bubble);
7056 return Event.extend(event);
7059 function fireEvent_DOM(element, eventName, memo, bubble) {
7060 var event = document.createEvent('HTMLEvents');
7061 event.initEvent('dataavailable', bubble, true);
7063 event.eventName = eventName;
7066 element.dispatchEvent(event);
7070 function fireEvent_IE(element, eventName, memo, bubble) {
7071 var event = document.createEventObject();
7072 event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
7074 event.eventName = eventName;
7077 element.fireEvent(event.eventType, event);
7081 var fireEvent = document.createEvent ? fireEvent_DOM : fireEvent_IE;
7085 Event.Handler = Class.create({
7086 initialize: function(element, eventName, selector, callback) {
7087 this.element = $(element);
7088 this.eventName = eventName;
7089 this.selector = selector;
7090 this.callback = callback;
7091 this.handler = this.handleEvent.bind(this);
7096 Event.observe(this.element, this.eventName, this.handler);
7101 Event.stopObserving(this.element, this.eventName, this.handler);
7105 handleEvent: function(event) {
7106 var element = Event.findElement(event, this.selector);
7107 if (element) this.callback.call(this.element, event, element);
7111 function on(element, eventName, selector, callback) {
7112 element = $(element);
7113 if (Object.isFunction(selector) && Object.isUndefined(callback)) {
7114 callback = selector, selector = null;
7117 return new Event.Handler(element, eventName, selector, callback).start();
7120 Object.extend(Event, Event.Methods);
7122 Object.extend(Event, {
7125 stopObserving: stopObserving,
7129 Element.addMethods({
7134 stopObserving: stopObserving,
7139 Object.extend(document, {
7140 fire: fire.methodize(),
7142 observe: observe.methodize(),
7144 stopObserving: stopObserving.methodize(),
7151 if (GLOBAL.Event) Object.extend(window.Event, Event);
7152 else GLOBAL.Event = Event;
7154 GLOBAL.Event.cache = {};
7156 function destroyCache_IE() {
7157 GLOBAL.Event.cache = null;
7160 if (window.attachEvent)
7161 window.attachEvent('onunload', destroyCache_IE);
7168 /* Code for creating leak-free event responders is based on work by
7169 John-David Dalton. */
7171 var docEl = document.documentElement;
7172 var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
7173 && 'onmouseleave' in docEl;
7175 function isSimulatedMouseEnterLeaveEvent(eventName) {
7176 return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
7177 (eventName === 'mouseenter' || eventName === 'mouseleave');
7180 function createResponder(uid, eventName, handler) {
7181 if (Event._isCustomEvent(eventName))
7182 return createResponderForCustomEvent(uid, eventName, handler);
7183 if (isSimulatedMouseEnterLeaveEvent(eventName))
7184 return createMouseEnterLeaveResponder(uid, eventName, handler);
7186 return function(event) {
7187 if (!Event.cache) return;
7189 var element = Event.cache[uid].element;
7190 Event.extend(event, element);
7191 handler.call(element, event);
7195 function createResponderForCustomEvent(uid, eventName, handler) {
7196 return function(event) {
7197 var element = Event.cache[uid].element;
7199 if (Object.isUndefined(event.eventName))
7202 if (event.eventName !== eventName)
7205 Event.extend(event, element);
7206 handler.call(element, event);
7210 function createMouseEnterLeaveResponder(uid, eventName, handler) {
7211 return function(event) {
7212 var element = Event.cache[uid].element;
7214 Event.extend(event, element);
7215 var parent = event.relatedTarget;
7217 while (parent && parent !== element) {
7218 try { parent = parent.parentNode; }
7219 catch(e) { parent = element; }
7222 if (parent === element) return;
7223 handler.call(element, event);
7227 GLOBAL.Event._createResponder = createResponder;
7232 /* Support for the DOMContentLoaded event is based on work by Dan Webb,
7233 Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
7237 function fireContentLoadedEvent() {
7238 if (document.loaded) return;
7239 if (TIMER) window.clearTimeout(TIMER);
7240 document.loaded = true;
7241 document.fire('dom:loaded');
7244 function checkReadyState() {
7245 if (document.readyState === 'complete') {
7246 document.detachEvent('onreadystatechange', checkReadyState);
7247 fireContentLoadedEvent();
7251 function pollDoScroll() {
7253 document.documentElement.doScroll('left');
7255 TIMER = pollDoScroll.defer();
7259 fireContentLoadedEvent();
7263 if (document.readyState === 'complete') {
7264 fireContentLoadedEvent();
7268 if (document.addEventListener) {
7269 document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
7271 document.attachEvent('onreadystatechange', checkReadyState);
7272 if (window == top) TIMER = pollDoScroll.defer();
7275 Event.observe(window, 'load', fireContentLoadedEvent);
7279Element.addMethods();
7280/*------------------------------- DEPRECATED -------------------------------*/
7282Hash.toQueryString = Object.toQueryString;
7284var Toggle = { display: Element.toggle };
7286Element.Methods.childOf = Element.Methods.descendantOf;
7289 Before: function(element, content) {
7290 return Element.insert(element, {before:content});
7293 Top: function(element, content) {
7294 return Element.insert(element, {top:content});
7297 Bottom: function(element, content) {
7298 return Element.insert(element, {bottom:content});
7301 After: function(element, content) {
7302 return Element.insert(element, {after:content});
7306var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
7309 includeScrollOffsets: false,
7311 prepare: function() {
7312 this.deltaX = window.pageXOffset
7313 || document.documentElement.scrollLeft
7314 || document.body.scrollLeft
7316 this.deltaY = window.pageYOffset
7317 || document.documentElement.scrollTop
7318 || document.body.scrollTop
7322 within: function(element, x, y) {
7323 if (this.includeScrollOffsets)
7324 return this.withinIncludingScrolloffsets(element, x, y);
7327 this.offset = Element.cumulativeOffset(element);
7329 return (y >= this.offset[1] &&
7330 y < this.offset[1] + element.offsetHeight &&
7331 x >= this.offset[0] &&
7332 x < this.offset[0] + element.offsetWidth);
7335 withinIncludingScrolloffsets: function(element, x, y) {
7336 var offsetcache = Element.cumulativeScrollOffset(element);
7338 this.xcomp = x + offsetcache[0] - this.deltaX;
7339 this.ycomp = y + offsetcache[1] - this.deltaY;
7340 this.offset = Element.cumulativeOffset(element);
7342 return (this.ycomp >= this.offset[1] &&
7343 this.ycomp < this.offset[1] + element.offsetHeight &&
7344 this.xcomp >= this.offset[0] &&
7345 this.xcomp < this.offset[0] + element.offsetWidth);
7348 overlap: function(mode, element) {
7349 if (!mode) return 0;
7350 if (mode == 'vertical')
7351 return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
7352 element.offsetHeight;
7353 if (mode == 'horizontal')
7354 return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
7355 element.offsetWidth;
7359 cumulativeOffset: Element.Methods.cumulativeOffset,
7361 positionedOffset: Element.Methods.positionedOffset,
7363 absolutize: function(element) {
7365 return Element.absolutize(element);
7368 relativize: function(element) {
7370 return Element.relativize(element);
7373 realOffset: Element.Methods.cumulativeScrollOffset,
7375 offsetParent: Element.Methods.getOffsetParent,
7377 page: Element.Methods.viewportOffset,
7379 clone: function(source, target, options) {
7380 options = options || { };
7381 return Element.clonePosition(target, source, options);
7385/*--------------------------------------------------------------------------*/
7387if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
7388 function iter(name) {
7389 return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
7392 instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
7393 function(element, className) {
7394 className = className.toString().strip();
7395 var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
7396 return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
7397 } : function(element, className) {
7398 className = className.toString().strip();
7399 var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
7400 if (!classNames && !className) return elements;
7402 var nodes = $(element).getElementsByTagName('*');
7403 className = ' ' + className + ' ';
7405 for (var i = 0, child, cn; child = nodes[i]; i++) {
7406 if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
7407 (classNames && classNames.all(function(name) {
7408 return !name.toString().blank() && cn.include(' ' + name + ' ');
7410 elements.push(Element.extend(child));
7415 return function(className, parentElement) {
7416 return $(parentElement || document.body).getElementsByClassName(className);
7420/*--------------------------------------------------------------------------*/
7422Element.ClassNames = Class.create();
7423Element.ClassNames.prototype = {
7424 initialize: function(element) {
7425 this.element = $(element);
7428 _each: function(iterator, context) {
7429 this.element.className.split(/\s+/).select(function(name) {
7430 return name.length > 0;
7431 })._each(iterator, context);
7434 set: function(className) {
7435 this.element.className = className;
7438 add: function(classNameToAdd) {
7439 if (this.include(classNameToAdd)) return;
7440 this.set($A(this).concat(classNameToAdd).join(' '));
7443 remove: function(classNameToRemove) {
7444 if (!this.include(classNameToRemove)) return;
7445 this.set($A(this).without(classNameToRemove).join(' '));
7448 toString: function() {
7449 return $A(this).join(' ');
7453Object.extend(Element.ClassNames.prototype, Enumerable);
7455/*--------------------------------------------------------------------------*/
7458 window.Selector = Class.create({
7459 initialize: function(expression) {
7460 this.expression = expression.strip();
7463 findElements: function(rootElement) {
7464 return Prototype.Selector.select(this.expression, rootElement);
7467 match: function(element) {
7468 return Prototype.Selector.match(element, this.expression);
7471 toString: function() {
7472 return this.expression;
7475 inspect: function() {
7476 return "#<Selector: " + this.expression + ">";
7480 Object.extend(Selector, {
7481 matchElements: function(elements, expression) {
7482 var match = Prototype.Selector.match,
7485 for (var i = 0, length = elements.length; i < length; i++) {
7486 var element = elements[i];
7487 if (match(element, expression)) {
7488 results.push(Element.extend(element));
7494 findElement: function(elements, expression, index) {
7496 var matchIndex = 0, element;
7497 for (var i = 0, length = elements.length; i < length; i++) {
7498 element = elements[i];
7499 if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
7500 return Element.extend(element);
7505 findChildElements: function(element, expressions) {
7506 var selector = expressions.toArray().join(', ');
7507 return Prototype.Selector.select(selector, element || document);