Index: chrome/test/data/dromaeo/lib/prototype.js |
diff --git a/chrome/test/data/dromaeo/lib/prototype.js b/chrome/test/data/dromaeo/lib/prototype.js |
index dfe8ab4e13652153903d481a1b006878df6a1f3b..474b2231bbdd2b9756ae0a4cf62c20496695e891 100644 |
--- a/chrome/test/data/dromaeo/lib/prototype.js |
+++ b/chrome/test/data/dromaeo/lib/prototype.js |
@@ -1,5 +1,5 @@ |
-/* Prototype JavaScript framework, version 1.6.0.3 |
- * (c) 2005-2008 Sam Stephenson |
+/* Prototype JavaScript framework, version 1.7 |
+ * (c) 2005-2010 Sam Stephenson |
* |
* Prototype is freely distributable under the terms of an MIT-style license. |
* For details, see the Prototype web site: http://www.prototypejs.org/ |
@@ -7,32 +7,53 @@ |
*--------------------------------------------------------------------------*/ |
var Prototype = { |
- Version: '1.6.0.3', |
- |
- Browser: { |
- IE: !!(window.attachEvent && |
- navigator.userAgent.indexOf('Opera') === -1), |
- Opera: navigator.userAgent.indexOf('Opera') > -1, |
- WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, |
- Gecko: navigator.userAgent.indexOf('Gecko') > -1 && |
- navigator.userAgent.indexOf('KHTML') === -1, |
- MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) |
- }, |
+ |
+ Version: '1.7', |
+ |
+ Browser: (function(){ |
+ var ua = navigator.userAgent; |
+ var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; |
+ return { |
+ IE: !!window.attachEvent && !isOpera, |
+ Opera: isOpera, |
+ WebKit: ua.indexOf('AppleWebKit/') > -1, |
+ Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, |
+ MobileSafari: /Apple.*Mobile/.test(ua) |
+ } |
+ })(), |
BrowserFeatures: { |
XPath: !!document.evaluate, |
+ |
SelectorsAPI: !!document.querySelector, |
- ElementExtensions: !!window.HTMLElement, |
- SpecificElementExtensions: |
- document.createElement('div')['__proto__'] && |
- document.createElement('div')['__proto__'] !== |
- document.createElement('form')['__proto__'] |
+ |
+ ElementExtensions: (function() { |
+ var constructor = window.Element || window.HTMLElement; |
+ return !!(constructor && constructor.prototype); |
+ })(), |
+ SpecificElementExtensions: (function() { |
+ if (typeof window.HTMLDivElement !== 'undefined') |
+ return true; |
+ |
+ var div = document.createElement('div'), |
+ form = document.createElement('form'), |
+ isSupported = false; |
+ |
+ if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { |
+ isSupported = true; |
+ } |
+ |
+ div = form = null; |
+ |
+ return isSupported; |
+ })() |
}, |
ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', |
JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, |
emptyFunction: function() { }, |
+ |
K: function(x) { return x } |
}; |
@@ -40,9 +61,38 @@ if (Prototype.Browser.MobileSafari) |
Prototype.BrowserFeatures.SpecificElementExtensions = false; |
+var Abstract = { }; |
+ |
+ |
+var Try = { |
+ these: function() { |
+ var returnValue; |
+ |
+ for (var i = 0, length = arguments.length; i < length; i++) { |
+ var lambda = arguments[i]; |
+ try { |
+ returnValue = lambda(); |
+ break; |
+ } catch (e) { } |
+ } |
+ |
+ return returnValue; |
+ } |
+}; |
+ |
/* Based on Alex Arnell's inheritance implementation. */ |
-var Class = { |
- create: function() { |
+ |
+var Class = (function() { |
+ |
+ var IS_DONTENUM_BUGGY = (function(){ |
+ for (var p in { toString: 1 }) { |
+ if (p === 'toString') return false; |
+ } |
+ return true; |
+ })(); |
+ |
+ function subclass() {}; |
+ function create() { |
var parent = null, properties = $A(arguments); |
if (Object.isFunction(properties[0])) |
parent = properties.shift(); |
@@ -56,39 +106,39 @@ var Class = { |
klass.subclasses = []; |
if (parent) { |
- var subclass = function() { }; |
subclass.prototype = parent.prototype; |
klass.prototype = new subclass; |
parent.subclasses.push(klass); |
} |
- for (var i = 0; i < properties.length; i++) |
+ for (var i = 0, length = properties.length; i < length; i++) |
klass.addMethods(properties[i]); |
if (!klass.prototype.initialize) |
klass.prototype.initialize = Prototype.emptyFunction; |
klass.prototype.constructor = klass; |
- |
return klass; |
} |
-}; |
-Class.Methods = { |
- addMethods: function(source) { |
- var ancestor = this.superclass && this.superclass.prototype; |
- var properties = Object.keys(source); |
+ function addMethods(source) { |
+ var ancestor = this.superclass && this.superclass.prototype, |
+ properties = Object.keys(source); |
- if (!Object.keys({ toString: true }).length) |
- properties.push("toString", "valueOf"); |
+ if (IS_DONTENUM_BUGGY) { |
+ if (source.toString != Object.prototype.toString) |
+ properties.push("toString"); |
+ if (source.valueOf != Object.prototype.valueOf) |
+ properties.push("valueOf"); |
+ } |
for (var i = 0, length = properties.length; i < length; i++) { |
var property = properties[i], value = source[property]; |
if (ancestor && Object.isFunction(value) && |
- value.argumentNames().first() == "$super") { |
+ value.argumentNames()[0] == "$super") { |
var method = value; |
value = (function(m) { |
- return function() { return ancestor[m].apply(this, arguments) }; |
+ return function() { return ancestor[m].apply(this, arguments); }; |
})(property).wrap(method); |
value.valueOf = method.valueOf.bind(method); |
@@ -99,198 +149,338 @@ Class.Methods = { |
return this; |
} |
-}; |
-var Abstract = { }; |
+ return { |
+ create: create, |
+ Methods: { |
+ addMethods: addMethods |
+ } |
+ }; |
+})(); |
+(function() { |
-Object.extend = function(destination, source) { |
- for (var property in source) |
- destination[property] = source[property]; |
- return destination; |
-}; |
+ var _toString = Object.prototype.toString, |
+ NULL_TYPE = 'Null', |
+ UNDEFINED_TYPE = 'Undefined', |
+ BOOLEAN_TYPE = 'Boolean', |
+ NUMBER_TYPE = 'Number', |
+ STRING_TYPE = 'String', |
+ OBJECT_TYPE = 'Object', |
+ FUNCTION_CLASS = '[object Function]', |
+ BOOLEAN_CLASS = '[object Boolean]', |
+ NUMBER_CLASS = '[object Number]', |
+ STRING_CLASS = '[object String]', |
+ ARRAY_CLASS = '[object Array]', |
+ DATE_CLASS = '[object Date]', |
+ NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && |
+ typeof JSON.stringify === 'function' && |
+ JSON.stringify(0) === '0' && |
+ typeof JSON.stringify(Prototype.K) === 'undefined'; |
+ |
+ function Type(o) { |
+ switch(o) { |
+ case null: return NULL_TYPE; |
+ case (void 0): return UNDEFINED_TYPE; |
+ } |
+ var type = typeof o; |
+ switch(type) { |
+ case 'boolean': return BOOLEAN_TYPE; |
+ case 'number': return NUMBER_TYPE; |
+ case 'string': return STRING_TYPE; |
+ } |
+ return OBJECT_TYPE; |
+ } |
+ |
+ function extend(destination, source) { |
+ for (var property in source) |
+ destination[property] = source[property]; |
+ return destination; |
+ } |
-Object.extend(Object, { |
- inspect: function(object) { |
+ function inspect(object) { |
try { |
- if (Object.isUndefined(object)) return 'undefined'; |
+ if (isUndefined(object)) return 'undefined'; |
if (object === null) return 'null'; |
return object.inspect ? object.inspect() : String(object); |
} catch (e) { |
if (e instanceof RangeError) return '...'; |
throw e; |
} |
- }, |
+ } |
- toJSON: function(object) { |
- var type = typeof object; |
- switch (type) { |
- case 'undefined': |
- case 'function': |
- case 'unknown': return; |
- case 'boolean': return object.toString(); |
+ function toJSON(value) { |
+ return Str('', { '': value }, []); |
+ } |
+ |
+ function Str(key, holder, stack) { |
+ var value = holder[key], |
+ type = typeof value; |
+ |
+ if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { |
+ value = value.toJSON(key); |
} |
- if (object === null) return 'null'; |
- if (object.toJSON) return object.toJSON(); |
- if (Object.isElement(object)) return; |
+ var _class = _toString.call(value); |
- var results = []; |
- for (var property in object) { |
- var value = Object.toJSON(object[property]); |
- if (!Object.isUndefined(value)) |
- results.push(property.toJSON() + ': ' + value); |
+ switch (_class) { |
+ case NUMBER_CLASS: |
+ case BOOLEAN_CLASS: |
+ case STRING_CLASS: |
+ value = value.valueOf(); |
} |
- return '{' + results.join(', ') + '}'; |
- }, |
+ switch (value) { |
+ case null: return 'null'; |
+ case true: return 'true'; |
+ case false: return 'false'; |
+ } |
+ |
+ type = typeof value; |
+ switch (type) { |
+ case 'string': |
+ return value.inspect(true); |
+ case 'number': |
+ return isFinite(value) ? String(value) : 'null'; |
+ case 'object': |
+ |
+ for (var i = 0, length = stack.length; i < length; i++) { |
+ if (stack[i] === value) { throw new TypeError(); } |
+ } |
+ stack.push(value); |
- toQueryString: function(object) { |
+ var partial = []; |
+ if (_class === ARRAY_CLASS) { |
+ for (var i = 0, length = value.length; i < length; i++) { |
+ var str = Str(i, value, stack); |
+ partial.push(typeof str === 'undefined' ? 'null' : str); |
+ } |
+ partial = '[' + partial.join(',') + ']'; |
+ } else { |
+ var keys = Object.keys(value); |
+ for (var i = 0, length = keys.length; i < length; i++) { |
+ var key = keys[i], str = Str(key, value, stack); |
+ if (typeof str !== "undefined") { |
+ partial.push(key.inspect(true)+ ':' + str); |
+ } |
+ } |
+ partial = '{' + partial.join(',') + '}'; |
+ } |
+ stack.pop(); |
+ return partial; |
+ } |
+ } |
+ |
+ function stringify(object) { |
+ return JSON.stringify(object); |
+ } |
+ |
+ function toQueryString(object) { |
return $H(object).toQueryString(); |
- }, |
+ } |
- toHTML: function(object) { |
+ function toHTML(object) { |
return object && object.toHTML ? object.toHTML() : String.interpret(object); |
- }, |
+ } |
- keys: function(object) { |
- var keys = []; |
- for (var property in object) |
- keys.push(property); |
- return keys; |
- }, |
+ function keys(object) { |
+ if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } |
+ var results = []; |
+ for (var property in object) { |
+ if (object.hasOwnProperty(property)) { |
+ results.push(property); |
+ } |
+ } |
+ return results; |
+ } |
- values: function(object) { |
- var values = []; |
+ function values(object) { |
+ var results = []; |
for (var property in object) |
- values.push(object[property]); |
- return values; |
- }, |
+ results.push(object[property]); |
+ return results; |
+ } |
- clone: function(object) { |
- return Object.extend({ }, object); |
- }, |
+ function clone(object) { |
+ return extend({ }, object); |
+ } |
- isElement: function(object) { |
+ function isElement(object) { |
return !!(object && object.nodeType == 1); |
- }, |
+ } |
- isArray: function(object) { |
- return object != null && typeof object == "object" && |
- 'splice' in object && 'join' in object; |
- }, |
+ function isArray(object) { |
+ return _toString.call(object) === ARRAY_CLASS; |
+ } |
+ |
+ var hasNativeIsArray = (typeof Array.isArray == 'function') |
+ && Array.isArray([]) && !Array.isArray({}); |
- isHash: function(object) { |
+ if (hasNativeIsArray) { |
+ isArray = Array.isArray; |
+ } |
+ |
+ function isHash(object) { |
return object instanceof Hash; |
- }, |
+ } |
- isFunction: function(object) { |
- return typeof object == "function"; |
- }, |
+ function isFunction(object) { |
+ return _toString.call(object) === FUNCTION_CLASS; |
+ } |
- isString: function(object) { |
- return typeof object == "string"; |
- }, |
+ function isString(object) { |
+ return _toString.call(object) === STRING_CLASS; |
+ } |
- isNumber: function(object) { |
- return typeof object == "number"; |
- }, |
+ function isNumber(object) { |
+ return _toString.call(object) === NUMBER_CLASS; |
+ } |
- isUndefined: function(object) { |
- return typeof object == "undefined"; |
+ function isDate(object) { |
+ return _toString.call(object) === DATE_CLASS; |
} |
-}); |
-Object.extend(Function.prototype, { |
- argumentNames: function() { |
- var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1] |
+ function isUndefined(object) { |
+ return typeof object === "undefined"; |
+ } |
+ |
+ extend(Object, { |
+ extend: extend, |
+ inspect: inspect, |
+ toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON, |
+ toQueryString: toQueryString, |
+ toHTML: toHTML, |
+ keys: Object.keys || keys, |
+ values: values, |
+ clone: clone, |
+ isElement: isElement, |
+ isArray: isArray, |
+ isHash: isHash, |
+ isFunction: isFunction, |
+ isString: isString, |
+ isNumber: isNumber, |
+ isDate: isDate, |
+ isUndefined: isUndefined |
+ }); |
+})(); |
+Object.extend(Function.prototype, (function() { |
+ var slice = Array.prototype.slice; |
+ |
+ function update(array, args) { |
+ var arrayLength = array.length, length = args.length; |
+ while (length--) array[arrayLength + length] = args[length]; |
+ return array; |
+ } |
+ |
+ function merge(array, args) { |
+ array = slice.call(array, 0); |
+ return update(array, args); |
+ } |
+ |
+ function argumentNames() { |
+ var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] |
+ .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') |
.replace(/\s+/g, '').split(','); |
return names.length == 1 && !names[0] ? [] : names; |
- }, |
+ } |
- bind: function() { |
+ function bind(context) { |
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; |
- var __method = this, args = $A(arguments), object = args.shift(); |
+ var __method = this, args = slice.call(arguments, 1); |
return function() { |
- return __method.apply(object, args.concat($A(arguments))); |
+ var a = merge(args, arguments); |
+ return __method.apply(context, a); |
} |
- }, |
+ } |
- bindAsEventListener: function() { |
- var __method = this, args = $A(arguments), object = args.shift(); |
+ function bindAsEventListener(context) { |
+ var __method = this, args = slice.call(arguments, 1); |
return function(event) { |
- return __method.apply(object, [event || window.event].concat(args)); |
+ var a = update([event || window.event], args); |
+ return __method.apply(context, a); |
} |
- }, |
+ } |
- curry: function() { |
+ function curry() { |
if (!arguments.length) return this; |
- var __method = this, args = $A(arguments); |
+ var __method = this, args = slice.call(arguments, 0); |
return function() { |
- return __method.apply(this, args.concat($A(arguments))); |
+ var a = merge(args, arguments); |
+ return __method.apply(this, a); |
} |
- }, |
+ } |
- delay: function() { |
- var __method = this, args = $A(arguments), timeout = args.shift() * 1000; |
+ function delay(timeout) { |
+ var __method = this, args = slice.call(arguments, 1); |
+ timeout = timeout * 1000; |
return window.setTimeout(function() { |
return __method.apply(__method, args); |
}, timeout); |
- }, |
+ } |
- defer: function() { |
- var args = [0.01].concat($A(arguments)); |
+ function defer() { |
+ var args = update([0.01], arguments); |
return this.delay.apply(this, args); |
- }, |
+ } |
- wrap: function(wrapper) { |
+ function wrap(wrapper) { |
var __method = this; |
return function() { |
- return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); |
+ var a = update([__method.bind(this)], arguments); |
+ return wrapper.apply(this, a); |
} |
- }, |
+ } |
- methodize: function() { |
+ function methodize() { |
if (this._methodized) return this._methodized; |
var __method = this; |
return this._methodized = function() { |
- return __method.apply(null, [this].concat($A(arguments))); |
+ var a = update([this], arguments); |
+ return __method.apply(null, a); |
}; |
} |
-}); |
-Date.prototype.toJSON = function() { |
- return '"' + this.getUTCFullYear() + '-' + |
- (this.getUTCMonth() + 1).toPaddedString(2) + '-' + |
- this.getUTCDate().toPaddedString(2) + 'T' + |
- this.getUTCHours().toPaddedString(2) + ':' + |
- this.getUTCMinutes().toPaddedString(2) + ':' + |
- this.getUTCSeconds().toPaddedString(2) + 'Z"'; |
-}; |
+ return { |
+ argumentNames: argumentNames, |
+ bind: bind, |
+ bindAsEventListener: bindAsEventListener, |
+ curry: curry, |
+ delay: delay, |
+ defer: defer, |
+ wrap: wrap, |
+ methodize: methodize |
+ } |
+})()); |
-var Try = { |
- these: function() { |
- var returnValue; |
- for (var i = 0, length = arguments.length; i < length; i++) { |
- var lambda = arguments[i]; |
- try { |
- returnValue = lambda(); |
- break; |
- } catch (e) { } |
- } |
- return returnValue; |
+(function(proto) { |
+ |
+ |
+ function toISOString() { |
+ return this.getUTCFullYear() + '-' + |
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' + |
+ this.getUTCDate().toPaddedString(2) + 'T' + |
+ this.getUTCHours().toPaddedString(2) + ':' + |
+ this.getUTCMinutes().toPaddedString(2) + ':' + |
+ this.getUTCSeconds().toPaddedString(2) + 'Z'; |
} |
-}; |
+ |
+ |
+ function toJSON() { |
+ return this.toISOString(); |
+ } |
+ |
+ if (!proto.toISOString) proto.toISOString = toISOString; |
+ if (!proto.toJSON) proto.toJSON = toJSON; |
+ |
+})(Date.prototype); |
+ |
RegExp.prototype.match = RegExp.prototype.test; |
RegExp.escape = function(str) { |
return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); |
}; |
- |
-/*--------------------------------------------------------------------------*/ |
- |
var PeriodicalExecuter = Class.create({ |
initialize: function(callback, frequency) { |
this.callback = callback; |
@@ -319,8 +509,10 @@ var PeriodicalExecuter = Class.create({ |
try { |
this.currentlyExecuting = true; |
this.execute(); |
- } finally { |
this.currentlyExecuting = false; |
+ } catch(e) { |
+ this.currentlyExecuting = false; |
+ throw e; |
} |
} |
} |
@@ -339,10 +531,28 @@ Object.extend(String, { |
} |
}); |
-Object.extend(String.prototype, { |
- gsub: function(pattern, replacement) { |
+Object.extend(String.prototype, (function() { |
+ var NATIVE_JSON_PARSE_SUPPORT = window.JSON && |
+ typeof JSON.parse === 'function' && |
+ JSON.parse('{"test": true}').test; |
+ |
+ function prepareReplacement(replacement) { |
+ if (Object.isFunction(replacement)) return replacement; |
+ var template = new Template(replacement); |
+ return function(match) { return template.evaluate(match) }; |
+ } |
+ |
+ function gsub(pattern, replacement) { |
var result = '', source = this, match; |
- replacement = arguments.callee.prepareReplacement(replacement); |
+ replacement = prepareReplacement(replacement); |
+ |
+ if (Object.isString(pattern)) |
+ pattern = RegExp.escape(pattern); |
+ |
+ if (!(pattern.length || pattern.source)) { |
+ replacement = replacement(''); |
+ return replacement + source.split('').join(replacement) + replacement; |
+ } |
while (source.length > 0) { |
if (match = source.match(pattern)) { |
@@ -354,76 +564,72 @@ Object.extend(String.prototype, { |
} |
} |
return result; |
- }, |
+ } |
- sub: function(pattern, replacement, count) { |
- replacement = this.gsub.prepareReplacement(replacement); |
+ function sub(pattern, replacement, count) { |
+ replacement = prepareReplacement(replacement); |
count = Object.isUndefined(count) ? 1 : count; |
return this.gsub(pattern, function(match) { |
if (--count < 0) return match[0]; |
return replacement(match); |
}); |
- }, |
+ } |
- scan: function(pattern, iterator) { |
+ function scan(pattern, iterator) { |
this.gsub(pattern, iterator); |
return String(this); |
- }, |
+ } |
- truncate: function(length, truncation) { |
+ function truncate(length, truncation) { |
length = length || 30; |
truncation = Object.isUndefined(truncation) ? '...' : truncation; |
return this.length > length ? |
this.slice(0, length - truncation.length) + truncation : String(this); |
- }, |
+ } |
- strip: function() { |
+ function strip() { |
return this.replace(/^\s+/, '').replace(/\s+$/, ''); |
- }, |
+ } |
- stripTags: function() { |
- return this.replace(/<\/?[^>]+>/gi, ''); |
- }, |
+ function stripTags() { |
+ return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); |
+ } |
- stripScripts: function() { |
+ function stripScripts() { |
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); |
- }, |
+ } |
- extractScripts: function() { |
- var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); |
- var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); |
+ function extractScripts() { |
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img'), |
+ matchOne = new RegExp(Prototype.ScriptFragment, 'im'); |
return (this.match(matchAll) || []).map(function(scriptTag) { |
return (scriptTag.match(matchOne) || ['', ''])[1]; |
}); |
- }, |
+ } |
- evalScripts: function() { |
+ function evalScripts() { |
return this.extractScripts().map(function(script) { return eval(script) }); |
- }, |
+ } |
- escapeHTML: function() { |
- var self = arguments.callee; |
- self.text.data = this; |
- return self.div.innerHTML; |
- }, |
+ function escapeHTML() { |
+ return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); |
+ } |
+ |
+ function unescapeHTML() { |
+ return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); |
+ } |
- unescapeHTML: function() { |
- var div = new Element('div'); |
- div.innerHTML = this.stripTags(); |
- return div.childNodes[0] ? (div.childNodes.length > 1 ? |
- $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : |
- div.childNodes[0].nodeValue) : ''; |
- }, |
- toQueryParams: function(separator) { |
+ function toQueryParams(separator) { |
var match = this.strip().match(/([^?#]*)(#.*)?$/); |
if (!match) return { }; |
return match[1].split(separator || '&').inject({ }, function(hash, pair) { |
if ((pair = pair.split('='))[0]) { |
- var key = decodeURIComponent(pair.shift()); |
- var value = pair.length > 1 ? pair.join('=') : pair[0]; |
+ var key = decodeURIComponent(pair.shift()), |
+ value = pair.length > 1 ? pair.join('=') : pair[0]; |
+ |
if (value != undefined) value = decodeURIComponent(value); |
if (key in hash) { |
@@ -434,128 +640,144 @@ Object.extend(String.prototype, { |
} |
return hash; |
}); |
- }, |
+ } |
- toArray: function() { |
+ function toArray() { |
return this.split(''); |
- }, |
+ } |
- succ: function() { |
+ function succ() { |
return this.slice(0, this.length - 1) + |
String.fromCharCode(this.charCodeAt(this.length - 1) + 1); |
- }, |
+ } |
- times: function(count) { |
+ function times(count) { |
return count < 1 ? '' : new Array(count + 1).join(this); |
- }, |
- |
- camelize: function() { |
- var parts = this.split('-'), len = parts.length; |
- if (len == 1) return parts[0]; |
- |
- var camelized = this.charAt(0) == '-' |
- ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) |
- : parts[0]; |
- |
- for (var i = 1; i < len; i++) |
- camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); |
+ } |
- return camelized; |
- }, |
+ function camelize() { |
+ return this.replace(/-+(.)?/g, function(match, chr) { |
+ return chr ? chr.toUpperCase() : ''; |
+ }); |
+ } |
- capitalize: function() { |
+ function capitalize() { |
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); |
- }, |
+ } |
- underscore: function() { |
- return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); |
- }, |
+ function underscore() { |
+ return this.replace(/::/g, '/') |
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') |
+ .replace(/([a-z\d])([A-Z])/g, '$1_$2') |
+ .replace(/-/g, '_') |
+ .toLowerCase(); |
+ } |
- dasherize: function() { |
- return this.gsub(/_/,'-'); |
- }, |
+ function dasherize() { |
+ return this.replace(/_/g, '-'); |
+ } |
- inspect: function(useDoubleQuotes) { |
- var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { |
- var character = String.specialChar[match[0]]; |
- return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); |
+ function inspect(useDoubleQuotes) { |
+ var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { |
+ if (character in String.specialChar) { |
+ return String.specialChar[character]; |
+ } |
+ return '\\u00' + character.charCodeAt().toPaddedString(2, 16); |
}); |
if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; |
return "'" + escapedString.replace(/'/g, '\\\'') + "'"; |
- }, |
- |
- toJSON: function() { |
- return this.inspect(true); |
- }, |
+ } |
- unfilterJSON: function(filter) { |
- return this.sub(filter || Prototype.JSONFilter, '#{1}'); |
- }, |
+ function unfilterJSON(filter) { |
+ return this.replace(filter || Prototype.JSONFilter, '$1'); |
+ } |
- isJSON: function() { |
+ function isJSON() { |
var str = this; |
if (str.blank()) return false; |
- str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); |
- return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); |
- }, |
+ str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'); |
+ str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); |
+ str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); |
+ return (/^[\],:{}\s]*$/).test(str); |
+ } |
- evalJSON: function(sanitize) { |
- var json = this.unfilterJSON(); |
+ function evalJSON(sanitize) { |
+ var json = this.unfilterJSON(), |
+ cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; |
+ if (cx.test(json)) { |
+ json = json.replace(cx, function (a) { |
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); |
+ }); |
+ } |
try { |
if (!sanitize || json.isJSON()) return eval('(' + json + ')'); |
} catch (e) { } |
throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); |
- }, |
+ } |
+ |
+ function parseJSON() { |
+ var json = this.unfilterJSON(); |
+ return JSON.parse(json); |
+ } |
- include: function(pattern) { |
+ function include(pattern) { |
return this.indexOf(pattern) > -1; |
- }, |
+ } |
- startsWith: function(pattern) { |
- return this.indexOf(pattern) === 0; |
- }, |
+ function startsWith(pattern) { |
+ return this.lastIndexOf(pattern, 0) === 0; |
+ } |
- endsWith: function(pattern) { |
+ function endsWith(pattern) { |
var d = this.length - pattern.length; |
- return d >= 0 && this.lastIndexOf(pattern) === d; |
- }, |
+ return d >= 0 && this.indexOf(pattern, d) === d; |
+ } |
- empty: function() { |
+ function empty() { |
return this == ''; |
- }, |
+ } |
- blank: function() { |
+ function blank() { |
return /^\s*$/.test(this); |
- }, |
- |
- interpolate: function(object, pattern) { |
- return new Template(this, pattern).evaluate(object); |
} |
-}); |
-if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { |
- escapeHTML: function() { |
- return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); |
- }, |
- unescapeHTML: function() { |
- return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); |
+ function interpolate(object, pattern) { |
+ return new Template(this, pattern).evaluate(object); |
} |
-}); |
- |
-String.prototype.gsub.prepareReplacement = function(replacement) { |
- if (Object.isFunction(replacement)) return replacement; |
- var template = new Template(replacement); |
- return function(match) { return template.evaluate(match) }; |
-}; |
- |
-String.prototype.parseQuery = String.prototype.toQueryParams; |
- |
-Object.extend(String.prototype.escapeHTML, { |
- div: document.createElement('div'), |
- text: document.createTextNode('') |
-}); |
-String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); |
+ return { |
+ gsub: gsub, |
+ sub: sub, |
+ scan: scan, |
+ truncate: truncate, |
+ strip: String.prototype.trim || strip, |
+ stripTags: stripTags, |
+ stripScripts: stripScripts, |
+ extractScripts: extractScripts, |
+ evalScripts: evalScripts, |
+ escapeHTML: escapeHTML, |
+ unescapeHTML: unescapeHTML, |
+ toQueryParams: toQueryParams, |
+ parseQuery: toQueryParams, |
+ toArray: toArray, |
+ succ: succ, |
+ times: times, |
+ camelize: camelize, |
+ capitalize: capitalize, |
+ underscore: underscore, |
+ dasherize: dasherize, |
+ inspect: inspect, |
+ unfilterJSON: unfilterJSON, |
+ isJSON: isJSON, |
+ evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON, |
+ include: include, |
+ startsWith: startsWith, |
+ endsWith: endsWith, |
+ empty: empty, |
+ blank: blank, |
+ interpolate: interpolate |
+ }; |
+})()); |
var Template = Class.create({ |
initialize: function(template, pattern) { |
@@ -564,22 +786,23 @@ var Template = Class.create({ |
}, |
evaluate: function(object) { |
- if (Object.isFunction(object.toTemplateReplacements)) |
+ if (object && Object.isFunction(object.toTemplateReplacements)) |
object = object.toTemplateReplacements(); |
return this.template.gsub(this.pattern, function(match) { |
- if (object == null) return ''; |
+ if (object == null) return (match[1] + ''); |
var before = match[1] || ''; |
if (before == '\\') return match[2]; |
- var ctx = object, expr = match[3]; |
- var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; |
+ var ctx = object, expr = match[3], |
+ pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; |
+ |
match = pattern.exec(expr); |
if (match == null) return before; |
while (match != null) { |
- var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; |
+ var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; |
ctx = ctx[comp]; |
if (null == ctx || '' == match[3]) break; |
expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); |
@@ -594,8 +817,8 @@ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; |
var $break = { }; |
-var Enumerable = { |
- each: function(iterator, context) { |
+var Enumerable = (function() { |
+ function each(iterator, context) { |
var index = 0; |
try { |
this._each(function(value) { |
@@ -605,17 +828,17 @@ var Enumerable = { |
if (e != $break) throw e; |
} |
return this; |
- }, |
+ } |
- eachSlice: function(number, iterator, context) { |
+ function eachSlice(number, iterator, context) { |
var index = -number, slices = [], array = this.toArray(); |
if (number < 1) return array; |
while ((index += number) < array.length) |
slices.push(array.slice(index, index+number)); |
return slices.collect(iterator, context); |
- }, |
+ } |
- all: function(iterator, context) { |
+ function all(iterator, context) { |
iterator = iterator || Prototype.K; |
var result = true; |
this.each(function(value, index) { |
@@ -623,9 +846,9 @@ var Enumerable = { |
if (!result) throw $break; |
}); |
return result; |
- }, |
+ } |
- any: function(iterator, context) { |
+ function any(iterator, context) { |
iterator = iterator || Prototype.K; |
var result = false; |
this.each(function(value, index) { |
@@ -633,18 +856,18 @@ var Enumerable = { |
throw $break; |
}); |
return result; |
- }, |
+ } |
- collect: function(iterator, context) { |
+ function collect(iterator, context) { |
iterator = iterator || Prototype.K; |
var results = []; |
this.each(function(value, index) { |
results.push(iterator.call(context, value, index)); |
}); |
return results; |
- }, |
+ } |
- detect: function(iterator, context) { |
+ function detect(iterator, context) { |
var result; |
this.each(function(value, index) { |
if (iterator.call(context, value, index)) { |
@@ -653,32 +876,32 @@ var Enumerable = { |
} |
}); |
return result; |
- }, |
+ } |
- findAll: function(iterator, context) { |
+ function findAll(iterator, context) { |
var results = []; |
this.each(function(value, index) { |
if (iterator.call(context, value, index)) |
results.push(value); |
}); |
return results; |
- }, |
+ } |
- grep: function(filter, iterator, context) { |
+ function grep(filter, iterator, context) { |
iterator = iterator || Prototype.K; |
var results = []; |
if (Object.isString(filter)) |
- filter = new RegExp(filter); |
+ filter = new RegExp(RegExp.escape(filter)); |
this.each(function(value, index) { |
if (filter.match(value)) |
results.push(iterator.call(context, value, index)); |
}); |
return results; |
- }, |
+ } |
- include: function(object) { |
+ function include(object) { |
if (Object.isFunction(this.indexOf)) |
if (this.indexOf(object) != -1) return true; |
@@ -690,31 +913,31 @@ var Enumerable = { |
} |
}); |
return found; |
- }, |
+ } |
- inGroupsOf: function(number, fillWith) { |
+ function inGroupsOf(number, fillWith) { |
fillWith = Object.isUndefined(fillWith) ? null : fillWith; |
return this.eachSlice(number, function(slice) { |
while(slice.length < number) slice.push(fillWith); |
return slice; |
}); |
- }, |
+ } |
- inject: function(memo, iterator, context) { |
+ function inject(memo, iterator, context) { |
this.each(function(value, index) { |
memo = iterator.call(context, memo, value, index); |
}); |
return memo; |
- }, |
+ } |
- invoke: function(method) { |
+ function invoke(method) { |
var args = $A(arguments).slice(1); |
return this.map(function(value) { |
return value[method].apply(value, args); |
}); |
- }, |
+ } |
- max: function(iterator, context) { |
+ function max(iterator, context) { |
iterator = iterator || Prototype.K; |
var result; |
this.each(function(value, index) { |
@@ -723,9 +946,9 @@ var Enumerable = { |
result = value; |
}); |
return result; |
- }, |
+ } |
- min: function(iterator, context) { |
+ function min(iterator, context) { |
iterator = iterator || Prototype.K; |
var result; |
this.each(function(value, index) { |
@@ -734,9 +957,9 @@ var Enumerable = { |
result = value; |
}); |
return result; |
- }, |
+ } |
- partition: function(iterator, context) { |
+ function partition(iterator, context) { |
iterator = iterator || Prototype.K; |
var trues = [], falses = []; |
this.each(function(value, index) { |
@@ -744,26 +967,26 @@ var Enumerable = { |
trues : falses).push(value); |
}); |
return [trues, falses]; |
- }, |
+ } |
- pluck: function(property) { |
+ function pluck(property) { |
var results = []; |
this.each(function(value) { |
results.push(value[property]); |
}); |
return results; |
- }, |
+ } |
- reject: function(iterator, context) { |
+ function reject(iterator, context) { |
var results = []; |
this.each(function(value, index) { |
if (!iterator.call(context, value, index)) |
results.push(value); |
}); |
return results; |
- }, |
+ } |
- sortBy: function(iterator, context) { |
+ function sortBy(iterator, context) { |
return this.map(function(value, index) { |
return { |
value: value, |
@@ -773,13 +996,13 @@ var Enumerable = { |
var a = left.criteria, b = right.criteria; |
return a < b ? -1 : a > b ? 1 : 0; |
}).pluck('value'); |
- }, |
+ } |
- toArray: function() { |
+ function toArray() { |
return this.map(); |
- }, |
+ } |
- zip: function() { |
+ function zip() { |
var iterator = Prototype.K, args = $A(arguments); |
if (Object.isFunction(args.last())) |
iterator = args.pop(); |
@@ -788,336 +1011,416 @@ var Enumerable = { |
return this.map(function(value, index) { |
return iterator(collections.pluck(index)); |
}); |
- }, |
+ } |
- size: function() { |
+ function size() { |
return this.toArray().length; |
- }, |
+ } |
- inspect: function() { |
+ function inspect() { |
return '#<Enumerable:' + this.toArray().inspect() + '>'; |
} |
-}; |
-Object.extend(Enumerable, { |
- map: Enumerable.collect, |
- find: Enumerable.detect, |
- select: Enumerable.findAll, |
- filter: Enumerable.findAll, |
- member: Enumerable.include, |
- entries: Enumerable.toArray, |
- every: Enumerable.all, |
- some: Enumerable.any |
-}); |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ return { |
+ each: each, |
+ eachSlice: eachSlice, |
+ all: all, |
+ every: all, |
+ any: any, |
+ some: any, |
+ collect: collect, |
+ map: collect, |
+ detect: detect, |
+ findAll: findAll, |
+ select: findAll, |
+ filter: findAll, |
+ grep: grep, |
+ include: include, |
+ member: include, |
+ inGroupsOf: inGroupsOf, |
+ inject: inject, |
+ invoke: invoke, |
+ max: max, |
+ min: min, |
+ partition: partition, |
+ pluck: pluck, |
+ reject: reject, |
+ sortBy: sortBy, |
+ toArray: toArray, |
+ entries: toArray, |
+ zip: zip, |
+ size: size, |
+ inspect: inspect, |
+ find: detect |
+ }; |
+})(); |
+ |
function $A(iterable) { |
if (!iterable) return []; |
- if (iterable.toArray) return iterable.toArray(); |
+ if ('toArray' in Object(iterable)) return iterable.toArray(); |
var length = iterable.length || 0, results = new Array(length); |
while (length--) results[length] = iterable[length]; |
return results; |
} |
-if (Prototype.Browser.WebKit) { |
- $A = function(iterable) { |
- if (!iterable) return []; |
- // In Safari, only use the `toArray` method if it's not a NodeList. |
- // A NodeList is a function, has an function `item` property, and a numeric |
- // `length` property. Adapted from Google Doctype. |
- if (!(typeof iterable === 'function' && typeof iterable.length === |
- 'number' && typeof iterable.item === 'function') && iterable.toArray) |
- return iterable.toArray(); |
- var length = iterable.length || 0, results = new Array(length); |
- while (length--) results[length] = iterable[length]; |
- return results; |
- }; |
+ |
+function $w(string) { |
+ if (!Object.isString(string)) return []; |
+ string = string.strip(); |
+ return string ? string.split(/\s+/) : []; |
} |
Array.from = $A; |
-Object.extend(Array.prototype, Enumerable); |
-if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; |
+(function() { |
+ var arrayProto = Array.prototype, |
+ slice = arrayProto.slice, |
+ _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available |
-Object.extend(Array.prototype, { |
- _each: function(iterator) { |
- for (var i = 0, length = this.length; i < length; i++) |
- iterator(this[i]); |
- }, |
+ function each(iterator, context) { |
+ for (var i = 0, length = this.length >>> 0; i < length; i++) { |
+ if (i in this) iterator.call(context, this[i], i, this); |
+ } |
+ } |
+ if (!_each) _each = each; |
- clear: function() { |
+ function clear() { |
this.length = 0; |
return this; |
- }, |
+ } |
- first: function() { |
+ function first() { |
return this[0]; |
- }, |
+ } |
- last: function() { |
+ function last() { |
return this[this.length - 1]; |
- }, |
+ } |
- compact: function() { |
+ function compact() { |
return this.select(function(value) { |
return value != null; |
}); |
- }, |
+ } |
- flatten: function() { |
+ function flatten() { |
return this.inject([], function(array, value) { |
- return array.concat(Object.isArray(value) ? |
- value.flatten() : [value]); |
+ if (Object.isArray(value)) |
+ return array.concat(value.flatten()); |
+ array.push(value); |
+ return array; |
}); |
- }, |
+ } |
- without: function() { |
- var values = $A(arguments); |
+ function without() { |
+ var values = slice.call(arguments, 0); |
return this.select(function(value) { |
return !values.include(value); |
}); |
- }, |
- |
- reverse: function(inline) { |
- return (inline !== false ? this : this.toArray())._reverse(); |
- }, |
+ } |
- reduce: function() { |
- return this.length > 1 ? this : this[0]; |
- }, |
+ function reverse(inline) { |
+ return (inline === false ? this.toArray() : this)._reverse(); |
+ } |
- uniq: function(sorted) { |
+ function uniq(sorted) { |
return this.inject([], function(array, value, index) { |
if (0 == index || (sorted ? array.last() != value : !array.include(value))) |
array.push(value); |
return array; |
}); |
- }, |
+ } |
- intersect: function(array) { |
+ function intersect(array) { |
return this.uniq().findAll(function(item) { |
return array.detect(function(value) { return item === value }); |
}); |
- }, |
+ } |
- clone: function() { |
- return [].concat(this); |
- }, |
- size: function() { |
+ function clone() { |
+ return slice.call(this, 0); |
+ } |
+ |
+ function size() { |
return this.length; |
- }, |
+ } |
- inspect: function() { |
+ function inspect() { |
return '[' + this.map(Object.inspect).join(', ') + ']'; |
- }, |
- |
- toJSON: function() { |
- var results = []; |
- this.each(function(object) { |
- var value = Object.toJSON(object); |
- if (!Object.isUndefined(value)) results.push(value); |
- }); |
- return '[' + results.join(', ') + ']'; |
} |
-}); |
-// use native browser JS 1.6 implementation if available |
-if (Object.isFunction(Array.prototype.forEach)) |
- Array.prototype._each = Array.prototype.forEach; |
- |
-if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { |
- i || (i = 0); |
- var length = this.length; |
- if (i < 0) i = length + i; |
- for (; i < length; i++) |
- if (this[i] === item) return i; |
- return -1; |
-}; |
- |
-if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { |
- i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; |
- var n = this.slice(0, i).reverse().indexOf(item); |
- return (n < 0) ? n : i - n - 1; |
-}; |
- |
-Array.prototype.toArray = Array.prototype.clone; |
+ function indexOf(item, i) { |
+ i || (i = 0); |
+ var length = this.length; |
+ if (i < 0) i = length + i; |
+ for (; i < length; i++) |
+ if (this[i] === item) return i; |
+ return -1; |
+ } |
-function $w(string) { |
- if (!Object.isString(string)) return []; |
- string = string.strip(); |
- return string ? string.split(/\s+/) : []; |
-} |
+ function lastIndexOf(item, i) { |
+ i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; |
+ var n = this.slice(0, i).reverse().indexOf(item); |
+ return (n < 0) ? n : i - n - 1; |
+ } |
-if (Prototype.Browser.Opera){ |
- Array.prototype.concat = function() { |
- var array = []; |
- for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); |
+ function concat() { |
+ var array = slice.call(this, 0), item; |
for (var i = 0, length = arguments.length; i < length; i++) { |
- if (Object.isArray(arguments[i])) { |
- for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) |
- array.push(arguments[i][j]); |
+ item = arguments[i]; |
+ if (Object.isArray(item) && !('callee' in item)) { |
+ for (var j = 0, arrayLength = item.length; j < arrayLength; j++) |
+ array.push(item[j]); |
} else { |
- array.push(arguments[i]); |
+ array.push(item); |
} |
} |
return array; |
- }; |
-} |
-Object.extend(Number.prototype, { |
- toColorPart: function() { |
- return this.toPaddedString(2, 16); |
- }, |
- |
- succ: function() { |
- return this + 1; |
- }, |
+ } |
- times: function(iterator, context) { |
- $R(0, this, true).each(iterator, context); |
- return this; |
- }, |
+ Object.extend(arrayProto, Enumerable); |
+ |
+ if (!arrayProto._reverse) |
+ arrayProto._reverse = arrayProto.reverse; |
+ |
+ Object.extend(arrayProto, { |
+ _each: _each, |
+ clear: clear, |
+ first: first, |
+ last: last, |
+ compact: compact, |
+ flatten: flatten, |
+ without: without, |
+ reverse: reverse, |
+ uniq: uniq, |
+ intersect: intersect, |
+ clone: clone, |
+ toArray: clone, |
+ size: size, |
+ inspect: inspect |
+ }); |
- toPaddedString: function(length, radix) { |
- var string = this.toString(radix || 10); |
- return '0'.times(length - string.length) + string; |
- }, |
+ var CONCAT_ARGUMENTS_BUGGY = (function() { |
+ return [].concat(arguments)[0][0] !== 1; |
+ })(1,2) |
- toJSON: function() { |
- return isFinite(this) ? this.toString() : 'null'; |
- } |
-}); |
+ if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; |
-$w('abs round ceil floor').each(function(method){ |
- Number.prototype[method] = Math[method].methodize(); |
-}); |
+ if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; |
+ if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; |
+})(); |
function $H(object) { |
return new Hash(object); |
}; |
var Hash = Class.create(Enumerable, (function() { |
+ function initialize(object) { |
+ this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); |
+ } |
- function toQueryPair(key, value) { |
- if (Object.isUndefined(value)) return key; |
- return key + '=' + encodeURIComponent(String.interpret(value)); |
+ |
+ function _each(iterator) { |
+ for (var key in this._object) { |
+ var value = this._object[key], pair = [key, value]; |
+ pair.key = key; |
+ pair.value = value; |
+ iterator(pair); |
+ } |
} |
- return { |
- initialize: function(object) { |
- this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); |
- }, |
+ function set(key, value) { |
+ return this._object[key] = value; |
+ } |
- _each: function(iterator) { |
- for (var key in this._object) { |
- var value = this._object[key], pair = [key, value]; |
- pair.key = key; |
- pair.value = value; |
- iterator(pair); |
- } |
- }, |
+ function get(key) { |
+ if (this._object[key] !== Object.prototype[key]) |
+ return this._object[key]; |
+ } |
- set: function(key, value) { |
- return this._object[key] = value; |
- }, |
+ function unset(key) { |
+ var value = this._object[key]; |
+ delete this._object[key]; |
+ return value; |
+ } |
- get: function(key) { |
- // simulating poorly supported hasOwnProperty |
- if (this._object[key] !== Object.prototype[key]) |
- return this._object[key]; |
- }, |
+ function toObject() { |
+ return Object.clone(this._object); |
+ } |
- unset: function(key) { |
- var value = this._object[key]; |
- delete this._object[key]; |
- return value; |
- }, |
- toObject: function() { |
- return Object.clone(this._object); |
- }, |
- keys: function() { |
- return this.pluck('key'); |
- }, |
+ function keys() { |
+ return this.pluck('key'); |
+ } |
- values: function() { |
- return this.pluck('value'); |
- }, |
+ function values() { |
+ return this.pluck('value'); |
+ } |
- index: function(value) { |
- var match = this.detect(function(pair) { |
- return pair.value === value; |
- }); |
- return match && match.key; |
- }, |
+ function index(value) { |
+ var match = this.detect(function(pair) { |
+ return pair.value === value; |
+ }); |
+ return match && match.key; |
+ } |
- merge: function(object) { |
- return this.clone().update(object); |
- }, |
+ function merge(object) { |
+ return this.clone().update(object); |
+ } |
- update: function(object) { |
- return new Hash(object).inject(this, function(result, pair) { |
- result.set(pair.key, pair.value); |
- return result; |
- }); |
- }, |
+ function update(object) { |
+ return new Hash(object).inject(this, function(result, pair) { |
+ result.set(pair.key, pair.value); |
+ return result; |
+ }); |
+ } |
- toQueryString: function() { |
- return this.inject([], function(results, pair) { |
- var key = encodeURIComponent(pair.key), values = pair.value; |
+ function toQueryPair(key, value) { |
+ if (Object.isUndefined(value)) return key; |
+ return key + '=' + encodeURIComponent(String.interpret(value)); |
+ } |
- if (values && typeof values == 'object') { |
- if (Object.isArray(values)) |
- return results.concat(values.map(toQueryPair.curry(key))); |
- } else results.push(toQueryPair(key, values)); |
- return results; |
- }).join('&'); |
- }, |
+ function toQueryString() { |
+ return this.inject([], function(results, pair) { |
+ var key = encodeURIComponent(pair.key), values = pair.value; |
- inspect: function() { |
- return '#<Hash:{' + this.map(function(pair) { |
- return pair.map(Object.inspect).join(': '); |
- }).join(', ') + '}>'; |
- }, |
+ if (values && typeof values == 'object') { |
+ if (Object.isArray(values)) { |
+ var queryValues = []; |
+ for (var i = 0, len = values.length, value; i < len; i++) { |
+ value = values[i]; |
+ queryValues.push(toQueryPair(key, value)); |
+ } |
+ return results.concat(queryValues); |
+ } |
+ } else results.push(toQueryPair(key, values)); |
+ return results; |
+ }).join('&'); |
+ } |
- toJSON: function() { |
- return Object.toJSON(this.toObject()); |
- }, |
+ function inspect() { |
+ return '#<Hash:{' + this.map(function(pair) { |
+ return pair.map(Object.inspect).join(': '); |
+ }).join(', ') + '}>'; |
+ } |
- clone: function() { |
- return new Hash(this); |
- } |
+ function clone() { |
+ return new Hash(this); |
} |
+ |
+ return { |
+ initialize: initialize, |
+ _each: _each, |
+ set: set, |
+ get: get, |
+ unset: unset, |
+ toObject: toObject, |
+ toTemplateReplacements: toObject, |
+ keys: keys, |
+ values: values, |
+ index: index, |
+ merge: merge, |
+ update: update, |
+ toQueryString: toQueryString, |
+ inspect: inspect, |
+ toJSON: toObject, |
+ clone: clone |
+ }; |
})()); |
-Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; |
Hash.from = $H; |
-var ObjectRange = Class.create(Enumerable, { |
- initialize: function(start, end, exclusive) { |
+Object.extend(Number.prototype, (function() { |
+ function toColorPart() { |
+ return this.toPaddedString(2, 16); |
+ } |
+ |
+ function succ() { |
+ return this + 1; |
+ } |
+ |
+ function times(iterator, context) { |
+ $R(0, this, true).each(iterator, context); |
+ return this; |
+ } |
+ |
+ function toPaddedString(length, radix) { |
+ var string = this.toString(radix || 10); |
+ return '0'.times(length - string.length) + string; |
+ } |
+ |
+ function abs() { |
+ return Math.abs(this); |
+ } |
+ |
+ function round() { |
+ return Math.round(this); |
+ } |
+ |
+ function ceil() { |
+ return Math.ceil(this); |
+ } |
+ |
+ function floor() { |
+ return Math.floor(this); |
+ } |
+ |
+ return { |
+ toColorPart: toColorPart, |
+ succ: succ, |
+ times: times, |
+ toPaddedString: toPaddedString, |
+ abs: abs, |
+ round: round, |
+ ceil: ceil, |
+ floor: floor |
+ }; |
+})()); |
+ |
+function $R(start, end, exclusive) { |
+ return new ObjectRange(start, end, exclusive); |
+} |
+ |
+var ObjectRange = Class.create(Enumerable, (function() { |
+ function initialize(start, end, exclusive) { |
this.start = start; |
this.end = end; |
this.exclusive = exclusive; |
- }, |
+ } |
- _each: function(iterator) { |
+ function _each(iterator) { |
var value = this.start; |
while (this.include(value)) { |
iterator(value); |
value = value.succ(); |
} |
- }, |
+ } |
- include: function(value) { |
+ function include(value) { |
if (value < this.start) |
return false; |
if (this.exclusive) |
return value < this.end; |
return value <= this.end; |
} |
-}); |
-var $R = function(start, end, exclusive) { |
- return new ObjectRange(start, end, exclusive); |
-}; |
+ return { |
+ initialize: initialize, |
+ _each: _each, |
+ include: include |
+ }; |
+})()); |
+ |
+ |
var Ajax = { |
getTransport: function() { |
@@ -1164,7 +1467,6 @@ Ajax.Responders.register({ |
onCreate: function() { Ajax.activeRequestCount++ }, |
onComplete: function() { Ajax.activeRequestCount-- } |
}); |
- |
Ajax.Base = Class.create({ |
initialize: function(options) { |
this.options = { |
@@ -1180,13 +1482,10 @@ Ajax.Base = Class.create({ |
this.options.method = this.options.method.toLowerCase(); |
- if (Object.isString(this.options.parameters)) |
- this.options.parameters = this.options.parameters.toQueryParams(); |
- else if (Object.isHash(this.options.parameters)) |
+ if (Object.isHash(this.options.parameters)) |
this.options.parameters = this.options.parameters.toObject(); |
} |
}); |
- |
Ajax.Request = Class.create(Ajax.Base, { |
_complete: false, |
@@ -1199,24 +1498,21 @@ Ajax.Request = Class.create(Ajax.Base, { |
request: function(url) { |
this.url = url; |
this.method = this.options.method; |
- var params = Object.clone(this.options.parameters); |
+ var params = Object.isString(this.options.parameters) ? |
+ this.options.parameters : |
+ Object.toQueryString(this.options.parameters); |
if (!['get', 'post'].include(this.method)) { |
- // simulate other verbs over post |
- params['_method'] = this.method; |
+ params += (params ? '&' : '') + "_method=" + this.method; |
this.method = 'post'; |
} |
- this.parameters = params; |
- |
- if (params = Object.toQueryString(params)) { |
- // when GET, append parameters to URL |
- if (this.method == 'get') |
- this.url += (this.url.include('?') ? '&' : '?') + params; |
- else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) |
- params += '&_='; |
+ if (params && this.method === 'get') { |
+ this.url += (this.url.include('?') ? '&' : '?') + params; |
} |
+ this.parameters = params.toQueryParams(); |
+ |
try { |
var response = new Ajax.Response(this); |
if (this.options.onCreate) this.options.onCreate(response); |
@@ -1269,7 +1565,6 @@ Ajax.Request = Class.create(Ajax.Base, { |
headers['Connection'] = 'close'; |
} |
- // user-defined headers |
if (typeof this.options.requestHeaders == 'object') { |
var extras = this.options.requestHeaders; |
@@ -1286,11 +1581,12 @@ Ajax.Request = Class.create(Ajax.Base, { |
success: function() { |
var status = this.getStatus(); |
- return !status || (status >= 200 && status < 300); |
+ return !status || (status >= 200 && status < 300) || status == 304; |
}, |
getStatus: function() { |
try { |
+ if (this.transport.status === 1223) return 204; |
return this.transport.status || 0; |
} catch (e) { return 0 } |
}, |
@@ -1323,7 +1619,6 @@ Ajax.Request = Class.create(Ajax.Base, { |
} |
if (state == 'Complete') { |
- // avoid memory leak in MSIE: clean up |
this.transport.onreadystatechange = Prototype.emptyFunction; |
} |
}, |
@@ -1340,7 +1635,7 @@ Ajax.Request = Class.create(Ajax.Base, { |
getHeader: function(name) { |
try { |
return this.transport.getResponseHeader(name) || null; |
- } catch (e) { return null } |
+ } catch (e) { return null; } |
}, |
evalResponse: function() { |
@@ -1360,20 +1655,27 @@ Ajax.Request = Class.create(Ajax.Base, { |
Ajax.Request.Events = |
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
Ajax.Response = Class.create({ |
initialize: function(request){ |
this.request = request; |
var transport = this.transport = request.transport, |
readyState = this.readyState = transport.readyState; |
- if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { |
+ if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { |
this.status = this.getStatus(); |
this.statusText = this.getStatusText(); |
this.responseText = String.interpret(transport.responseText); |
this.headerJSON = this._getHeaderJSON(); |
} |
- if(readyState == 4) { |
+ if (readyState == 4) { |
var xml = transport.responseXML; |
this.responseXML = Object.isUndefined(xml) ? null : xml; |
this.responseJSON = this._getResponseJSON(); |
@@ -1381,6 +1683,7 @@ Ajax.Response = Class.create({ |
}, |
status: 0, |
+ |
statusText: '', |
getStatus: Ajax.Request.prototype.getStatus, |
@@ -1510,6 +1813,8 @@ Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { |
this.updater = new Ajax.Updater(this.container, this.url, this.options); |
} |
}); |
+ |
+ |
function $(element) { |
if (arguments.length > 1) { |
for (var i = 0, elements = [], length = arguments.length; i < length; i++) |
@@ -1534,10 +1839,9 @@ if (Prototype.BrowserFeatures.XPath) { |
/*--------------------------------------------------------------------------*/ |
-if (!window.Node) var Node = { }; |
+if (!Node) var Node = { }; |
if (!Node.ELEMENT_NODE) { |
- // DOM level 2 ECMAScript Language Binding |
Object.extend(Node, { |
ELEMENT_NODE: 1, |
ATTRIBUTE_NODE: 2, |
@@ -1554,26 +1858,63 @@ if (!Node.ELEMENT_NODE) { |
}); |
} |
-(function() { |
- var element = this.Element; |
- this.Element = function(tagName, attributes) { |
+ |
+ |
+(function(global) { |
+ function shouldUseCache(tagName, attributes) { |
+ if (tagName === 'select') return false; |
+ if ('type' in attributes) return false; |
+ return true; |
+ } |
+ |
+ var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ |
+ try { |
+ var el = document.createElement('<input name="x">'); |
+ return el.tagName.toLowerCase() === 'input' && el.name === 'x'; |
+ } |
+ catch(err) { |
+ return false; |
+ } |
+ })(); |
+ |
+ var element = global.Element; |
+ |
+ global.Element = function(tagName, attributes) { |
attributes = attributes || { }; |
tagName = tagName.toLowerCase(); |
var cache = Element.cache; |
- if (Prototype.Browser.IE && attributes.name) { |
+ |
+ if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) { |
tagName = '<' + tagName + ' name="' + attributes.name + '">'; |
delete attributes.name; |
return Element.writeAttribute(document.createElement(tagName), attributes); |
} |
+ |
if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); |
- return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); |
+ |
+ var node = shouldUseCache(tagName, attributes) ? |
+ cache[tagName].cloneNode(false) : document.createElement(tagName); |
+ |
+ return Element.writeAttribute(node, attributes); |
}; |
- Object.extend(this.Element, element || { }); |
- if (element) this.Element.prototype = element.prototype; |
-}).call(window); |
+ Object.extend(global.Element, element || { }); |
+ if (element) global.Element.prototype = element.prototype; |
+ |
+})(this); |
+ |
+Element.idCounter = 1; |
Element.cache = { }; |
+Element._purgeElement = function(element) { |
+ var uid = element._prototypeUID; |
+ if (uid) { |
+ Element.stopObserving(element); |
+ element._prototypeUID = void 0; |
+ delete Element.Storage[uid]; |
+ } |
+} |
+ |
Element.Methods = { |
visible: function(element) { |
return $(element).style.display != 'none'; |
@@ -1603,15 +1944,116 @@ Element.Methods = { |
return element; |
}, |
- update: function(element, content) { |
- element = $(element); |
- if (content && content.toElement) content = content.toElement(); |
- if (Object.isElement(content)) return element.update().insert(content); |
- content = Object.toHTML(content); |
- element.innerHTML = content.stripScripts(); |
- content.evalScripts.bind(content).defer(); |
- return element; |
- }, |
+ update: (function(){ |
+ |
+ var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ |
+ var el = document.createElement("select"), |
+ isBuggy = true; |
+ el.innerHTML = "<option value=\"test\">test</option>"; |
+ if (el.options && el.options[0]) { |
+ isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; |
+ } |
+ el = null; |
+ return isBuggy; |
+ })(); |
+ |
+ var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ |
+ try { |
+ var el = document.createElement("table"); |
+ if (el && el.tBodies) { |
+ el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>"; |
+ var isBuggy = typeof el.tBodies[0] == "undefined"; |
+ el = null; |
+ return isBuggy; |
+ } |
+ } catch (e) { |
+ return true; |
+ } |
+ })(); |
+ |
+ var LINK_ELEMENT_INNERHTML_BUGGY = (function() { |
+ try { |
+ var el = document.createElement('div'); |
+ el.innerHTML = "<link>"; |
+ var isBuggy = (el.childNodes.length === 0); |
+ el = null; |
+ return isBuggy; |
+ } catch(e) { |
+ return true; |
+ } |
+ })(); |
+ |
+ var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY || |
+ TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY; |
+ |
+ var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { |
+ var s = document.createElement("script"), |
+ isBuggy = false; |
+ try { |
+ s.appendChild(document.createTextNode("")); |
+ isBuggy = !s.firstChild || |
+ s.firstChild && s.firstChild.nodeType !== 3; |
+ } catch (e) { |
+ isBuggy = true; |
+ } |
+ s = null; |
+ return isBuggy; |
+ })(); |
+ |
+ |
+ function update(element, content) { |
+ element = $(element); |
+ var purgeElement = Element._purgeElement; |
+ |
+ var descendants = element.getElementsByTagName('*'), |
+ i = descendants.length; |
+ while (i--) purgeElement(descendants[i]); |
+ |
+ if (content && content.toElement) |
+ content = content.toElement(); |
+ |
+ if (Object.isElement(content)) |
+ return element.update().insert(content); |
+ |
+ content = Object.toHTML(content); |
+ |
+ var tagName = element.tagName.toUpperCase(); |
+ |
+ if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { |
+ element.text = content; |
+ return element; |
+ } |
+ |
+ if (ANY_INNERHTML_BUGGY) { |
+ if (tagName in Element._insertionTranslations.tags) { |
+ while (element.firstChild) { |
+ element.removeChild(element.firstChild); |
+ } |
+ Element._getContentFromAnonymousElement(tagName, content.stripScripts()) |
+ .each(function(node) { |
+ element.appendChild(node) |
+ }); |
+ } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) { |
+ while (element.firstChild) { |
+ element.removeChild(element.firstChild); |
+ } |
+ var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true); |
+ nodes.each(function(node) { element.appendChild(node) }); |
+ } |
+ else { |
+ element.innerHTML = content.stripScripts(); |
+ } |
+ } |
+ else { |
+ element.innerHTML = content.stripScripts(); |
+ } |
+ |
+ content.evalScripts.bind(content).defer(); |
+ return element; |
+ } |
+ |
+ return update; |
+ })(), |
replace: function(element, content) { |
element = $(element); |
@@ -1679,28 +2121,35 @@ Element.Methods = { |
element = $(element); |
var result = '<' + element.tagName.toLowerCase(); |
$H({'id': 'id', 'className': 'class'}).each(function(pair) { |
- var property = pair.first(), attribute = pair.last(); |
- var value = (element[property] || '').toString(); |
+ var property = pair.first(), |
+ attribute = pair.last(), |
+ value = (element[property] || '').toString(); |
if (value) result += ' ' + attribute + '=' + value.inspect(true); |
}); |
return result + '>'; |
}, |
- recursivelyCollect: function(element, property) { |
+ recursivelyCollect: function(element, property, maximumLength) { |
element = $(element); |
+ maximumLength = maximumLength || -1; |
var elements = []; |
- while (element = element[property]) |
+ |
+ while (element = element[property]) { |
if (element.nodeType == 1) |
elements.push(Element.extend(element)); |
+ if (elements.length == maximumLength) |
+ break; |
+ } |
+ |
return elements; |
}, |
ancestors: function(element) { |
- return $(element).recursivelyCollect('parentNode'); |
+ return Element.recursivelyCollect(element, 'parentNode'); |
}, |
descendants: function(element) { |
- return $(element).select("*"); |
+ return Element.select(element, "*"); |
}, |
firstDescendant: function(element) { |
@@ -1710,78 +2159,96 @@ Element.Methods = { |
}, |
immediateDescendants: function(element) { |
- if (!(element = $(element).firstChild)) return []; |
- while (element && element.nodeType != 1) element = element.nextSibling; |
- if (element) return [element].concat($(element).nextSiblings()); |
- return []; |
+ var results = [], child = $(element).firstChild; |
+ while (child) { |
+ if (child.nodeType === 1) { |
+ results.push(Element.extend(child)); |
+ } |
+ child = child.nextSibling; |
+ } |
+ return results; |
}, |
- previousSiblings: function(element) { |
- return $(element).recursivelyCollect('previousSibling'); |
+ previousSiblings: function(element, maximumLength) { |
+ return Element.recursivelyCollect(element, 'previousSibling'); |
}, |
nextSiblings: function(element) { |
- return $(element).recursivelyCollect('nextSibling'); |
+ return Element.recursivelyCollect(element, 'nextSibling'); |
}, |
siblings: function(element) { |
element = $(element); |
- return element.previousSiblings().reverse().concat(element.nextSiblings()); |
+ return Element.previousSiblings(element).reverse() |
+ .concat(Element.nextSiblings(element)); |
}, |
match: function(element, selector) { |
+ element = $(element); |
if (Object.isString(selector)) |
- selector = new Selector(selector); |
- return selector.match($(element)); |
+ return Prototype.Selector.match(element, selector); |
+ return selector.match(element); |
}, |
up: function(element, expression, index) { |
element = $(element); |
if (arguments.length == 1) return $(element.parentNode); |
- var ancestors = element.ancestors(); |
+ var ancestors = Element.ancestors(element); |
return Object.isNumber(expression) ? ancestors[expression] : |
- Selector.findElement(ancestors, expression, index); |
+ Prototype.Selector.find(ancestors, expression, index); |
}, |
down: function(element, expression, index) { |
element = $(element); |
- if (arguments.length == 1) return element.firstDescendant(); |
- return Object.isNumber(expression) ? element.descendants()[expression] : |
+ if (arguments.length == 1) return Element.firstDescendant(element); |
+ return Object.isNumber(expression) ? Element.descendants(element)[expression] : |
Element.select(element, expression)[index || 0]; |
}, |
previous: function(element, expression, index) { |
element = $(element); |
- if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); |
- var previousSiblings = element.previousSiblings(); |
- return Object.isNumber(expression) ? previousSiblings[expression] : |
- Selector.findElement(previousSiblings, expression, index); |
+ if (Object.isNumber(expression)) index = expression, expression = false; |
+ if (!Object.isNumber(index)) index = 0; |
+ |
+ if (expression) { |
+ return Prototype.Selector.find(element.previousSiblings(), expression, index); |
+ } else { |
+ return element.recursivelyCollect("previousSibling", index + 1)[index]; |
+ } |
}, |
next: function(element, expression, index) { |
element = $(element); |
- if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); |
- var nextSiblings = element.nextSiblings(); |
- return Object.isNumber(expression) ? nextSiblings[expression] : |
- Selector.findElement(nextSiblings, expression, index); |
+ if (Object.isNumber(expression)) index = expression, expression = false; |
+ if (!Object.isNumber(index)) index = 0; |
+ |
+ if (expression) { |
+ return Prototype.Selector.find(element.nextSiblings(), expression, index); |
+ } else { |
+ var maximumLength = Object.isNumber(index) ? index + 1 : 1; |
+ return element.recursivelyCollect("nextSibling", index + 1)[index]; |
+ } |
}, |
- select: function() { |
- var args = $A(arguments), element = $(args.shift()); |
- return Selector.findChildElements(element, args); |
+ |
+ select: function(element) { |
+ element = $(element); |
+ var expressions = Array.prototype.slice.call(arguments, 1).join(', '); |
+ return Prototype.Selector.select(expressions, element); |
}, |
- adjacent: function() { |
- var args = $A(arguments), element = $(args.shift()); |
- return Selector.findChildElements(element.parentNode, args).without(element); |
+ adjacent: function(element) { |
+ element = $(element); |
+ var expressions = Array.prototype.slice.call(arguments, 1).join(', '); |
+ return Prototype.Selector.select(expressions, element.parentNode).without(element); |
}, |
identify: function(element) { |
element = $(element); |
- var id = element.readAttribute('id'), self = arguments.callee; |
+ var id = Element.readAttribute(element, 'id'); |
if (id) return id; |
- do { id = 'anonymous_element_' + self.counter++ } while ($(id)); |
- element.writeAttribute('id', id); |
+ do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); |
+ Element.writeAttribute(element, 'id', id); |
return id; |
}, |
@@ -1820,11 +2287,11 @@ Element.Methods = { |
}, |
getHeight: function(element) { |
- return $(element).getDimensions().height; |
+ return Element.getDimensions(element).height; |
}, |
getWidth: function(element) { |
- return $(element).getDimensions().width; |
+ return Element.getDimensions(element).width; |
}, |
classNames: function(element) { |
@@ -1840,7 +2307,7 @@ Element.Methods = { |
addClassName: function(element, className) { |
if (!(element = $(element))) return; |
- if (!element.hasClassName(className)) |
+ if (!Element.hasClassName(element, className)) |
element.className += (element.className ? ' ' : '') + className; |
return element; |
}, |
@@ -1854,11 +2321,10 @@ Element.Methods = { |
toggleClassName: function(element, className) { |
if (!(element = $(element))) return; |
- return element[element.hasClassName(className) ? |
- 'removeClassName' : 'addClassName'](className); |
+ return Element[Element.hasClassName(element, className) ? |
+ 'removeClassName' : 'addClassName'](element, className); |
}, |
- // removes whitespace-only text node children |
cleanWhitespace: function(element) { |
element = $(element); |
var node = element.firstChild; |
@@ -1892,7 +2358,7 @@ Element.Methods = { |
scrollTo: function(element) { |
element = $(element); |
- var pos = element.cumulativeOffset(); |
+ var pos = Element.cumulativeOffset(element); |
window.scrollTo(pos[0], pos[1]); |
return element; |
}, |
@@ -1938,37 +2404,12 @@ Element.Methods = { |
return element; |
}, |
- getDimensions: function(element) { |
- element = $(element); |
- var display = element.getStyle('display'); |
- if (display != 'none' && display != null) // Safari bug |
- return {width: element.offsetWidth, height: element.offsetHeight}; |
- |
- // All *Width and *Height properties give 0 on elements with display none, |
- // so enable the element temporarily |
- var els = element.style; |
- var originalVisibility = els.visibility; |
- var originalPosition = els.position; |
- var originalDisplay = els.display; |
- els.visibility = 'hidden'; |
- els.position = 'absolute'; |
- els.display = 'block'; |
- var originalWidth = element.clientWidth; |
- var originalHeight = element.clientHeight; |
- els.display = originalDisplay; |
- els.position = originalPosition; |
- els.visibility = originalVisibility; |
- return {width: originalWidth, height: originalHeight}; |
- }, |
- |
makePositioned: function(element) { |
element = $(element); |
var pos = Element.getStyle(element, 'position'); |
if (pos == 'static' || !pos) { |
element._madePositioned = true; |
element.style.position = 'relative'; |
- // Opera returns the offset relative to the positioning context, when an |
- // element is position relative but top and left have not been defined |
if (Prototype.Browser.Opera) { |
element.style.top = 0; |
element.style.left = 0; |
@@ -2007,117 +2448,6 @@ Element.Methods = { |
return element; |
}, |
- cumulativeOffset: function(element) { |
- var valueT = 0, valueL = 0; |
- do { |
- valueT += element.offsetTop || 0; |
- valueL += element.offsetLeft || 0; |
- element = element.offsetParent; |
- } while (element); |
- return Element._returnOffset(valueL, valueT); |
- }, |
- |
- positionedOffset: function(element) { |
- var valueT = 0, valueL = 0; |
- do { |
- valueT += element.offsetTop || 0; |
- valueL += element.offsetLeft || 0; |
- element = element.offsetParent; |
- if (element) { |
- if (element.tagName.toUpperCase() == 'BODY') break; |
- var p = Element.getStyle(element, 'position'); |
- if (p !== 'static') break; |
- } |
- } while (element); |
- return Element._returnOffset(valueL, valueT); |
- }, |
- |
- absolutize: function(element) { |
- element = $(element); |
- if (element.getStyle('position') == 'absolute') return element; |
- // Position.prepare(); // To be done manually by Scripty when it needs it. |
- |
- var offsets = element.positionedOffset(); |
- var top = offsets[1]; |
- var left = offsets[0]; |
- var width = element.clientWidth; |
- var height = element.clientHeight; |
- |
- element._originalLeft = left - parseFloat(element.style.left || 0); |
- element._originalTop = top - parseFloat(element.style.top || 0); |
- element._originalWidth = element.style.width; |
- element._originalHeight = element.style.height; |
- |
- element.style.position = 'absolute'; |
- element.style.top = top + 'px'; |
- element.style.left = left + 'px'; |
- element.style.width = width + 'px'; |
- element.style.height = height + 'px'; |
- return element; |
- }, |
- |
- relativize: function(element) { |
- element = $(element); |
- if (element.getStyle('position') == 'relative') return element; |
- // Position.prepare(); // To be done manually by Scripty when it needs it. |
- |
- element.style.position = 'relative'; |
- var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); |
- var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); |
- |
- element.style.top = top + 'px'; |
- element.style.left = left + 'px'; |
- element.style.height = element._originalHeight; |
- element.style.width = element._originalWidth; |
- return element; |
- }, |
- |
- cumulativeScrollOffset: function(element) { |
- var valueT = 0, valueL = 0; |
- do { |
- valueT += element.scrollTop || 0; |
- valueL += element.scrollLeft || 0; |
- element = element.parentNode; |
- } while (element); |
- return Element._returnOffset(valueL, valueT); |
- }, |
- |
- getOffsetParent: function(element) { |
- if (element.offsetParent) return $(element.offsetParent); |
- if (element == document.body) return $(element); |
- |
- while ((element = element.parentNode) && element != document.body) |
- if (Element.getStyle(element, 'position') != 'static') |
- return $(element); |
- |
- return $(document.body); |
- }, |
- |
- viewportOffset: function(forElement) { |
- var valueT = 0, valueL = 0; |
- |
- var element = forElement; |
- do { |
- valueT += element.offsetTop || 0; |
- valueL += element.offsetLeft || 0; |
- |
- // Safari fix |
- if (element.offsetParent == document.body && |
- Element.getStyle(element, 'position') == 'absolute') break; |
- |
- } while (element = element.offsetParent); |
- |
- element = forElement; |
- do { |
- if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { |
- valueT -= element.scrollTop || 0; |
- valueL -= element.scrollLeft || 0; |
- } |
- } while (element = element.parentNode); |
- |
- return Element._returnOffset(valueL, valueT); |
- }, |
- |
clonePosition: function(element, source) { |
var options = Object.extend({ |
setLeft: true, |
@@ -2128,28 +2458,21 @@ Element.Methods = { |
offsetLeft: 0 |
}, arguments[2] || { }); |
- // find page position of source |
source = $(source); |
- var p = source.viewportOffset(); |
+ var p = Element.viewportOffset(source), delta = [0, 0], parent = null; |
- // find coordinate system to use |
element = $(element); |
- var delta = [0, 0]; |
- var parent = null; |
- // delta [0,0] will do fine with position: fixed elements, |
- // position:absolute needs offsetParent deltas |
+ |
if (Element.getStyle(element, 'position') == 'absolute') { |
- parent = element.getOffsetParent(); |
- delta = parent.viewportOffset(); |
+ parent = Element.getOffsetParent(element); |
+ delta = Element.viewportOffset(parent); |
} |
- // correct by body offsets (fixes Safari) |
if (parent == document.body) { |
delta[0] -= document.body.offsetLeft; |
delta[1] -= document.body.offsetTop; |
} |
- // set position |
if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; |
if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; |
if (options.setWidth) element.style.width = source.offsetWidth + 'px'; |
@@ -2158,10 +2481,9 @@ Element.Methods = { |
} |
}; |
-Element.Methods.identify.counter = 1; |
- |
Object.extend(Element.Methods, { |
getElementsBySelector: Element.Methods.select, |
+ |
childElements: Element.Methods.immediateDescendants |
}); |
@@ -2179,14 +2501,9 @@ if (Prototype.Browser.Opera) { |
Element.Methods.getStyle = Element.Methods.getStyle.wrap( |
function(proceed, element, style) { |
switch (style) { |
- case 'left': case 'top': case 'right': case 'bottom': |
- if (proceed(element, 'position') === 'static') return null; |
case 'height': case 'width': |
- // returns '0px' for hidden elements; we want it to return null |
if (!Element.visible(element)) return null; |
- // returns the border-box dimensions rather than the content-box |
- // dimensions, so we subtract padding and borders from the value |
var dim = parseInt(proceed(element, style), 10); |
if (dim !== element['offset' + style.capitalize()]) |
@@ -2219,52 +2536,6 @@ if (Prototype.Browser.Opera) { |
} |
else if (Prototype.Browser.IE) { |
- // IE doesn't report offsets correctly for static elements, so we change them |
- // to "relative" to get the values, then change them back. |
- Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( |
- function(proceed, element) { |
- element = $(element); |
- // IE throws an error if element is not in document |
- try { element.offsetParent } |
- catch(e) { return $(document.body) } |
- var position = element.getStyle('position'); |
- if (position !== 'static') return proceed(element); |
- element.setStyle({ position: 'relative' }); |
- var value = proceed(element); |
- element.setStyle({ position: position }); |
- return value; |
- } |
- ); |
- |
- $w('positionedOffset viewportOffset').each(function(method) { |
- Element.Methods[method] = Element.Methods[method].wrap( |
- function(proceed, element) { |
- element = $(element); |
- try { element.offsetParent } |
- catch(e) { return Element._returnOffset(0,0) } |
- var position = element.getStyle('position'); |
- if (position !== 'static') return proceed(element); |
- // Trigger hasLayout on the offset parent so that IE6 reports |
- // accurate offsetTop and offsetLeft values for position: fixed. |
- var offsetParent = element.getOffsetParent(); |
- if (offsetParent && offsetParent.getStyle('position') === 'fixed') |
- offsetParent.setStyle({ zoom: 1 }); |
- element.setStyle({ position: 'relative' }); |
- var value = proceed(element); |
- element.setStyle({ position: position }); |
- return value; |
- } |
- ); |
- }); |
- |
- Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( |
- function(proceed, element) { |
- try { element.offsetParent } |
- catch(e) { return Element._returnOffset(0,0) } |
- return proceed(element); |
- } |
- ); |
- |
Element.Methods.getStyle = function(element, style) { |
element = $(element); |
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); |
@@ -2306,36 +2577,90 @@ else if (Prototype.Browser.IE) { |
return element; |
}; |
- Element._attributeTranslations = { |
- read: { |
- names: { |
- 'class': 'className', |
- 'for': 'htmlFor' |
- }, |
- values: { |
- _getAttr: function(element, attribute) { |
- return element.getAttribute(attribute, 2); |
- }, |
- _getAttrNode: function(element, attribute) { |
- var node = element.getAttributeNode(attribute); |
- return node ? node.value : ""; |
- }, |
- _getEv: function(element, attribute) { |
- attribute = element.getAttribute(attribute); |
- return attribute ? attribute.toString().slice(23, -2) : null; |
- }, |
- _flag: function(element, attribute) { |
- return $(element).hasAttribute(attribute) ? attribute : null; |
- }, |
- style: function(element) { |
- return element.style.cssText.toLowerCase(); |
+ Element._attributeTranslations = (function(){ |
+ |
+ var classProp = 'className', |
+ forProp = 'for', |
+ el = document.createElement('div'); |
+ |
+ el.setAttribute(classProp, 'x'); |
+ |
+ if (el.className !== 'x') { |
+ el.setAttribute('class', 'x'); |
+ if (el.className === 'x') { |
+ classProp = 'class'; |
+ } |
+ } |
+ el = null; |
+ |
+ el = document.createElement('label'); |
+ el.setAttribute(forProp, 'x'); |
+ if (el.htmlFor !== 'x') { |
+ el.setAttribute('htmlFor', 'x'); |
+ if (el.htmlFor === 'x') { |
+ forProp = 'htmlFor'; |
+ } |
+ } |
+ el = null; |
+ |
+ return { |
+ read: { |
+ names: { |
+ 'class': classProp, |
+ 'className': classProp, |
+ 'for': forProp, |
+ 'htmlFor': forProp |
}, |
- title: function(element) { |
- return element.title; |
+ values: { |
+ _getAttr: function(element, attribute) { |
+ return element.getAttribute(attribute); |
+ }, |
+ _getAttr2: function(element, attribute) { |
+ return element.getAttribute(attribute, 2); |
+ }, |
+ _getAttrNode: function(element, attribute) { |
+ var node = element.getAttributeNode(attribute); |
+ return node ? node.value : ""; |
+ }, |
+ _getEv: (function(){ |
+ |
+ var el = document.createElement('div'), f; |
+ el.onclick = Prototype.emptyFunction; |
+ var value = el.getAttribute('onclick'); |
+ |
+ if (String(value).indexOf('{') > -1) { |
+ f = function(element, attribute) { |
+ attribute = element.getAttribute(attribute); |
+ if (!attribute) return null; |
+ attribute = attribute.toString(); |
+ attribute = attribute.split('{')[1]; |
+ attribute = attribute.split('}')[0]; |
+ return attribute.strip(); |
+ }; |
+ } |
+ else if (value === '') { |
+ f = function(element, attribute) { |
+ attribute = element.getAttribute(attribute); |
+ if (!attribute) return null; |
+ return attribute.strip(); |
+ }; |
+ } |
+ el = null; |
+ return f; |
+ })(), |
+ _flag: function(element, attribute) { |
+ return $(element).hasAttribute(attribute) ? attribute : null; |
+ }, |
+ style: function(element) { |
+ return element.style.cssText.toLowerCase(); |
+ }, |
+ title: function(element) { |
+ return element.title; |
+ } |
} |
} |
} |
- }; |
+ })(); |
Element._attributeTranslations.write = { |
names: Object.extend({ |
@@ -2363,8 +2688,8 @@ else if (Prototype.Browser.IE) { |
(function(v) { |
Object.extend(v, { |
- href: v._getAttr, |
- src: v._getAttr, |
+ href: v._getAttr2, |
+ src: v._getAttr2, |
type: v._getAttr, |
action: v._getAttrNode, |
disabled: v._flag, |
@@ -2391,6 +2716,26 @@ else if (Prototype.Browser.IE) { |
onchange: v._getEv |
}); |
})(Element._attributeTranslations.read.values); |
+ |
+ if (Prototype.BrowserFeatures.ElementExtensions) { |
+ (function() { |
+ function _descendants(element) { |
+ var nodes = element.getElementsByTagName('*'), results = []; |
+ for (var i = 0, node; node = nodes[i]; i++) |
+ if (node.tagName !== "!") // Filter out comment nodes. |
+ results.push(node); |
+ return results; |
+ } |
+ |
+ Element.Methods.down = function(element, expression, index) { |
+ element = $(element); |
+ if (arguments.length == 1) return element.firstDescendant(); |
+ return Object.isNumber(expression) ? _descendants(element)[expression] : |
+ Element.select(element, expression)[index || 0]; |
+ } |
+ })(); |
+ } |
+ |
} |
else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { |
@@ -2409,7 +2754,7 @@ else if (Prototype.Browser.WebKit) { |
(value < 0.00001) ? 0 : value; |
if (value == 1) |
- if(element.tagName.toUpperCase() == 'IMG' && element.width) { |
+ if (element.tagName.toUpperCase() == 'IMG' && element.width) { |
element.width++; element.width--; |
} else try { |
var n = document.createTextNode(' '); |
@@ -2419,49 +2764,9 @@ else if (Prototype.Browser.WebKit) { |
return element; |
}; |
- |
- // Safari returns margins on body which is incorrect if the child is absolutely |
- // positioned. For performance reasons, redefine Element#cumulativeOffset for |
- // KHTML/WebKit only. |
- Element.Methods.cumulativeOffset = function(element) { |
- var valueT = 0, valueL = 0; |
- do { |
- valueT += element.offsetTop || 0; |
- valueL += element.offsetLeft || 0; |
- if (element.offsetParent == document.body) |
- if (Element.getStyle(element, 'position') == 'absolute') break; |
- |
- element = element.offsetParent; |
- } while (element); |
- |
- return Element._returnOffset(valueL, valueT); |
- }; |
-} |
- |
-if (Prototype.Browser.IE || Prototype.Browser.Opera) { |
- // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements |
- Element.Methods.update = function(element, content) { |
- element = $(element); |
- |
- if (content && content.toElement) content = content.toElement(); |
- if (Object.isElement(content)) return element.update().insert(content); |
- |
- content = Object.toHTML(content); |
- var tagName = element.tagName.toUpperCase(); |
- |
- if (tagName in Element._insertionTranslations.tags) { |
- $A(element.childNodes).each(function(node) { element.removeChild(node) }); |
- Element._getContentFromAnonymousElement(tagName, content.stripScripts()) |
- .each(function(node) { element.appendChild(node) }); |
- } |
- else element.innerHTML = content.stripScripts(); |
- |
- content.evalScripts.bind(content).defer(); |
- return element; |
- }; |
} |
-if ('outerHTML' in document.createElement('div')) { |
+if ('outerHTML' in document.documentElement) { |
Element.Methods.replace = function(element, content) { |
element = $(element); |
@@ -2475,8 +2780,8 @@ if ('outerHTML' in document.createElement('div')) { |
var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); |
if (Element._insertionTranslations.tags[tagName]) { |
- var nextSibling = element.next(); |
- var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); |
+ var nextSibling = element.next(), |
+ fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); |
parent.removeChild(element); |
if (nextSibling) |
fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); |
@@ -2497,12 +2802,27 @@ Element._returnOffset = function(l, t) { |
return result; |
}; |
-Element._getContentFromAnonymousElement = function(tagName, html) { |
- var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; |
- if (t) { |
- div.innerHTML = t[0] + html + t[1]; |
- t[2].times(function() { div = div.firstChild }); |
- } else div.innerHTML = html; |
+Element._getContentFromAnonymousElement = function(tagName, html, force) { |
+ var div = new Element('div'), |
+ t = Element._insertionTranslations.tags[tagName]; |
+ |
+ var workaround = false; |
+ if (t) workaround = true; |
+ else if (force) { |
+ workaround = true; |
+ t = ['', '', 0]; |
+ } |
+ |
+ if (workaround) { |
+ div.innerHTML = ' ' + t[0] + html + t[1]; |
+ div.removeChild(div.firstChild); |
+ for (var i = t[2]; i--; ) { |
+ div = div.firstChild; |
+ } |
+ } |
+ else { |
+ div.innerHTML = html; |
+ } |
return $A(div.childNodes); |
}; |
@@ -2529,12 +2849,13 @@ Element._insertionTranslations = { |
}; |
(function() { |
- Object.extend(this.tags, { |
- THEAD: this.tags.TBODY, |
- TFOOT: this.tags.TBODY, |
- TH: this.tags.TD |
+ var tags = Element._insertionTranslations.tags; |
+ Object.extend(tags, { |
+ THEAD: tags.TBODY, |
+ TFOOT: tags.TBODY, |
+ TH: tags.TD |
}); |
-}).call(Element._insertionTranslations); |
+})(); |
Element.Methods.Simulated = { |
hasAttribute: function(element, attribute) { |
@@ -2548,41 +2869,81 @@ Element.Methods.ByTag = { }; |
Object.extend(Element, Element.Methods); |
-if (!Prototype.BrowserFeatures.ElementExtensions && |
- document.createElement('div')['__proto__']) { |
- window.HTMLElement = { }; |
- window.HTMLElement.prototype = document.createElement('div')['__proto__']; |
- Prototype.BrowserFeatures.ElementExtensions = true; |
-} |
+(function(div) { |
+ |
+ if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { |
+ window.HTMLElement = { }; |
+ window.HTMLElement.prototype = div['__proto__']; |
+ Prototype.BrowserFeatures.ElementExtensions = true; |
+ } |
+ |
+ div = null; |
+ |
+})(document.createElement('div')); |
Element.extend = (function() { |
- if (Prototype.BrowserFeatures.SpecificElementExtensions) |
+ |
+ function checkDeficiency(tagName) { |
+ if (typeof window.Element != 'undefined') { |
+ var proto = window.Element.prototype; |
+ if (proto) { |
+ var id = '_' + (Math.random()+'').slice(2), |
+ el = document.createElement(tagName); |
+ proto[id] = 'x'; |
+ var isBuggy = (el[id] !== 'x'); |
+ delete proto[id]; |
+ el = null; |
+ return isBuggy; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ function extendElementWith(element, methods) { |
+ for (var property in methods) { |
+ var value = methods[property]; |
+ if (Object.isFunction(value) && !(property in element)) |
+ element[property] = value.methodize(); |
+ } |
+ } |
+ |
+ var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); |
+ |
+ if (Prototype.BrowserFeatures.SpecificElementExtensions) { |
+ if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { |
+ return function(element) { |
+ if (element && typeof element._extendedByPrototype == 'undefined') { |
+ var t = element.tagName; |
+ if (t && (/^(?:object|applet|embed)$/i.test(t))) { |
+ extendElementWith(element, Element.Methods); |
+ extendElementWith(element, Element.Methods.Simulated); |
+ extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); |
+ } |
+ } |
+ return element; |
+ } |
+ } |
return Prototype.K; |
+ } |
var Methods = { }, ByTag = Element.Methods.ByTag; |
var extend = Object.extend(function(element) { |
- if (!element || element._extendedByPrototype || |
+ if (!element || typeof element._extendedByPrototype != 'undefined' || |
element.nodeType != 1 || element == window) return element; |
var methods = Object.clone(Methods), |
- tagName = element.tagName.toUpperCase(), property, value; |
+ tagName = element.tagName.toUpperCase(); |
- // extend methods for specific tags |
if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); |
- for (property in methods) { |
- value = methods[property]; |
- if (Object.isFunction(value) && !(property in element)) |
- element[property] = value.methodize(); |
- } |
+ extendElementWith(element, methods); |
element._extendedByPrototype = Prototype.emptyFunction; |
return element; |
}, { |
refresh: function() { |
- // extend methods for all tags (Safari doesn't need this) |
if (!Prototype.BrowserFeatures.ElementExtensions) { |
Object.extend(Methods, Element.Methods); |
Object.extend(Methods, Element.Methods.Simulated); |
@@ -2594,10 +2955,14 @@ Element.extend = (function() { |
return extend; |
})(); |
-Element.hasAttribute = function(element, attribute) { |
- if (element.hasAttribute) return element.hasAttribute(attribute); |
- return Element.Methods.Simulated.hasAttribute(element, attribute); |
-}; |
+if (document.documentElement.hasAttribute) { |
+ Element.hasAttribute = function(element, attribute) { |
+ return element.hasAttribute(attribute); |
+ }; |
+} |
+else { |
+ Element.hasAttribute = Element.Methods.Simulated.hasAttribute; |
+} |
Element.addMethods = function(methods) { |
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; |
@@ -2609,7 +2974,8 @@ Element.addMethods = function(methods) { |
"FORM": Object.clone(Form.Methods), |
"INPUT": Object.clone(Form.Element.Methods), |
"SELECT": Object.clone(Form.Element.Methods), |
- "TEXTAREA": Object.clone(Form.Element.Methods) |
+ "TEXTAREA": Object.clone(Form.Element.Methods), |
+ "BUTTON": Object.clone(Form.Element.Methods) |
}); |
} |
@@ -2661,14 +3027,19 @@ Element.addMethods = function(methods) { |
klass = 'HTML' + tagName.capitalize() + 'Element'; |
if (window[klass]) return window[klass]; |
- window[klass] = { }; |
- window[klass].prototype = document.createElement(tagName)['__proto__']; |
- return window[klass]; |
+ var element = document.createElement(tagName), |
+ proto = element['__proto__'] || element.constructor.prototype; |
+ |
+ element = null; |
+ return proto; |
} |
+ var elementPrototype = window.HTMLElement ? HTMLElement.prototype : |
+ Element.prototype; |
+ |
if (F.ElementExtensions) { |
- copy(Element.Methods, HTMLElement.prototype); |
- copy(Element.Methods.Simulated, HTMLElement.prototype, true); |
+ copy(Element.Methods, elementPrototype); |
+ copy(Element.Methods.Simulated, elementPrototype, true); |
} |
if (F.SpecificElementExtensions) { |
@@ -2686,791 +3057,1947 @@ Element.addMethods = function(methods) { |
Element.cache = { }; |
}; |
+ |
document.viewport = { |
+ |
getDimensions: function() { |
- var dimensions = { }, B = Prototype.Browser; |
- $w('width height').each(function(d) { |
- var D = d.capitalize(); |
- if (B.WebKit && !document.evaluate) { |
- // Safari <3.0 needs self.innerWidth/Height |
- dimensions[d] = self['inner' + D]; |
- } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { |
- // Opera <9.5 needs document.body.clientWidth/Height |
- dimensions[d] = document.body['client' + D] |
- } else { |
- dimensions[d] = document.documentElement['client' + D]; |
- } |
- }); |
- return dimensions; |
- }, |
- |
- getWidth: function() { |
- return this.getDimensions().width; |
- }, |
- |
- getHeight: function() { |
- return this.getDimensions().height; |
+ return { width: this.getWidth(), height: this.getHeight() }; |
}, |
getScrollOffsets: function() { |
return Element._returnOffset( |
window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, |
- window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); |
+ window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); |
} |
}; |
-/* Portions of the Selector class are derived from Jack Slocum's DomQuery, |
- * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style |
- * license. Please see http://www.yui-ext.com/ for more information. */ |
- |
-var Selector = Class.create({ |
- initialize: function(expression) { |
- this.expression = expression.strip(); |
- |
- if (this.shouldUseSelectorsAPI()) { |
- this.mode = 'selectorsAPI'; |
- } else if (this.shouldUseXPath()) { |
- this.mode = 'xpath'; |
- this.compileXPathMatcher(); |
- } else { |
- this.mode = "normal"; |
- this.compileMatcher(); |
- } |
- }, |
+(function(viewport) { |
+ var B = Prototype.Browser, doc = document, element, property = {}; |
- shouldUseXPath: function() { |
- if (!Prototype.BrowserFeatures.XPath) return false; |
+ function getRootElement() { |
+ if (B.WebKit && !doc.evaluate) |
+ return document; |
- var e = this.expression; |
+ if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) |
+ return document.body; |
- // Safari 3 chokes on :*-of-type and :empty |
- if (Prototype.Browser.WebKit && |
- (e.include("-of-type") || e.include(":empty"))) |
- return false; |
+ return document.documentElement; |
+ } |
- // XPath can't do namespaced attributes, nor can it read |
- // the "checked" property from DOM nodes |
- if ((/(\[[\w-]*?:|:checked)/).test(e)) |
- return false; |
+ function define(D) { |
+ if (!element) element = getRootElement(); |
- return true; |
- }, |
+ property[D] = 'client' + D; |
- shouldUseSelectorsAPI: function() { |
- if (!Prototype.BrowserFeatures.SelectorsAPI) return false; |
+ viewport['get' + D] = function() { return element[property[D]] }; |
+ return viewport['get' + D](); |
+ } |
- if (!Selector._div) Selector._div = new Element('div'); |
+ viewport.getWidth = define.curry('Width'); |
- // Make sure the browser treats the selector as valid. Test on an |
- // isolated element to minimize cost of this check. |
- try { |
- Selector._div.querySelector(this.expression); |
- } catch(e) { |
- return false; |
+ viewport.getHeight = define.curry('Height'); |
+})(document.viewport); |
+ |
+ |
+Element.Storage = { |
+ UID: 1 |
+}; |
+ |
+Element.addMethods({ |
+ getStorage: function(element) { |
+ if (!(element = $(element))) return; |
+ |
+ var uid; |
+ if (element === window) { |
+ uid = 0; |
+ } else { |
+ if (typeof element._prototypeUID === "undefined") |
+ element._prototypeUID = Element.Storage.UID++; |
+ uid = element._prototypeUID; |
} |
- return true; |
+ if (!Element.Storage[uid]) |
+ Element.Storage[uid] = $H(); |
+ |
+ return Element.Storage[uid]; |
}, |
- compileMatcher: function() { |
- var e = this.expression, ps = Selector.patterns, h = Selector.handlers, |
- c = Selector.criteria, le, p, m; |
+ store: function(element, key, value) { |
+ if (!(element = $(element))) return; |
+ |
+ if (arguments.length === 2) { |
+ Element.getStorage(element).update(key); |
+ } else { |
+ Element.getStorage(element).set(key, value); |
+ } |
- if (Selector._cache[e]) { |
- this.matcher = Selector._cache[e]; |
- return; |
+ return element; |
+ }, |
+ |
+ retrieve: function(element, key, defaultValue) { |
+ if (!(element = $(element))) return; |
+ var hash = Element.getStorage(element), value = hash.get(key); |
+ |
+ if (Object.isUndefined(value)) { |
+ hash.set(key, defaultValue); |
+ value = defaultValue; |
} |
- this.matcher = ["this.matcher = function(root) {", |
- "var r = root, h = Selector.handlers, c = false, n;"]; |
+ return value; |
+ }, |
- while (e && le != e && (/\S/).test(e)) { |
- le = e; |
- for (var i in ps) { |
- p = ps[i]; |
- if (m = e.match(p)) { |
- this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : |
- new Template(c[i]).evaluate(m)); |
- e = e.replace(m[0], ''); |
- break; |
- } |
+ clone: function(element, deep) { |
+ if (!(element = $(element))) return; |
+ var clone = element.cloneNode(deep); |
+ clone._prototypeUID = void 0; |
+ if (deep) { |
+ var descendants = Element.select(clone, '*'), |
+ i = descendants.length; |
+ while (i--) { |
+ descendants[i]._prototypeUID = void 0; |
} |
} |
- |
- this.matcher.push("return h.unique(n);\n}"); |
- eval(this.matcher.join('\n')); |
- Selector._cache[this.expression] = this.matcher; |
+ return Element.extend(clone); |
}, |
- compileXPathMatcher: function() { |
- var e = this.expression, ps = Selector.patterns, |
- x = Selector.xpath, le, m; |
+ purge: function(element) { |
+ if (!(element = $(element))) return; |
+ var purgeElement = Element._purgeElement; |
+ |
+ purgeElement(element); |
+ |
+ var descendants = element.getElementsByTagName('*'), |
+ i = descendants.length; |
+ |
+ while (i--) purgeElement(descendants[i]); |
+ |
+ return null; |
+ } |
+}); |
+ |
+(function() { |
- if (Selector._cache[e]) { |
- this.xpath = Selector._cache[e]; return; |
+ function toDecimal(pctString) { |
+ var match = pctString.match(/^(\d+)%?$/i); |
+ if (!match) return null; |
+ return (Number(match[1]) / 100); |
+ } |
+ |
+ function getPixelValue(value, property, context) { |
+ var element = null; |
+ if (Object.isElement(value)) { |
+ element = value; |
+ value = element.getStyle(property); |
} |
- this.matcher = ['.//*']; |
- while (e && le != e && (/\S/).test(e)) { |
- le = e; |
- for (var i in ps) { |
- if (m = e.match(ps[i])) { |
- this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : |
- new Template(x[i]).evaluate(m)); |
- e = e.replace(m[0], ''); |
- break; |
- } |
- } |
+ if (value === null) { |
+ return null; |
} |
- this.xpath = this.matcher.join(''); |
- Selector._cache[this.expression] = this.xpath; |
- }, |
+ if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { |
+ return window.parseFloat(value); |
+ } |
- findElements: function(root) { |
- root = root || document; |
- var e = this.expression, results; |
- |
- switch (this.mode) { |
- case 'selectorsAPI': |
- // querySelectorAll queries document-wide, then filters to descendants |
- // of the context element. That's not what we want. |
- // Add an explicit context to the selector if necessary. |
- if (root !== document) { |
- var oldId = root.id, id = $(root).identify(); |
- e = "#" + id + " " + e; |
- } |
+ var isPercentage = value.include('%'), isViewport = (context === document.viewport); |
- results = $A(root.querySelectorAll(e)).map(Element.extend); |
- root.id = oldId; |
+ if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) { |
+ var style = element.style.left, rStyle = element.runtimeStyle.left; |
+ element.runtimeStyle.left = element.currentStyle.left; |
+ element.style.left = value || 0; |
+ value = element.style.pixelLeft; |
+ element.style.left = style; |
+ element.runtimeStyle.left = rStyle; |
- return results; |
- case 'xpath': |
- return document._getElementsByXPath(this.xpath, root); |
- default: |
- return this.matcher(root); |
+ return value; |
} |
- }, |
- match: function(element) { |
- this.tokens = []; |
- |
- var e = this.expression, ps = Selector.patterns, as = Selector.assertions; |
- var le, p, m; |
- |
- while (e && le !== e && (/\S/).test(e)) { |
- le = e; |
- for (var i in ps) { |
- p = ps[i]; |
- if (m = e.match(p)) { |
- // use the Selector.assertions methods unless the selector |
- // is too complex. |
- if (as[i]) { |
- this.tokens.push([i, Object.clone(m)]); |
- e = e.replace(m[0], ''); |
- } else { |
- // reluctantly do a document-wide search |
- // and look for a match in the array |
- return this.findElements(document).include(element); |
- } |
+ if (element && isPercentage) { |
+ context = context || element.parentNode; |
+ var decimal = toDecimal(value); |
+ var whole = null; |
+ var position = element.getStyle('position'); |
+ |
+ var isHorizontal = property.include('left') || property.include('right') || |
+ property.include('width'); |
+ |
+ var isVertical = property.include('top') || property.include('bottom') || |
+ property.include('height'); |
+ |
+ if (context === document.viewport) { |
+ if (isHorizontal) { |
+ whole = document.viewport.getWidth(); |
+ } else if (isVertical) { |
+ whole = document.viewport.getHeight(); |
+ } |
+ } else { |
+ if (isHorizontal) { |
+ whole = $(context).measure('width'); |
+ } else if (isVertical) { |
+ whole = $(context).measure('height'); |
} |
} |
+ |
+ return (whole === null) ? 0 : whole * decimal; |
} |
- var match = true, name, matches; |
- for (var i = 0, token; token = this.tokens[i]; i++) { |
- name = token[0], matches = token[1]; |
- if (!Selector.assertions[name](element, matches)) { |
- match = false; break; |
- } |
+ return 0; |
+ } |
+ |
+ function toCSSPixels(number) { |
+ if (Object.isString(number) && number.endsWith('px')) { |
+ return number; |
} |
+ return number + 'px'; |
+ } |
- return match; |
- }, |
+ function isDisplayed(element) { |
+ var originalElement = element; |
+ while (element && element.parentNode) { |
+ var display = element.getStyle('display'); |
+ if (display === 'none') { |
+ return false; |
+ } |
+ element = $(element.parentNode); |
+ } |
+ return true; |
+ } |
- toString: function() { |
- return this.expression; |
- }, |
+ var hasLayout = Prototype.K; |
+ if ('currentStyle' in document.documentElement) { |
+ hasLayout = function(element) { |
+ if (!element.currentStyle.hasLayout) { |
+ element.style.zoom = 1; |
+ } |
+ return element; |
+ }; |
+ } |
- inspect: function() { |
- return "#<Selector:" + this.expression.inspect() + ">"; |
+ function cssNameFor(key) { |
+ if (key.include('border')) key = key + '-width'; |
+ return key.camelize(); |
} |
-}); |
-Object.extend(Selector, { |
- _cache: { }, |
- |
- xpath: { |
- descendant: "//*", |
- child: "/*", |
- adjacent: "/following-sibling::*[1]", |
- laterSibling: '/following-sibling::*', |
- tagName: function(m) { |
- if (m[1] == '*') return ''; |
- return "[local-name()='" + m[1].toLowerCase() + |
- "' or local-name()='" + m[1].toUpperCase() + "']"; |
+ Element.Layout = Class.create(Hash, { |
+ initialize: function($super, element, preCompute) { |
+ $super(); |
+ this.element = $(element); |
+ |
+ Element.Layout.PROPERTIES.each( function(property) { |
+ this._set(property, null); |
+ }, this); |
+ |
+ if (preCompute) { |
+ this._preComputing = true; |
+ this._begin(); |
+ Element.Layout.PROPERTIES.each( this._compute, this ); |
+ this._end(); |
+ this._preComputing = false; |
+ } |
+ }, |
+ |
+ _set: function(property, value) { |
+ return Hash.prototype.set.call(this, property, value); |
+ }, |
+ |
+ set: function(property, value) { |
+ throw "Properties of Element.Layout are read-only."; |
+ }, |
+ |
+ get: function($super, property) { |
+ var value = $super(property); |
+ return value === null ? this._compute(property) : value; |
+ }, |
+ |
+ _begin: function() { |
+ if (this._prepared) return; |
+ |
+ var element = this.element; |
+ if (isDisplayed(element)) { |
+ this._prepared = true; |
+ return; |
+ } |
+ |
+ var originalStyles = { |
+ position: element.style.position || '', |
+ width: element.style.width || '', |
+ visibility: element.style.visibility || '', |
+ display: element.style.display || '' |
+ }; |
+ |
+ element.store('prototype_original_styles', originalStyles); |
+ |
+ var position = element.getStyle('position'), |
+ width = element.getStyle('width'); |
+ |
+ if (width === "0px" || width === null) { |
+ element.style.display = 'block'; |
+ width = element.getStyle('width'); |
+ } |
+ |
+ var context = (position === 'fixed') ? document.viewport : |
+ element.parentNode; |
+ |
+ element.setStyle({ |
+ position: 'absolute', |
+ visibility: 'hidden', |
+ display: 'block' |
+ }); |
+ |
+ var positionedWidth = element.getStyle('width'); |
+ |
+ var newWidth; |
+ if (width && (positionedWidth === width)) { |
+ newWidth = getPixelValue(element, 'width', context); |
+ } else if (position === 'absolute' || position === 'fixed') { |
+ newWidth = getPixelValue(element, 'width', context); |
+ } else { |
+ var parent = element.parentNode, pLayout = $(parent).getLayout(); |
+ |
+ newWidth = pLayout.get('width') - |
+ this.get('margin-left') - |
+ this.get('border-left') - |
+ this.get('padding-left') - |
+ this.get('padding-right') - |
+ this.get('border-right') - |
+ this.get('margin-right'); |
+ } |
+ |
+ element.setStyle({ width: newWidth + 'px' }); |
+ |
+ this._prepared = true; |
}, |
- className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", |
- id: "[@id='#{1}']", |
- attrPresence: function(m) { |
- m[1] = m[1].toLowerCase(); |
- return new Template("[@#{1}]").evaluate(m); |
+ |
+ _end: function() { |
+ var element = this.element; |
+ var originalStyles = element.retrieve('prototype_original_styles'); |
+ element.store('prototype_original_styles', null); |
+ element.setStyle(originalStyles); |
+ this._prepared = false; |
}, |
- attr: function(m) { |
- m[1] = m[1].toLowerCase(); |
- m[3] = m[5] || m[6]; |
- return new Template(Selector.xpath.operators[m[2]]).evaluate(m); |
+ |
+ _compute: function(property) { |
+ var COMPUTATIONS = Element.Layout.COMPUTATIONS; |
+ if (!(property in COMPUTATIONS)) { |
+ throw "Property not found."; |
+ } |
+ |
+ return this._set(property, COMPUTATIONS[property].call(this, this.element)); |
}, |
- pseudo: function(m) { |
- var h = Selector.xpath.pseudos[m[1]]; |
- if (!h) return ''; |
- if (Object.isFunction(h)) return h(m); |
- return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); |
+ |
+ toObject: function() { |
+ var args = $A(arguments); |
+ var keys = (args.length === 0) ? Element.Layout.PROPERTIES : |
+ args.join(' ').split(' '); |
+ var obj = {}; |
+ keys.each( function(key) { |
+ if (!Element.Layout.PROPERTIES.include(key)) return; |
+ var value = this.get(key); |
+ if (value != null) obj[key] = value; |
+ }, this); |
+ return obj; |
}, |
- operators: { |
- '=': "[@#{1}='#{3}']", |
- '!=': "[@#{1}!='#{3}']", |
- '^=': "[starts-with(@#{1}, '#{3}')]", |
- '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", |
- '*=': "[contains(@#{1}, '#{3}')]", |
- '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", |
- '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" |
+ |
+ toHash: function() { |
+ var obj = this.toObject.apply(this, arguments); |
+ return new Hash(obj); |
}, |
- pseudos: { |
- 'first-child': '[not(preceding-sibling::*)]', |
- 'last-child': '[not(following-sibling::*)]', |
- 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', |
- 'empty': "[count(*) = 0 and (count(text()) = 0)]", |
- 'checked': "[@checked]", |
- 'disabled': "[(@disabled) and (@type!='hidden')]", |
- 'enabled': "[not(@disabled) and (@type!='hidden')]", |
- 'not': function(m) { |
- var e = m[6], p = Selector.patterns, |
- x = Selector.xpath, le, v; |
- |
- var exclusion = []; |
- while (e && le != e && (/\S/).test(e)) { |
- le = e; |
- for (var i in p) { |
- if (m = e.match(p[i])) { |
- v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); |
- exclusion.push("(" + v.substring(1, v.length - 1) + ")"); |
- e = e.replace(m[0], ''); |
- break; |
- } |
- } |
+ |
+ toCSS: function() { |
+ var args = $A(arguments); |
+ var keys = (args.length === 0) ? Element.Layout.PROPERTIES : |
+ args.join(' ').split(' '); |
+ var css = {}; |
+ |
+ keys.each( function(key) { |
+ if (!Element.Layout.PROPERTIES.include(key)) return; |
+ if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; |
+ |
+ var value = this.get(key); |
+ if (value != null) css[cssNameFor(key)] = value + 'px'; |
+ }, this); |
+ return css; |
+ }, |
+ |
+ inspect: function() { |
+ return "#<Element.Layout>"; |
+ } |
+ }); |
+ |
+ Object.extend(Element.Layout, { |
+ 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'), |
+ |
+ COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), |
+ |
+ COMPUTATIONS: { |
+ 'height': function(element) { |
+ if (!this._preComputing) this._begin(); |
+ |
+ var bHeight = this.get('border-box-height'); |
+ if (bHeight <= 0) { |
+ if (!this._preComputing) this._end(); |
+ return 0; |
+ } |
+ |
+ var bTop = this.get('border-top'), |
+ bBottom = this.get('border-bottom'); |
+ |
+ var pTop = this.get('padding-top'), |
+ pBottom = this.get('padding-bottom'); |
+ |
+ if (!this._preComputing) this._end(); |
+ |
+ return bHeight - bTop - bBottom - pTop - pBottom; |
+ }, |
+ |
+ 'width': function(element) { |
+ if (!this._preComputing) this._begin(); |
+ |
+ var bWidth = this.get('border-box-width'); |
+ if (bWidth <= 0) { |
+ if (!this._preComputing) this._end(); |
+ return 0; |
} |
- return "[not(" + exclusion.join(" and ") + ")]"; |
+ |
+ var bLeft = this.get('border-left'), |
+ bRight = this.get('border-right'); |
+ |
+ var pLeft = this.get('padding-left'), |
+ pRight = this.get('padding-right'); |
+ |
+ if (!this._preComputing) this._end(); |
+ |
+ return bWidth - bLeft - bRight - pLeft - pRight; |
+ }, |
+ |
+ 'padding-box-height': function(element) { |
+ var height = this.get('height'), |
+ pTop = this.get('padding-top'), |
+ pBottom = this.get('padding-bottom'); |
+ |
+ return height + pTop + pBottom; |
+ }, |
+ |
+ 'padding-box-width': function(element) { |
+ var width = this.get('width'), |
+ pLeft = this.get('padding-left'), |
+ pRight = this.get('padding-right'); |
+ |
+ return width + pLeft + pRight; |
+ }, |
+ |
+ 'border-box-height': function(element) { |
+ if (!this._preComputing) this._begin(); |
+ var height = element.offsetHeight; |
+ if (!this._preComputing) this._end(); |
+ return height; |
+ }, |
+ |
+ 'border-box-width': function(element) { |
+ if (!this._preComputing) this._begin(); |
+ var width = element.offsetWidth; |
+ if (!this._preComputing) this._end(); |
+ return width; |
+ }, |
+ |
+ 'margin-box-height': function(element) { |
+ var bHeight = this.get('border-box-height'), |
+ mTop = this.get('margin-top'), |
+ mBottom = this.get('margin-bottom'); |
+ |
+ if (bHeight <= 0) return 0; |
+ |
+ return bHeight + mTop + mBottom; |
+ }, |
+ |
+ 'margin-box-width': function(element) { |
+ var bWidth = this.get('border-box-width'), |
+ mLeft = this.get('margin-left'), |
+ mRight = this.get('margin-right'); |
+ |
+ if (bWidth <= 0) return 0; |
+ |
+ return bWidth + mLeft + mRight; |
+ }, |
+ |
+ 'top': function(element) { |
+ var offset = element.positionedOffset(); |
+ return offset.top; |
+ }, |
+ |
+ 'bottom': function(element) { |
+ var offset = element.positionedOffset(), |
+ parent = element.getOffsetParent(), |
+ pHeight = parent.measure('height'); |
+ |
+ var mHeight = this.get('border-box-height'); |
+ |
+ return pHeight - mHeight - offset.top; |
+ }, |
+ |
+ 'left': function(element) { |
+ var offset = element.positionedOffset(); |
+ return offset.left; |
+ }, |
+ |
+ 'right': function(element) { |
+ var offset = element.positionedOffset(), |
+ parent = element.getOffsetParent(), |
+ pWidth = parent.measure('width'); |
+ |
+ var mWidth = this.get('border-box-width'); |
+ |
+ return pWidth - mWidth - offset.left; |
+ }, |
+ |
+ 'padding-top': function(element) { |
+ return getPixelValue(element, 'paddingTop'); |
+ }, |
+ |
+ 'padding-bottom': function(element) { |
+ return getPixelValue(element, 'paddingBottom'); |
}, |
- 'nth-child': function(m) { |
- return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); |
+ |
+ 'padding-left': function(element) { |
+ return getPixelValue(element, 'paddingLeft'); |
}, |
- 'nth-last-child': function(m) { |
- return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); |
+ |
+ 'padding-right': function(element) { |
+ return getPixelValue(element, 'paddingRight'); |
}, |
- 'nth-of-type': function(m) { |
- return Selector.xpath.pseudos.nth("position() ", m); |
+ |
+ 'border-top': function(element) { |
+ return getPixelValue(element, 'borderTopWidth'); |
}, |
- 'nth-last-of-type': function(m) { |
- return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); |
+ |
+ 'border-bottom': function(element) { |
+ return getPixelValue(element, 'borderBottomWidth'); |
}, |
- 'first-of-type': function(m) { |
- m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); |
+ |
+ 'border-left': function(element) { |
+ return getPixelValue(element, 'borderLeftWidth'); |
}, |
- 'last-of-type': function(m) { |
- m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); |
+ |
+ 'border-right': function(element) { |
+ return getPixelValue(element, 'borderRightWidth'); |
}, |
- 'only-of-type': function(m) { |
- var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); |
+ |
+ 'margin-top': function(element) { |
+ return getPixelValue(element, 'marginTop'); |
}, |
- nth: function(fragment, m) { |
- var mm, formula = m[6], predicate; |
- if (formula == 'even') formula = '2n+0'; |
- if (formula == 'odd') formula = '2n+1'; |
- if (mm = formula.match(/^(\d+)$/)) // digit only |
- return '[' + fragment + "= " + mm[1] + ']'; |
- if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b |
- if (mm[1] == "-") mm[1] = -1; |
- var a = mm[1] ? Number(mm[1]) : 1; |
- var b = mm[2] ? Number(mm[2]) : 0; |
- predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + |
- "((#{fragment} - #{b}) div #{a} >= 0)]"; |
- return new Template(predicate).evaluate({ |
- fragment: fragment, a: a, b: b }); |
- } |
+ |
+ 'margin-bottom': function(element) { |
+ return getPixelValue(element, 'marginBottom'); |
+ }, |
+ |
+ 'margin-left': function(element) { |
+ return getPixelValue(element, 'marginLeft'); |
+ }, |
+ |
+ 'margin-right': function(element) { |
+ return getPixelValue(element, 'marginRight'); |
} |
} |
- }, |
+ }); |
- criteria: { |
- tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', |
- className: 'n = h.className(n, r, "#{1}", c); c = false;', |
- id: 'n = h.id(n, r, "#{1}", c); c = false;', |
- attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', |
- attr: function(m) { |
- m[3] = (m[5] || m[6]); |
- return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); |
- }, |
- pseudo: function(m) { |
- if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); |
- return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); |
- }, |
- descendant: 'c = "descendant";', |
- child: 'c = "child";', |
- adjacent: 'c = "adjacent";', |
- laterSibling: 'c = "laterSibling";' |
- }, |
+ if ('getBoundingClientRect' in document.documentElement) { |
+ Object.extend(Element.Layout.COMPUTATIONS, { |
+ 'right': function(element) { |
+ var parent = hasLayout(element.getOffsetParent()); |
+ var rect = element.getBoundingClientRect(), |
+ pRect = parent.getBoundingClientRect(); |
- patterns: { |
- // combinators must be listed first |
- // (and descendant needs to be last combinator) |
- laterSibling: /^\s*~\s*/, |
- child: /^\s*>\s*/, |
- adjacent: /^\s*\+\s*/, |
- descendant: /^\s/, |
- |
- // selectors follow |
- tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, |
- id: /^#([\w\-\*]+)(\b|$)/, |
- className: /^\.([\w\-\*]+)(\b|$)/, |
- pseudo: |
-/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, |
- attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, |
- attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ |
- }, |
+ return (pRect.right - rect.right).round(); |
+ }, |
+ |
+ 'bottom': function(element) { |
+ var parent = hasLayout(element.getOffsetParent()); |
+ var rect = element.getBoundingClientRect(), |
+ pRect = parent.getBoundingClientRect(); |
+ |
+ return (pRect.bottom - rect.bottom).round(); |
+ } |
+ }); |
+ } |
- // for Selector.match and Element#match |
- assertions: { |
- tagName: function(element, matches) { |
- return matches[1].toUpperCase() == element.tagName.toUpperCase(); |
+ Element.Offset = Class.create({ |
+ initialize: function(left, top) { |
+ this.left = left.round(); |
+ this.top = top.round(); |
+ |
+ this[0] = this.left; |
+ this[1] = this.top; |
}, |
- className: function(element, matches) { |
- return Element.hasClassName(element, matches[1]); |
+ relativeTo: function(offset) { |
+ return new Element.Offset( |
+ this.left - offset.left, |
+ this.top - offset.top |
+ ); |
}, |
- id: function(element, matches) { |
- return element.id === matches[1]; |
+ inspect: function() { |
+ return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this); |
}, |
- attrPresence: function(element, matches) { |
- return Element.hasAttribute(element, matches[1]); |
+ toString: function() { |
+ return "[#{left}, #{top}]".interpolate(this); |
}, |
- attr: function(element, matches) { |
- var nodeValue = Element.readAttribute(element, matches[1]); |
- return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); |
+ toArray: function() { |
+ return [this.left, this.top]; |
} |
- }, |
+ }); |
- handlers: { |
- // UTILITY FUNCTIONS |
- // joins two collections |
- concat: function(a, b) { |
- for (var i = 0, node; node = b[i]; i++) |
- a.push(node); |
- return a; |
- }, |
+ function getLayout(element, preCompute) { |
+ return new Element.Layout(element, preCompute); |
+ } |
- // marks an array of nodes for counting |
- mark: function(nodes) { |
- var _true = Prototype.emptyFunction; |
- for (var i = 0, node; node = nodes[i]; i++) |
- node._countedByPrototype = _true; |
- return nodes; |
- }, |
+ function measure(element, property) { |
+ return $(element).getLayout().get(property); |
+ } |
- unmark: function(nodes) { |
- for (var i = 0, node; node = nodes[i]; i++) |
- node._countedByPrototype = undefined; |
- return nodes; |
- }, |
+ function getDimensions(element) { |
+ element = $(element); |
+ var display = Element.getStyle(element, 'display'); |
- // mark each child node with its position (for nth calls) |
- // "ofType" flag indicates whether we're indexing for nth-of-type |
- // rather than nth-child |
- index: function(parentNode, reverse, ofType) { |
- parentNode._countedByPrototype = Prototype.emptyFunction; |
- if (reverse) { |
- for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { |
- var node = nodes[i]; |
- if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; |
- } |
- } else { |
- for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) |
- if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; |
- } |
- }, |
+ if (display && display !== 'none') { |
+ return { width: element.offsetWidth, height: element.offsetHeight }; |
+ } |
- // filters out duplicates and extends all nodes |
- unique: function(nodes) { |
- if (nodes.length == 0) return nodes; |
- var results = [], n; |
- for (var i = 0, l = nodes.length; i < l; i++) |
- if (!(n = nodes[i])._countedByPrototype) { |
- n._countedByPrototype = Prototype.emptyFunction; |
- results.push(Element.extend(n)); |
- } |
- return Selector.handlers.unmark(results); |
- }, |
+ var style = element.style; |
+ var originalStyles = { |
+ visibility: style.visibility, |
+ position: style.position, |
+ display: style.display |
+ }; |
- // COMBINATOR FUNCTIONS |
- descendant: function(nodes) { |
- var h = Selector.handlers; |
- for (var i = 0, results = [], node; node = nodes[i]; i++) |
- h.concat(results, node.getElementsByTagName('*')); |
- return results; |
- }, |
+ var newStyles = { |
+ visibility: 'hidden', |
+ display: 'block' |
+ }; |
- child: function(nodes) { |
- var h = Selector.handlers; |
- for (var i = 0, results = [], node; node = nodes[i]; i++) { |
- for (var j = 0, child; child = node.childNodes[j]; j++) |
- if (child.nodeType == 1 && child.tagName != '!') results.push(child); |
- } |
- return results; |
- }, |
+ if (originalStyles.position !== 'fixed') |
+ newStyles.position = 'absolute'; |
- adjacent: function(nodes) { |
- for (var i = 0, results = [], node; node = nodes[i]; i++) { |
- var next = this.nextElementSibling(node); |
- if (next) results.push(next); |
- } |
- return results; |
- }, |
+ Element.setStyle(element, newStyles); |
- laterSibling: function(nodes) { |
- var h = Selector.handlers; |
- for (var i = 0, results = [], node; node = nodes[i]; i++) |
- h.concat(results, Element.nextSiblings(node)); |
- return results; |
- }, |
+ var dimensions = { |
+ width: element.offsetWidth, |
+ height: element.offsetHeight |
+ }; |
- nextElementSibling: function(node) { |
- while (node = node.nextSibling) |
- if (node.nodeType == 1) return node; |
- return null; |
- }, |
+ Element.setStyle(element, originalStyles); |
- previousElementSibling: function(node) { |
- while (node = node.previousSibling) |
- if (node.nodeType == 1) return node; |
- return null; |
- }, |
+ return dimensions; |
+ } |
- // TOKEN FUNCTIONS |
- tagName: function(nodes, root, tagName, combinator) { |
- var uTagName = tagName.toUpperCase(); |
- var results = [], h = Selector.handlers; |
- if (nodes) { |
- if (combinator) { |
- // fastlane for ordinary descendant combinators |
- if (combinator == "descendant") { |
- for (var i = 0, node; node = nodes[i]; i++) |
- h.concat(results, node.getElementsByTagName(tagName)); |
- return results; |
- } else nodes = this[combinator](nodes); |
- if (tagName == "*") return nodes; |
- } |
- for (var i = 0, node; node = nodes[i]; i++) |
- if (node.tagName.toUpperCase() === uTagName) results.push(node); |
- return results; |
- } else return root.getElementsByTagName(tagName); |
- }, |
+ function getOffsetParent(element) { |
+ element = $(element); |
- id: function(nodes, root, id, combinator) { |
- var targetNode = $(id), h = Selector.handlers; |
- if (!targetNode) return []; |
- if (!nodes && root == document) return [targetNode]; |
- if (nodes) { |
- if (combinator) { |
- if (combinator == 'child') { |
- for (var i = 0, node; node = nodes[i]; i++) |
- if (targetNode.parentNode == node) return [targetNode]; |
- } else if (combinator == 'descendant') { |
- for (var i = 0, node; node = nodes[i]; i++) |
- if (Element.descendantOf(targetNode, node)) return [targetNode]; |
- } else if (combinator == 'adjacent') { |
- for (var i = 0, node; node = nodes[i]; i++) |
- if (Selector.handlers.previousElementSibling(targetNode) == node) |
- return [targetNode]; |
- } else nodes = h[combinator](nodes); |
- } |
- for (var i = 0, node; node = nodes[i]; i++) |
- if (node == targetNode) return [targetNode]; |
- return []; |
- } |
- return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; |
- }, |
+ if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) |
+ return $(document.body); |
- className: function(nodes, root, className, combinator) { |
- if (nodes && combinator) nodes = this[combinator](nodes); |
- return Selector.handlers.byClassName(nodes, root, className); |
- }, |
+ var isInline = (Element.getStyle(element, 'display') === 'inline'); |
+ if (!isInline && element.offsetParent) return $(element.offsetParent); |
- byClassName: function(nodes, root, className) { |
- if (!nodes) nodes = Selector.handlers.descendant([root]); |
- var needle = ' ' + className + ' '; |
- for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { |
- nodeClassName = node.className; |
- if (nodeClassName.length == 0) continue; |
- if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) |
- results.push(node); |
+ while ((element = element.parentNode) && element !== document.body) { |
+ if (Element.getStyle(element, 'position') !== 'static') { |
+ return isHtml(element) ? $(document.body) : $(element); |
} |
- return results; |
- }, |
+ } |
- attrPresence: function(nodes, root, attr, combinator) { |
- if (!nodes) nodes = root.getElementsByTagName("*"); |
- if (nodes && combinator) nodes = this[combinator](nodes); |
- var results = []; |
- for (var i = 0, node; node = nodes[i]; i++) |
- if (Element.hasAttribute(node, attr)) results.push(node); |
- return results; |
- }, |
+ return $(document.body); |
+ } |
- attr: function(nodes, root, attr, value, operator, combinator) { |
- if (!nodes) nodes = root.getElementsByTagName("*"); |
- if (nodes && combinator) nodes = this[combinator](nodes); |
- var handler = Selector.operators[operator], results = []; |
- for (var i = 0, node; node = nodes[i]; i++) { |
- var nodeValue = Element.readAttribute(node, attr); |
- if (nodeValue === null) continue; |
- if (handler(nodeValue, value)) results.push(node); |
- } |
- return results; |
- }, |
- pseudo: function(nodes, name, value, root, combinator) { |
- if (nodes && combinator) nodes = this[combinator](nodes); |
- if (!nodes) nodes = root.getElementsByTagName("*"); |
- return Selector.pseudos[name](nodes, value, root); |
+ function cumulativeOffset(element) { |
+ element = $(element); |
+ var valueT = 0, valueL = 0; |
+ if (element.parentNode) { |
+ do { |
+ valueT += element.offsetTop || 0; |
+ valueL += element.offsetLeft || 0; |
+ element = element.offsetParent; |
+ } while (element); |
} |
- }, |
+ return new Element.Offset(valueL, valueT); |
+ } |
- pseudos: { |
- 'first-child': function(nodes, value, root) { |
- for (var i = 0, results = [], node; node = nodes[i]; i++) { |
- if (Selector.handlers.previousElementSibling(node)) continue; |
- results.push(node); |
- } |
- return results; |
- }, |
- 'last-child': function(nodes, value, root) { |
- for (var i = 0, results = [], node; node = nodes[i]; i++) { |
- if (Selector.handlers.nextElementSibling(node)) continue; |
- results.push(node); |
- } |
- return results; |
- }, |
- 'only-child': function(nodes, value, root) { |
- var h = Selector.handlers; |
- for (var i = 0, results = [], node; node = nodes[i]; i++) |
- if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) |
- results.push(node); |
- return results; |
- }, |
- 'nth-child': function(nodes, formula, root) { |
- return Selector.pseudos.nth(nodes, formula, root); |
- }, |
- 'nth-last-child': function(nodes, formula, root) { |
- return Selector.pseudos.nth(nodes, formula, root, true); |
- }, |
- 'nth-of-type': function(nodes, formula, root) { |
- return Selector.pseudos.nth(nodes, formula, root, false, true); |
- }, |
- 'nth-last-of-type': function(nodes, formula, root) { |
- return Selector.pseudos.nth(nodes, formula, root, true, true); |
- }, |
- 'first-of-type': function(nodes, formula, root) { |
- return Selector.pseudos.nth(nodes, "1", root, false, true); |
- }, |
- 'last-of-type': function(nodes, formula, root) { |
- return Selector.pseudos.nth(nodes, "1", root, true, true); |
- }, |
- 'only-of-type': function(nodes, formula, root) { |
- var p = Selector.pseudos; |
- return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); |
- }, |
+ function positionedOffset(element) { |
+ element = $(element); |
- // handles the an+b logic |
- getIndices: function(a, b, total) { |
- if (a == 0) return b > 0 ? [b] : []; |
- return $R(1, total).inject([], function(memo, i) { |
- if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); |
- return memo; |
- }); |
- }, |
+ var layout = element.getLayout(); |
- // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type |
- nth: function(nodes, formula, root, reverse, ofType) { |
- if (nodes.length == 0) return []; |
- if (formula == 'even') formula = '2n+0'; |
- if (formula == 'odd') formula = '2n+1'; |
- var h = Selector.handlers, results = [], indexed = [], m; |
- h.mark(nodes); |
- for (var i = 0, node; node = nodes[i]; i++) { |
- if (!node.parentNode._countedByPrototype) { |
- h.index(node.parentNode, reverse, ofType); |
- indexed.push(node.parentNode); |
- } |
- } |
- if (formula.match(/^\d+$/)) { // just a number |
- formula = Number(formula); |
- for (var i = 0, node; node = nodes[i]; i++) |
- if (node.nodeIndex == formula) results.push(node); |
- } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b |
- if (m[1] == "-") m[1] = -1; |
- var a = m[1] ? Number(m[1]) : 1; |
- var b = m[2] ? Number(m[2]) : 0; |
- var indices = Selector.pseudos.getIndices(a, b, nodes.length); |
- for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { |
- for (var j = 0; j < l; j++) |
- if (node.nodeIndex == indices[j]) results.push(node); |
- } |
+ var valueT = 0, valueL = 0; |
+ do { |
+ valueT += element.offsetTop || 0; |
+ valueL += element.offsetLeft || 0; |
+ element = element.offsetParent; |
+ if (element) { |
+ if (isBody(element)) break; |
+ var p = Element.getStyle(element, 'position'); |
+ if (p !== 'static') break; |
} |
- h.unmark(nodes); |
- h.unmark(indexed); |
- return results; |
- }, |
+ } while (element); |
+ |
+ valueL -= layout.get('margin-top'); |
+ valueT -= layout.get('margin-left'); |
+ |
+ return new Element.Offset(valueL, valueT); |
+ } |
+ |
+ function cumulativeScrollOffset(element) { |
+ var valueT = 0, valueL = 0; |
+ do { |
+ valueT += element.scrollTop || 0; |
+ valueL += element.scrollLeft || 0; |
+ element = element.parentNode; |
+ } while (element); |
+ return new Element.Offset(valueL, valueT); |
+ } |
+ |
+ function viewportOffset(forElement) { |
+ element = $(element); |
+ var valueT = 0, valueL = 0, docBody = document.body; |
+ |
+ var element = forElement; |
+ do { |
+ valueT += element.offsetTop || 0; |
+ valueL += element.offsetLeft || 0; |
+ if (element.offsetParent == docBody && |
+ Element.getStyle(element, 'position') == 'absolute') break; |
+ } while (element = element.offsetParent); |
- 'empty': function(nodes, value, root) { |
- for (var i = 0, results = [], node; node = nodes[i]; i++) { |
- // IE treats comments as element nodes |
- if (node.tagName == '!' || node.firstChild) continue; |
- results.push(node); |
+ element = forElement; |
+ do { |
+ if (element != docBody) { |
+ valueT -= element.scrollTop || 0; |
+ valueL -= element.scrollLeft || 0; |
} |
- return results; |
- }, |
+ } while (element = element.parentNode); |
+ return new Element.Offset(valueL, valueT); |
+ } |
- 'not': function(nodes, selector, root) { |
- var h = Selector.handlers, selectorType, m; |
- var exclusions = new Selector(selector).findElements(root); |
- h.mark(exclusions); |
- for (var i = 0, results = [], node; node = nodes[i]; i++) |
- if (!node._countedByPrototype) results.push(node); |
- h.unmark(exclusions); |
- return results; |
- }, |
+ function absolutize(element) { |
+ element = $(element); |
- 'enabled': function(nodes, value, root) { |
- for (var i = 0, results = [], node; node = nodes[i]; i++) |
- if (!node.disabled && (!node.type || node.type !== 'hidden')) |
- results.push(node); |
- return results; |
- }, |
+ if (Element.getStyle(element, 'position') === 'absolute') { |
+ return element; |
+ } |
- 'disabled': function(nodes, value, root) { |
- for (var i = 0, results = [], node; node = nodes[i]; i++) |
- if (node.disabled) results.push(node); |
- return results; |
- }, |
+ var offsetParent = getOffsetParent(element); |
+ var eOffset = element.viewportOffset(), |
+ pOffset = offsetParent.viewportOffset(); |
- 'checked': function(nodes, value, root) { |
- for (var i = 0, results = [], node; node = nodes[i]; i++) |
- if (node.checked) results.push(node); |
- return results; |
+ var offset = eOffset.relativeTo(pOffset); |
+ var layout = element.getLayout(); |
+ |
+ element.store('prototype_absolutize_original_styles', { |
+ left: element.getStyle('left'), |
+ top: element.getStyle('top'), |
+ width: element.getStyle('width'), |
+ height: element.getStyle('height') |
+ }); |
+ |
+ element.setStyle({ |
+ position: 'absolute', |
+ top: offset.top + 'px', |
+ left: offset.left + 'px', |
+ width: layout.get('width') + 'px', |
+ height: layout.get('height') + 'px' |
+ }); |
+ |
+ return element; |
+ } |
+ |
+ function relativize(element) { |
+ element = $(element); |
+ if (Element.getStyle(element, 'position') === 'relative') { |
+ return element; |
} |
- }, |
- operators: { |
- '=': function(nv, v) { return nv == v; }, |
- '!=': function(nv, v) { return nv != v; }, |
- '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, |
- '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, |
- '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, |
- '$=': function(nv, v) { return nv.endsWith(v); }, |
- '*=': function(nv, v) { return nv.include(v); }, |
- '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, |
- '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + |
- '-').include('-' + (v || "").toUpperCase() + '-'); } |
- }, |
+ var originalStyles = |
+ element.retrieve('prototype_absolutize_original_styles'); |
+ |
+ if (originalStyles) element.setStyle(originalStyles); |
+ return element; |
+ } |
+ |
+ if (Prototype.Browser.IE) { |
+ getOffsetParent = getOffsetParent.wrap( |
+ function(proceed, element) { |
+ element = $(element); |
+ |
+ if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) |
+ return $(document.body); |
+ |
+ var position = element.getStyle('position'); |
+ if (position !== 'static') return proceed(element); |
+ |
+ element.setStyle({ position: 'relative' }); |
+ var value = proceed(element); |
+ element.setStyle({ position: position }); |
+ return value; |
+ } |
+ ); |
+ |
+ positionedOffset = positionedOffset.wrap(function(proceed, element) { |
+ element = $(element); |
+ if (!element.parentNode) return new Element.Offset(0, 0); |
+ var position = element.getStyle('position'); |
+ if (position !== 'static') return proceed(element); |
+ |
+ var offsetParent = element.getOffsetParent(); |
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed') |
+ hasLayout(offsetParent); |
- split: function(expression) { |
- var expressions = []; |
- expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { |
- expressions.push(m[1].strip()); |
+ element.setStyle({ position: 'relative' }); |
+ var value = proceed(element); |
+ element.setStyle({ position: position }); |
+ return value; |
}); |
- return expressions; |
- }, |
+ } else if (Prototype.Browser.Webkit) { |
+ cumulativeOffset = function(element) { |
+ element = $(element); |
+ var valueT = 0, valueL = 0; |
+ do { |
+ valueT += element.offsetTop || 0; |
+ valueL += element.offsetLeft || 0; |
+ if (element.offsetParent == document.body) |
+ if (Element.getStyle(element, 'position') == 'absolute') break; |
- matchElements: function(elements, expression) { |
- var matches = $$(expression), h = Selector.handlers; |
- h.mark(matches); |
- for (var i = 0, results = [], element; element = elements[i]; i++) |
- if (element._countedByPrototype) results.push(element); |
- h.unmark(matches); |
- return results; |
- }, |
+ element = element.offsetParent; |
+ } while (element); |
- findElement: function(elements, expression, index) { |
- if (Object.isNumber(expression)) { |
- index = expression; expression = false; |
+ return new Element.Offset(valueL, valueT); |
+ }; |
+ } |
+ |
+ |
+ Element.addMethods({ |
+ getLayout: getLayout, |
+ measure: measure, |
+ getDimensions: getDimensions, |
+ getOffsetParent: getOffsetParent, |
+ cumulativeOffset: cumulativeOffset, |
+ positionedOffset: positionedOffset, |
+ cumulativeScrollOffset: cumulativeScrollOffset, |
+ viewportOffset: viewportOffset, |
+ absolutize: absolutize, |
+ relativize: relativize |
+ }); |
+ |
+ function isBody(element) { |
+ return element.nodeName.toUpperCase() === 'BODY'; |
+ } |
+ |
+ function isHtml(element) { |
+ return element.nodeName.toUpperCase() === 'HTML'; |
+ } |
+ |
+ function isDocument(element) { |
+ return element.nodeType === Node.DOCUMENT_NODE; |
+ } |
+ |
+ function isDetached(element) { |
+ return element !== document.body && |
+ !Element.descendantOf(element, document.body); |
+ } |
+ |
+ if ('getBoundingClientRect' in document.documentElement) { |
+ Element.addMethods({ |
+ viewportOffset: function(element) { |
+ element = $(element); |
+ if (isDetached(element)) return new Element.Offset(0, 0); |
+ |
+ var rect = element.getBoundingClientRect(), |
+ docEl = document.documentElement; |
+ return new Element.Offset(rect.left - docEl.clientLeft, |
+ rect.top - docEl.clientTop); |
+ } |
+ }); |
+ } |
+})(); |
+window.$$ = function() { |
+ var expression = $A(arguments).join(', '); |
+ return Prototype.Selector.select(expression, document); |
+}; |
+ |
+Prototype.Selector = (function() { |
+ |
+ function select() { |
+ throw new Error('Method "Prototype.Selector.select" must be defined.'); |
+ } |
+ |
+ function match() { |
+ throw new Error('Method "Prototype.Selector.match" must be defined.'); |
+ } |
+ |
+ function find(elements, expression, index) { |
+ index = index || 0; |
+ var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; |
+ |
+ for (i = 0; i < length; i++) { |
+ if (match(elements[i], expression) && index == matchIndex++) { |
+ return Element.extend(elements[i]); |
+ } |
} |
- return Selector.matchElements(elements, expression || '*')[index || 0]; |
- }, |
+ } |
- findChildElements: function(element, expressions) { |
- expressions = Selector.split(expressions.join(',')); |
- var results = [], h = Selector.handlers; |
- for (var i = 0, l = expressions.length, selector; i < l; i++) { |
- selector = new Selector(expressions[i].strip()); |
- h.concat(results, selector.findElements(element)); |
+ function extendElements(elements) { |
+ for (var i = 0, length = elements.length; i < length; i++) { |
+ Element.extend(elements[i]); |
} |
- return (l > 1) ? h.unique(results) : results; |
+ return elements; |
} |
+ |
+ |
+ var K = Prototype.K; |
+ |
+ return { |
+ select: select, |
+ match: match, |
+ find: find, |
+ extendElements: (Element.extend === K) ? K : extendElements, |
+ extendElement: Element.extend |
+ }; |
+})(); |
+Prototype._original_property = window.Sizzle; |
+/*! |
+ * Sizzle CSS Selector Engine - v1.0 |
+ * Copyright 2009, The Dojo Foundation |
+ * Released under the MIT, BSD, and GPL Licenses. |
+ * More information: http://sizzlejs.com/ |
+ */ |
+(function(){ |
+ |
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, |
+ done = 0, |
+ toString = Object.prototype.toString, |
+ hasDuplicate = false, |
+ baseHasDuplicate = true; |
+ |
+[0, 0].sort(function(){ |
+ baseHasDuplicate = false; |
+ return 0; |
}); |
-if (Prototype.Browser.IE) { |
- Object.extend(Selector.handlers, { |
- // IE returns comment nodes on getElementsByTagName("*"). |
- // Filter them out. |
- concat: function(a, b) { |
- for (var i = 0, node; node = b[i]; i++) |
- if (node.tagName !== "!") a.push(node); |
- return a; |
- }, |
+var Sizzle = function(selector, context, results, seed) { |
+ results = results || []; |
+ var origContext = context = context || document; |
+ |
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) { |
+ return []; |
+ } |
+ |
+ if ( !selector || typeof selector !== "string" ) { |
+ return results; |
+ } |
+ |
+ var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), |
+ soFar = selector; |
+ |
+ while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { |
+ soFar = m[3]; |
+ |
+ parts.push( m[1] ); |
+ |
+ if ( m[2] ) { |
+ extra = m[3]; |
+ break; |
+ } |
+ } |
+ |
+ if ( parts.length > 1 && origPOS.exec( selector ) ) { |
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { |
+ set = posProcess( parts[0] + parts[1], context ); |
+ } else { |
+ set = Expr.relative[ parts[0] ] ? |
+ [ context ] : |
+ Sizzle( parts.shift(), context ); |
+ |
+ while ( parts.length ) { |
+ selector = parts.shift(); |
+ |
+ if ( Expr.relative[ selector ] ) |
+ selector += parts.shift(); |
+ |
+ set = posProcess( selector, set ); |
+ } |
+ } |
+ } else { |
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && |
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { |
+ var ret = Sizzle.find( parts.shift(), context, contextXML ); |
+ context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; |
+ } |
+ |
+ if ( context ) { |
+ var ret = seed ? |
+ { expr: parts.pop(), set: makeArray(seed) } : |
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); |
+ set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; |
+ |
+ if ( parts.length > 0 ) { |
+ checkSet = makeArray(set); |
+ } else { |
+ prune = false; |
+ } |
+ |
+ while ( parts.length ) { |
+ var cur = parts.pop(), pop = cur; |
+ |
+ if ( !Expr.relative[ cur ] ) { |
+ cur = ""; |
+ } else { |
+ pop = parts.pop(); |
+ } |
+ |
+ if ( pop == null ) { |
+ pop = context; |
+ } |
+ |
+ Expr.relative[ cur ]( checkSet, pop, contextXML ); |
+ } |
+ } else { |
+ checkSet = parts = []; |
+ } |
+ } |
+ |
+ if ( !checkSet ) { |
+ checkSet = set; |
+ } |
+ |
+ if ( !checkSet ) { |
+ throw "Syntax error, unrecognized expression: " + (cur || selector); |
+ } |
+ |
+ if ( toString.call(checkSet) === "[object Array]" ) { |
+ if ( !prune ) { |
+ results.push.apply( results, checkSet ); |
+ } else if ( context && context.nodeType === 1 ) { |
+ for ( var i = 0; checkSet[i] != null; i++ ) { |
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { |
+ results.push( set[i] ); |
+ } |
+ } |
+ } else { |
+ for ( var i = 0; checkSet[i] != null; i++ ) { |
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) { |
+ results.push( set[i] ); |
+ } |
+ } |
+ } |
+ } else { |
+ makeArray( checkSet, results ); |
+ } |
+ |
+ if ( extra ) { |
+ Sizzle( extra, origContext, results, seed ); |
+ Sizzle.uniqueSort( results ); |
+ } |
+ |
+ return results; |
+}; |
- // IE improperly serializes _countedByPrototype in (inner|outer)HTML. |
- unmark: function(nodes) { |
- for (var i = 0, node; node = nodes[i]; i++) |
- node.removeAttribute('_countedByPrototype'); |
- return nodes; |
- } |
- }); |
+Sizzle.uniqueSort = function(results){ |
+ if ( sortOrder ) { |
+ hasDuplicate = baseHasDuplicate; |
+ results.sort(sortOrder); |
+ |
+ if ( hasDuplicate ) { |
+ for ( var i = 1; i < results.length; i++ ) { |
+ if ( results[i] === results[i-1] ) { |
+ results.splice(i--, 1); |
+ } |
+ } |
+ } |
+ } |
+ |
+ return results; |
+}; |
+ |
+Sizzle.matches = function(expr, set){ |
+ return Sizzle(expr, null, null, set); |
+}; |
+ |
+Sizzle.find = function(expr, context, isXML){ |
+ var set, match; |
+ |
+ if ( !expr ) { |
+ return []; |
+ } |
+ |
+ for ( var i = 0, l = Expr.order.length; i < l; i++ ) { |
+ var type = Expr.order[i], match; |
+ |
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { |
+ var left = match[1]; |
+ match.splice(1,1); |
+ |
+ if ( left.substr( left.length - 1 ) !== "\\" ) { |
+ match[1] = (match[1] || "").replace(/\\/g, ""); |
+ set = Expr.find[ type ]( match, context, isXML ); |
+ if ( set != null ) { |
+ expr = expr.replace( Expr.match[ type ], "" ); |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ |
+ if ( !set ) { |
+ set = context.getElementsByTagName("*"); |
+ } |
+ |
+ return {set: set, expr: expr}; |
+}; |
+ |
+Sizzle.filter = function(expr, set, inplace, not){ |
+ var old = expr, result = [], curLoop = set, match, anyFound, |
+ isXMLFilter = set && set[0] && isXML(set[0]); |
+ |
+ while ( expr && set.length ) { |
+ for ( var type in Expr.filter ) { |
+ if ( (match = Expr.match[ type ].exec( expr )) != null ) { |
+ var filter = Expr.filter[ type ], found, item; |
+ anyFound = false; |
+ |
+ if ( curLoop == result ) { |
+ result = []; |
+ } |
+ |
+ if ( Expr.preFilter[ type ] ) { |
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); |
+ |
+ if ( !match ) { |
+ anyFound = found = true; |
+ } else if ( match === true ) { |
+ continue; |
+ } |
+ } |
+ |
+ if ( match ) { |
+ for ( var i = 0; (item = curLoop[i]) != null; i++ ) { |
+ if ( item ) { |
+ found = filter( item, match, i, curLoop ); |
+ var pass = not ^ !!found; |
+ |
+ if ( inplace && found != null ) { |
+ if ( pass ) { |
+ anyFound = true; |
+ } else { |
+ curLoop[i] = false; |
+ } |
+ } else if ( pass ) { |
+ result.push( item ); |
+ anyFound = true; |
+ } |
+ } |
+ } |
+ } |
+ |
+ if ( found !== undefined ) { |
+ if ( !inplace ) { |
+ curLoop = result; |
+ } |
+ |
+ expr = expr.replace( Expr.match[ type ], "" ); |
+ |
+ if ( !anyFound ) { |
+ return []; |
+ } |
+ |
+ break; |
+ } |
+ } |
+ } |
+ |
+ if ( expr == old ) { |
+ if ( anyFound == null ) { |
+ throw "Syntax error, unrecognized expression: " + expr; |
+ } else { |
+ break; |
+ } |
+ } |
+ |
+ old = expr; |
+ } |
+ |
+ return curLoop; |
+}; |
+ |
+var Expr = Sizzle.selectors = { |
+ order: [ "ID", "NAME", "TAG" ], |
+ match: { |
+ ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, |
+ CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, |
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, |
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, |
+ TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, |
+ CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, |
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, |
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ |
+ }, |
+ leftMatch: {}, |
+ attrMap: { |
+ "class": "className", |
+ "for": "htmlFor" |
+ }, |
+ attrHandle: { |
+ href: function(elem){ |
+ return elem.getAttribute("href"); |
+ } |
+ }, |
+ relative: { |
+ "+": function(checkSet, part, isXML){ |
+ var isPartStr = typeof part === "string", |
+ isTag = isPartStr && !/\W/.test(part), |
+ isPartStrNotTag = isPartStr && !isTag; |
+ |
+ if ( isTag && !isXML ) { |
+ part = part.toUpperCase(); |
+ } |
+ |
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { |
+ if ( (elem = checkSet[i]) ) { |
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} |
+ |
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? |
+ elem || false : |
+ elem === part; |
+ } |
+ } |
+ |
+ if ( isPartStrNotTag ) { |
+ Sizzle.filter( part, checkSet, true ); |
+ } |
+ }, |
+ ">": function(checkSet, part, isXML){ |
+ var isPartStr = typeof part === "string"; |
+ |
+ if ( isPartStr && !/\W/.test(part) ) { |
+ part = isXML ? part : part.toUpperCase(); |
+ |
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) { |
+ var elem = checkSet[i]; |
+ if ( elem ) { |
+ var parent = elem.parentNode; |
+ checkSet[i] = parent.nodeName === part ? parent : false; |
+ } |
+ } |
+ } else { |
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) { |
+ var elem = checkSet[i]; |
+ if ( elem ) { |
+ checkSet[i] = isPartStr ? |
+ elem.parentNode : |
+ elem.parentNode === part; |
+ } |
+ } |
+ |
+ if ( isPartStr ) { |
+ Sizzle.filter( part, checkSet, true ); |
+ } |
+ } |
+ }, |
+ "": function(checkSet, part, isXML){ |
+ var doneName = done++, checkFn = dirCheck; |
+ |
+ if ( !/\W/.test(part) ) { |
+ var nodeCheck = part = isXML ? part : part.toUpperCase(); |
+ checkFn = dirNodeCheck; |
+ } |
+ |
+ checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); |
+ }, |
+ "~": function(checkSet, part, isXML){ |
+ var doneName = done++, checkFn = dirCheck; |
+ |
+ if ( typeof part === "string" && !/\W/.test(part) ) { |
+ var nodeCheck = part = isXML ? part : part.toUpperCase(); |
+ checkFn = dirNodeCheck; |
+ } |
+ |
+ checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); |
+ } |
+ }, |
+ find: { |
+ ID: function(match, context, isXML){ |
+ if ( typeof context.getElementById !== "undefined" && !isXML ) { |
+ var m = context.getElementById(match[1]); |
+ return m ? [m] : []; |
+ } |
+ }, |
+ NAME: function(match, context, isXML){ |
+ if ( typeof context.getElementsByName !== "undefined" ) { |
+ var ret = [], results = context.getElementsByName(match[1]); |
+ |
+ for ( var i = 0, l = results.length; i < l; i++ ) { |
+ if ( results[i].getAttribute("name") === match[1] ) { |
+ ret.push( results[i] ); |
+ } |
+ } |
+ |
+ return ret.length === 0 ? null : ret; |
+ } |
+ }, |
+ TAG: function(match, context){ |
+ return context.getElementsByTagName(match[1]); |
+ } |
+ }, |
+ preFilter: { |
+ CLASS: function(match, curLoop, inplace, result, not, isXML){ |
+ match = " " + match[1].replace(/\\/g, "") + " "; |
+ |
+ if ( isXML ) { |
+ return match; |
+ } |
+ |
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { |
+ if ( elem ) { |
+ if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { |
+ if ( !inplace ) |
+ result.push( elem ); |
+ } else if ( inplace ) { |
+ curLoop[i] = false; |
+ } |
+ } |
+ } |
+ |
+ return false; |
+ }, |
+ ID: function(match){ |
+ return match[1].replace(/\\/g, ""); |
+ }, |
+ TAG: function(match, curLoop){ |
+ for ( var i = 0; curLoop[i] === false; i++ ){} |
+ return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); |
+ }, |
+ CHILD: function(match){ |
+ if ( match[1] == "nth" ) { |
+ var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( |
+ match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || |
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); |
+ |
+ match[2] = (test[1] + (test[2] || 1)) - 0; |
+ match[3] = test[3] - 0; |
+ } |
+ |
+ match[0] = done++; |
+ |
+ return match; |
+ }, |
+ ATTR: function(match, curLoop, inplace, result, not, isXML){ |
+ var name = match[1].replace(/\\/g, ""); |
+ |
+ if ( !isXML && Expr.attrMap[name] ) { |
+ match[1] = Expr.attrMap[name]; |
+ } |
+ |
+ if ( match[2] === "~=" ) { |
+ match[4] = " " + match[4] + " "; |
+ } |
+ |
+ return match; |
+ }, |
+ PSEUDO: function(match, curLoop, inplace, result, not){ |
+ if ( match[1] === "not" ) { |
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { |
+ match[3] = Sizzle(match[3], null, null, curLoop); |
+ } else { |
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); |
+ if ( !inplace ) { |
+ result.push.apply( result, ret ); |
+ } |
+ return false; |
+ } |
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { |
+ return true; |
+ } |
+ |
+ return match; |
+ }, |
+ POS: function(match){ |
+ match.unshift( true ); |
+ return match; |
+ } |
+ }, |
+ filters: { |
+ enabled: function(elem){ |
+ return elem.disabled === false && elem.type !== "hidden"; |
+ }, |
+ disabled: function(elem){ |
+ return elem.disabled === true; |
+ }, |
+ checked: function(elem){ |
+ return elem.checked === true; |
+ }, |
+ selected: function(elem){ |
+ elem.parentNode.selectedIndex; |
+ return elem.selected === true; |
+ }, |
+ parent: function(elem){ |
+ return !!elem.firstChild; |
+ }, |
+ empty: function(elem){ |
+ return !elem.firstChild; |
+ }, |
+ has: function(elem, i, match){ |
+ return !!Sizzle( match[3], elem ).length; |
+ }, |
+ header: function(elem){ |
+ return /h\d/i.test( elem.nodeName ); |
+ }, |
+ text: function(elem){ |
+ return "text" === elem.type; |
+ }, |
+ radio: function(elem){ |
+ return "radio" === elem.type; |
+ }, |
+ checkbox: function(elem){ |
+ return "checkbox" === elem.type; |
+ }, |
+ file: function(elem){ |
+ return "file" === elem.type; |
+ }, |
+ password: function(elem){ |
+ return "password" === elem.type; |
+ }, |
+ submit: function(elem){ |
+ return "submit" === elem.type; |
+ }, |
+ image: function(elem){ |
+ return "image" === elem.type; |
+ }, |
+ reset: function(elem){ |
+ return "reset" === elem.type; |
+ }, |
+ button: function(elem){ |
+ return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; |
+ }, |
+ input: function(elem){ |
+ return /input|select|textarea|button/i.test(elem.nodeName); |
+ } |
+ }, |
+ setFilters: { |
+ first: function(elem, i){ |
+ return i === 0; |
+ }, |
+ last: function(elem, i, match, array){ |
+ return i === array.length - 1; |
+ }, |
+ even: function(elem, i){ |
+ return i % 2 === 0; |
+ }, |
+ odd: function(elem, i){ |
+ return i % 2 === 1; |
+ }, |
+ lt: function(elem, i, match){ |
+ return i < match[3] - 0; |
+ }, |
+ gt: function(elem, i, match){ |
+ return i > match[3] - 0; |
+ }, |
+ nth: function(elem, i, match){ |
+ return match[3] - 0 == i; |
+ }, |
+ eq: function(elem, i, match){ |
+ return match[3] - 0 == i; |
+ } |
+ }, |
+ filter: { |
+ PSEUDO: function(elem, match, i, array){ |
+ var name = match[1], filter = Expr.filters[ name ]; |
+ |
+ if ( filter ) { |
+ return filter( elem, i, match, array ); |
+ } else if ( name === "contains" ) { |
+ return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; |
+ } else if ( name === "not" ) { |
+ var not = match[3]; |
+ |
+ for ( var i = 0, l = not.length; i < l; i++ ) { |
+ if ( not[i] === elem ) { |
+ return false; |
+ } |
+ } |
+ |
+ return true; |
+ } |
+ }, |
+ CHILD: function(elem, match){ |
+ var type = match[1], node = elem; |
+ switch (type) { |
+ case 'only': |
+ case 'first': |
+ while ( (node = node.previousSibling) ) { |
+ if ( node.nodeType === 1 ) return false; |
+ } |
+ if ( type == 'first') return true; |
+ node = elem; |
+ case 'last': |
+ while ( (node = node.nextSibling) ) { |
+ if ( node.nodeType === 1 ) return false; |
+ } |
+ return true; |
+ case 'nth': |
+ var first = match[2], last = match[3]; |
+ |
+ if ( first == 1 && last == 0 ) { |
+ return true; |
+ } |
+ |
+ var doneName = match[0], |
+ parent = elem.parentNode; |
+ |
+ if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { |
+ var count = 0; |
+ for ( node = parent.firstChild; node; node = node.nextSibling ) { |
+ if ( node.nodeType === 1 ) { |
+ node.nodeIndex = ++count; |
+ } |
+ } |
+ parent.sizcache = doneName; |
+ } |
+ |
+ var diff = elem.nodeIndex - last; |
+ if ( first == 0 ) { |
+ return diff == 0; |
+ } else { |
+ return ( diff % first == 0 && diff / first >= 0 ); |
+ } |
+ } |
+ }, |
+ ID: function(elem, match){ |
+ return elem.nodeType === 1 && elem.getAttribute("id") === match; |
+ }, |
+ TAG: function(elem, match){ |
+ return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; |
+ }, |
+ CLASS: function(elem, match){ |
+ return (" " + (elem.className || elem.getAttribute("class")) + " ") |
+ .indexOf( match ) > -1; |
+ }, |
+ ATTR: function(elem, match){ |
+ var name = match[1], |
+ result = Expr.attrHandle[ name ] ? |
+ Expr.attrHandle[ name ]( elem ) : |
+ elem[ name ] != null ? |
+ elem[ name ] : |
+ elem.getAttribute( name ), |
+ value = result + "", |
+ type = match[2], |
+ check = match[4]; |
+ |
+ return result == null ? |
+ type === "!=" : |
+ type === "=" ? |
+ value === check : |
+ type === "*=" ? |
+ value.indexOf(check) >= 0 : |
+ type === "~=" ? |
+ (" " + value + " ").indexOf(check) >= 0 : |
+ !check ? |
+ value && result !== false : |
+ type === "!=" ? |
+ value != check : |
+ type === "^=" ? |
+ value.indexOf(check) === 0 : |
+ type === "$=" ? |
+ value.substr(value.length - check.length) === check : |
+ type === "|=" ? |
+ value === check || value.substr(0, check.length + 1) === check + "-" : |
+ false; |
+ }, |
+ POS: function(elem, match, i, array){ |
+ var name = match[2], filter = Expr.setFilters[ name ]; |
+ |
+ if ( filter ) { |
+ return filter( elem, i, match, array ); |
+ } |
+ } |
+ } |
+}; |
+ |
+var origPOS = Expr.match.POS; |
+ |
+for ( var type in Expr.match ) { |
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); |
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); |
+} |
+ |
+var makeArray = function(array, results) { |
+ array = Array.prototype.slice.call( array, 0 ); |
+ |
+ if ( results ) { |
+ results.push.apply( results, array ); |
+ return results; |
+ } |
+ |
+ return array; |
+}; |
+ |
+try { |
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 ); |
+ |
+} catch(e){ |
+ makeArray = function(array, results) { |
+ var ret = results || []; |
+ |
+ if ( toString.call(array) === "[object Array]" ) { |
+ Array.prototype.push.apply( ret, array ); |
+ } else { |
+ if ( typeof array.length === "number" ) { |
+ for ( var i = 0, l = array.length; i < l; i++ ) { |
+ ret.push( array[i] ); |
+ } |
+ } else { |
+ for ( var i = 0; array[i]; i++ ) { |
+ ret.push( array[i] ); |
+ } |
+ } |
+ } |
+ |
+ return ret; |
+ }; |
} |
-function $$() { |
- return Selector.findChildElements(document, $A(arguments)); |
+var sortOrder; |
+ |
+if ( document.documentElement.compareDocumentPosition ) { |
+ sortOrder = function( a, b ) { |
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { |
+ if ( a == b ) { |
+ hasDuplicate = true; |
+ } |
+ return 0; |
+ } |
+ |
+ var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; |
+ if ( ret === 0 ) { |
+ hasDuplicate = true; |
+ } |
+ return ret; |
+ }; |
+} else if ( "sourceIndex" in document.documentElement ) { |
+ sortOrder = function( a, b ) { |
+ if ( !a.sourceIndex || !b.sourceIndex ) { |
+ if ( a == b ) { |
+ hasDuplicate = true; |
+ } |
+ return 0; |
+ } |
+ |
+ var ret = a.sourceIndex - b.sourceIndex; |
+ if ( ret === 0 ) { |
+ hasDuplicate = true; |
+ } |
+ return ret; |
+ }; |
+} else if ( document.createRange ) { |
+ sortOrder = function( a, b ) { |
+ if ( !a.ownerDocument || !b.ownerDocument ) { |
+ if ( a == b ) { |
+ hasDuplicate = true; |
+ } |
+ return 0; |
+ } |
+ |
+ var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); |
+ aRange.setStart(a, 0); |
+ aRange.setEnd(a, 0); |
+ bRange.setStart(b, 0); |
+ bRange.setEnd(b, 0); |
+ var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); |
+ if ( ret === 0 ) { |
+ hasDuplicate = true; |
+ } |
+ return ret; |
+ }; |
} |
+ |
+(function(){ |
+ var form = document.createElement("div"), |
+ id = "script" + (new Date).getTime(); |
+ form.innerHTML = "<a name='" + id + "'/>"; |
+ |
+ var root = document.documentElement; |
+ root.insertBefore( form, root.firstChild ); |
+ |
+ if ( !!document.getElementById( id ) ) { |
+ Expr.find.ID = function(match, context, isXML){ |
+ if ( typeof context.getElementById !== "undefined" && !isXML ) { |
+ var m = context.getElementById(match[1]); |
+ return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; |
+ } |
+ }; |
+ |
+ Expr.filter.ID = function(elem, match){ |
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); |
+ return elem.nodeType === 1 && node && node.nodeValue === match; |
+ }; |
+ } |
+ |
+ root.removeChild( form ); |
+ root = form = null; // release memory in IE |
+})(); |
+ |
+(function(){ |
+ |
+ var div = document.createElement("div"); |
+ div.appendChild( document.createComment("") ); |
+ |
+ if ( div.getElementsByTagName("*").length > 0 ) { |
+ Expr.find.TAG = function(match, context){ |
+ var results = context.getElementsByTagName(match[1]); |
+ |
+ if ( match[1] === "*" ) { |
+ var tmp = []; |
+ |
+ for ( var i = 0; results[i]; i++ ) { |
+ if ( results[i].nodeType === 1 ) { |
+ tmp.push( results[i] ); |
+ } |
+ } |
+ |
+ results = tmp; |
+ } |
+ |
+ return results; |
+ }; |
+ } |
+ |
+ div.innerHTML = "<a href='#'></a>"; |
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && |
+ div.firstChild.getAttribute("href") !== "#" ) { |
+ Expr.attrHandle.href = function(elem){ |
+ return elem.getAttribute("href", 2); |
+ }; |
+ } |
+ |
+ div = null; // release memory in IE |
+})(); |
+ |
+if ( document.querySelectorAll ) (function(){ |
+ var oldSizzle = Sizzle, div = document.createElement("div"); |
+ div.innerHTML = "<p class='TEST'></p>"; |
+ |
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { |
+ return; |
+ } |
+ |
+ Sizzle = function(query, context, extra, seed){ |
+ context = context || document; |
+ |
+ if ( !seed && context.nodeType === 9 && !isXML(context) ) { |
+ try { |
+ return makeArray( context.querySelectorAll(query), extra ); |
+ } catch(e){} |
+ } |
+ |
+ return oldSizzle(query, context, extra, seed); |
+ }; |
+ |
+ for ( var prop in oldSizzle ) { |
+ Sizzle[ prop ] = oldSizzle[ prop ]; |
+ } |
+ |
+ div = null; // release memory in IE |
+})(); |
+ |
+if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ |
+ var div = document.createElement("div"); |
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>"; |
+ |
+ if ( div.getElementsByClassName("e").length === 0 ) |
+ return; |
+ |
+ div.lastChild.className = "e"; |
+ |
+ if ( div.getElementsByClassName("e").length === 1 ) |
+ return; |
+ |
+ Expr.order.splice(1, 0, "CLASS"); |
+ Expr.find.CLASS = function(match, context, isXML) { |
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { |
+ return context.getElementsByClassName(match[1]); |
+ } |
+ }; |
+ |
+ div = null; // release memory in IE |
+})(); |
+ |
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { |
+ var sibDir = dir == "previousSibling" && !isXML; |
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) { |
+ var elem = checkSet[i]; |
+ if ( elem ) { |
+ if ( sibDir && elem.nodeType === 1 ){ |
+ elem.sizcache = doneName; |
+ elem.sizset = i; |
+ } |
+ elem = elem[dir]; |
+ var match = false; |
+ |
+ while ( elem ) { |
+ if ( elem.sizcache === doneName ) { |
+ match = checkSet[elem.sizset]; |
+ break; |
+ } |
+ |
+ if ( elem.nodeType === 1 && !isXML ){ |
+ elem.sizcache = doneName; |
+ elem.sizset = i; |
+ } |
+ |
+ if ( elem.nodeName === cur ) { |
+ match = elem; |
+ break; |
+ } |
+ |
+ elem = elem[dir]; |
+ } |
+ |
+ checkSet[i] = match; |
+ } |
+ } |
+} |
+ |
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { |
+ var sibDir = dir == "previousSibling" && !isXML; |
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) { |
+ var elem = checkSet[i]; |
+ if ( elem ) { |
+ if ( sibDir && elem.nodeType === 1 ) { |
+ elem.sizcache = doneName; |
+ elem.sizset = i; |
+ } |
+ elem = elem[dir]; |
+ var match = false; |
+ |
+ while ( elem ) { |
+ if ( elem.sizcache === doneName ) { |
+ match = checkSet[elem.sizset]; |
+ break; |
+ } |
+ |
+ if ( elem.nodeType === 1 ) { |
+ if ( !isXML ) { |
+ elem.sizcache = doneName; |
+ elem.sizset = i; |
+ } |
+ if ( typeof cur !== "string" ) { |
+ if ( elem === cur ) { |
+ match = true; |
+ break; |
+ } |
+ |
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { |
+ match = elem; |
+ break; |
+ } |
+ } |
+ |
+ elem = elem[dir]; |
+ } |
+ |
+ checkSet[i] = match; |
+ } |
+ } |
+} |
+ |
+var contains = document.compareDocumentPosition ? function(a, b){ |
+ return a.compareDocumentPosition(b) & 16; |
+} : function(a, b){ |
+ return a !== b && (a.contains ? a.contains(b) : true); |
+}; |
+ |
+var isXML = function(elem){ |
+ return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || |
+ !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; |
+}; |
+ |
+var posProcess = function(selector, context){ |
+ var tmpSet = [], later = "", match, |
+ root = context.nodeType ? [context] : context; |
+ |
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) { |
+ later += match[0]; |
+ selector = selector.replace( Expr.match.PSEUDO, "" ); |
+ } |
+ |
+ selector = Expr.relative[selector] ? selector + "*" : selector; |
+ |
+ for ( var i = 0, l = root.length; i < l; i++ ) { |
+ Sizzle( selector, root[i], tmpSet ); |
+ } |
+ |
+ return Sizzle.filter( later, tmpSet ); |
+}; |
+ |
+ |
+window.Sizzle = Sizzle; |
+ |
+})(); |
+ |
+;(function(engine) { |
+ var extendElements = Prototype.Selector.extendElements; |
+ |
+ function select(selector, scope) { |
+ return extendElements(engine(selector, scope || document)); |
+ } |
+ |
+ function match(element, selector) { |
+ return engine.matches(selector, [element]).length == 1; |
+ } |
+ |
+ Prototype.Selector.engine = engine; |
+ Prototype.Selector.select = select; |
+ Prototype.Selector.match = match; |
+})(Sizzle); |
+ |
+window.Sizzle = Prototype._original_property; |
+delete Prototype._original_property; |
+ |
var Form = { |
reset: function(form) { |
- $(form).reset(); |
+ form = $(form); |
+ form.reset(); |
return form; |
}, |
serializeElements: function(elements, options) { |
if (typeof options != 'object') options = { hash: !!options }; |
else if (Object.isUndefined(options.hash)) options.hash = true; |
- var key, value, submitted = false, submit = options.submit; |
+ var key, value, submitted = false, submit = options.submit, accumulator, initial; |
+ |
+ if (options.hash) { |
+ initial = {}; |
+ accumulator = function(result, key, value) { |
+ if (key in result) { |
+ if (!Object.isArray(result[key])) result[key] = [result[key]]; |
+ result[key].push(value); |
+ } else result[key] = value; |
+ return result; |
+ }; |
+ } else { |
+ initial = ''; |
+ accumulator = function(result, key, value) { |
+ return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value); |
+ } |
+ } |
- var data = elements.inject({ }, function(result, element) { |
+ return elements.inject(initial, function(result, element) { |
if (!element.disabled && element.name) { |
key = element.name; value = $(element).getValue(); |
if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && |
submit !== false && (!submit || key == submit) && (submitted = true)))) { |
- if (key in result) { |
- // a key is already present; construct an array of values |
- if (!Object.isArray(result[key])) result[key] = [result[key]]; |
- result[key].push(value); |
- } |
- else result[key] = value; |
+ result = accumulator(result, key, value); |
} |
} |
return result; |
}); |
- |
- return options.hash ? data : Object.toQueryString(data); |
} |
}; |
@@ -3479,14 +5006,19 @@ Form.Methods = { |
return Form.serializeElements(Form.getElements(form), options); |
}, |
- getElements: function(form) { |
- return $A($(form).getElementsByTagName('*')).inject([], |
- function(elements, child) { |
- if (Form.Element.Serializers[child.tagName.toLowerCase()]) |
- elements.push(Element.extend(child)); |
- return elements; |
- } |
- ); |
+ getElements: function(form) { |
+ var elements = $(form).getElementsByTagName('*'), |
+ element, |
+ arr = [ ], |
+ serializers = Form.Element.Serializers; |
+ for (var i = 0; element = elements[i]; i++) { |
+ arr.push(element); |
+ } |
+ return arr.inject([], function(elements, child) { |
+ if (serializers[child.tagName.toLowerCase()]) |
+ elements.push(Element.extend(child)); |
+ return elements; |
+ }) |
}, |
getInputs: function(form, typeName, name) { |
@@ -3526,13 +5058,14 @@ Form.Methods = { |
}).sortBy(function(element) { return element.tabIndex }).first(); |
return firstByIndex ? firstByIndex : elements.find(function(element) { |
- return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); |
+ return /^(?:input|select|textarea)$/i.test(element.tagName); |
}); |
}, |
focusFirstElement: function(form) { |
form = $(form); |
- form.findFirstElement().activate(); |
+ var element = form.findFirstElement(); |
+ if (element) element.activate(); |
return form; |
}, |
@@ -3557,6 +5090,7 @@ Form.Methods = { |
/*--------------------------------------------------------------------------*/ |
+ |
Form.Element = { |
focus: function(element) { |
$(element).focus(); |
@@ -3570,6 +5104,7 @@ Form.Element = { |
}; |
Form.Element.Methods = { |
+ |
serialize: function(element) { |
element = $(element); |
if (!element.disabled && element.name) { |
@@ -3610,7 +5145,7 @@ Form.Element.Methods = { |
try { |
element.focus(); |
if (element.select && (element.tagName.toLowerCase() != 'input' || |
- !['button', 'reset', 'submit'].include(element.type))) |
+ !(/^(?:button|reset|submit)$/i.test(element.type)))) |
element.select(); |
} catch (e) { } |
return element; |
@@ -3632,75 +5167,86 @@ Form.Element.Methods = { |
/*--------------------------------------------------------------------------*/ |
var Field = Form.Element; |
+ |
var $F = Form.Element.Methods.getValue; |
/*--------------------------------------------------------------------------*/ |
-Form.Element.Serializers = { |
- input: function(element, value) { |
+Form.Element.Serializers = (function() { |
+ function input(element, value) { |
switch (element.type.toLowerCase()) { |
case 'checkbox': |
case 'radio': |
- return Form.Element.Serializers.inputSelector(element, value); |
+ return inputSelector(element, value); |
default: |
- return Form.Element.Serializers.textarea(element, value); |
+ return valueSelector(element, value); |
} |
- }, |
+ } |
- inputSelector: function(element, value) { |
- if (Object.isUndefined(value)) return element.checked ? element.value : null; |
+ function inputSelector(element, value) { |
+ if (Object.isUndefined(value)) |
+ return element.checked ? element.value : null; |
else element.checked = !!value; |
- }, |
+ } |
- textarea: function(element, value) { |
+ function valueSelector(element, value) { |
if (Object.isUndefined(value)) return element.value; |
else element.value = value; |
- }, |
+ } |
- select: function(element, value) { |
+ function select(element, value) { |
if (Object.isUndefined(value)) |
- return this[element.type == 'select-one' ? |
- 'selectOne' : 'selectMany'](element); |
- else { |
- var opt, currentValue, single = !Object.isArray(value); |
- for (var i = 0, length = element.length; i < length; i++) { |
- opt = element.options[i]; |
- currentValue = this.optionValue(opt); |
- if (single) { |
- if (currentValue == value) { |
- opt.selected = true; |
- return; |
- } |
+ return (element.type === 'select-one' ? selectOne : selectMany)(element); |
+ |
+ var opt, currentValue, single = !Object.isArray(value); |
+ for (var i = 0, length = element.length; i < length; i++) { |
+ opt = element.options[i]; |
+ currentValue = this.optionValue(opt); |
+ if (single) { |
+ if (currentValue == value) { |
+ opt.selected = true; |
+ return; |
} |
- else opt.selected = value.include(currentValue); |
} |
+ else opt.selected = value.include(currentValue); |
} |
- }, |
+ } |
- selectOne: function(element) { |
+ function selectOne(element) { |
var index = element.selectedIndex; |
- return index >= 0 ? this.optionValue(element.options[index]) : null; |
- }, |
+ return index >= 0 ? optionValue(element.options[index]) : null; |
+ } |
- selectMany: function(element) { |
+ function selectMany(element) { |
var values, length = element.length; |
if (!length) return null; |
for (var i = 0, values = []; i < length; i++) { |
var opt = element.options[i]; |
- if (opt.selected) values.push(this.optionValue(opt)); |
+ if (opt.selected) values.push(optionValue(opt)); |
} |
return values; |
- }, |
+ } |
- optionValue: function(opt) { |
- // extend element because hasAttribute may not be native |
- return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; |
+ function optionValue(opt) { |
+ return Element.hasAttribute(opt, 'value') ? opt.value : opt.text; |
} |
-}; |
+ |
+ return { |
+ input: input, |
+ inputSelector: inputSelector, |
+ textarea: valueSelector, |
+ select: select, |
+ selectOne: selectOne, |
+ selectMany: selectMany, |
+ optionValue: optionValue, |
+ button: valueSelector |
+ }; |
+})(); |
/*--------------------------------------------------------------------------*/ |
+ |
Abstract.TimedObserver = Class.create(PeriodicalExecuter, { |
initialize: function($super, element, frequency, callback) { |
$super(callback, frequency); |
@@ -3782,354 +5328,527 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { |
return Form.serialize(this.element); |
} |
}); |
-if (!window.Event) var Event = { }; |
- |
-Object.extend(Event, { |
- KEY_BACKSPACE: 8, |
- KEY_TAB: 9, |
- KEY_RETURN: 13, |
- KEY_ESC: 27, |
- KEY_LEFT: 37, |
- KEY_UP: 38, |
- KEY_RIGHT: 39, |
- KEY_DOWN: 40, |
- KEY_DELETE: 46, |
- KEY_HOME: 36, |
- KEY_END: 35, |
- KEY_PAGEUP: 33, |
- KEY_PAGEDOWN: 34, |
- KEY_INSERT: 45, |
- |
- cache: { }, |
- |
- relatedTarget: function(event) { |
- var element; |
- switch(event.type) { |
- case 'mouseover': element = event.fromElement; break; |
- case 'mouseout': element = event.toElement; break; |
- default: return null; |
- } |
- return Element.extend(element); |
+(function() { |
+ |
+ var Event = { |
+ KEY_BACKSPACE: 8, |
+ KEY_TAB: 9, |
+ KEY_RETURN: 13, |
+ KEY_ESC: 27, |
+ KEY_LEFT: 37, |
+ KEY_UP: 38, |
+ KEY_RIGHT: 39, |
+ KEY_DOWN: 40, |
+ KEY_DELETE: 46, |
+ KEY_HOME: 36, |
+ KEY_END: 35, |
+ KEY_PAGEUP: 33, |
+ KEY_PAGEDOWN: 34, |
+ KEY_INSERT: 45, |
+ |
+ cache: {} |
+ }; |
+ |
+ var docEl = document.documentElement; |
+ var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl |
+ && 'onmouseleave' in docEl; |
+ |
+ |
+ |
+ var isIELegacyEvent = function(event) { return false; }; |
+ |
+ if (window.attachEvent) { |
+ if (window.addEventListener) { |
+ isIELegacyEvent = function(event) { |
+ return !(event instanceof window.Event); |
+ }; |
+ } else { |
+ isIELegacyEvent = function(event) { return true; }; |
+ } |
} |
-}); |
-Event.Methods = (function() { |
- var isButton; |
+ var _isButton; |
- if (Prototype.Browser.IE) { |
- var buttonMap = { 0: 1, 1: 4, 2: 2 }; |
- isButton = function(event, code) { |
- return event.button == buttonMap[code]; |
- }; |
+ function _isButtonForDOMEvents(event, code) { |
+ return event.which ? (event.which === code + 1) : (event.button === code); |
+ } |
- } else if (Prototype.Browser.WebKit) { |
- isButton = function(event, code) { |
- switch (code) { |
- case 0: return event.which == 1 && !event.metaKey; |
- case 1: return event.which == 1 && event.metaKey; |
- default: return false; |
- } |
- }; |
+ var legacyButtonMap = { 0: 1, 1: 4, 2: 2 }; |
+ function _isButtonForLegacyEvents(event, code) { |
+ return event.button === legacyButtonMap[code]; |
+ } |
- } else { |
- isButton = function(event, code) { |
- return event.which ? (event.which === code + 1) : (event.button === code); |
- }; |
+ function _isButtonForWebKit(event, code) { |
+ switch (code) { |
+ case 0: return event.which == 1 && !event.metaKey; |
+ case 1: return event.which == 2 || (event.which == 1 && event.metaKey); |
+ case 2: return event.which == 3; |
+ default: return false; |
+ } |
} |
- return { |
- isLeftClick: function(event) { return isButton(event, 0) }, |
- isMiddleClick: function(event) { return isButton(event, 1) }, |
- isRightClick: function(event) { return isButton(event, 2) }, |
- |
- element: function(event) { |
- event = Event.extend(event); |
- |
- var node = event.target, |
- type = event.type, |
- currentTarget = event.currentTarget; |
- |
- if (currentTarget && currentTarget.tagName) { |
- // Firefox screws up the "click" event when moving between radio buttons |
- // via arrow keys. It also screws up the "load" and "error" events on images, |
- // reporting the document as the target instead of the original image. |
- if (type === 'load' || type === 'error' || |
- (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' |
- && currentTarget.type === 'radio')) |
- node = currentTarget; |
+ if (window.attachEvent) { |
+ if (!window.addEventListener) { |
+ _isButton = _isButtonForLegacyEvents; |
+ } else { |
+ _isButton = function(event, code) { |
+ return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) : |
+ _isButtonForDOMEvents(event, code); |
} |
- if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; |
- return Element.extend(node); |
- }, |
+ } |
+ } else if (Prototype.Browser.WebKit) { |
+ _isButton = _isButtonForWebKit; |
+ } else { |
+ _isButton = _isButtonForDOMEvents; |
+ } |
- findElement: function(event, expression) { |
- var element = Event.element(event); |
- if (!expression) return element; |
- var elements = [element].concat(element.ancestors()); |
- return Selector.findElement(elements, expression, 0); |
- }, |
+ function isLeftClick(event) { return _isButton(event, 0) } |
- pointer: function(event) { |
- var docElement = document.documentElement, |
- body = document.body || { scrollLeft: 0, scrollTop: 0 }; |
- return { |
- x: event.pageX || (event.clientX + |
- (docElement.scrollLeft || body.scrollLeft) - |
- (docElement.clientLeft || 0)), |
- y: event.pageY || (event.clientY + |
- (docElement.scrollTop || body.scrollTop) - |
- (docElement.clientTop || 0)) |
- }; |
- }, |
+ function isMiddleClick(event) { return _isButton(event, 1) } |
+ |
+ function isRightClick(event) { return _isButton(event, 2) } |
+ |
+ function element(event) { |
+ event = Event.extend(event); |
+ |
+ var node = event.target, type = event.type, |
+ currentTarget = event.currentTarget; |
- pointerX: function(event) { return Event.pointer(event).x }, |
- pointerY: function(event) { return Event.pointer(event).y }, |
+ if (currentTarget && currentTarget.tagName) { |
+ if (type === 'load' || type === 'error' || |
+ (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' |
+ && currentTarget.type === 'radio')) |
+ node = currentTarget; |
+ } |
+ |
+ if (node.nodeType == Node.TEXT_NODE) |
+ node = node.parentNode; |
+ |
+ return Element.extend(node); |
+ } |
- stop: function(event) { |
- Event.extend(event); |
- event.preventDefault(); |
- event.stopPropagation(); |
- event.stopped = true; |
+ function findElement(event, expression) { |
+ var element = Event.element(event); |
+ |
+ if (!expression) return element; |
+ while (element) { |
+ if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { |
+ return Element.extend(element); |
+ } |
+ element = element.parentNode; |
} |
+ } |
+ |
+ function pointer(event) { |
+ return { x: pointerX(event), y: pointerY(event) }; |
+ } |
+ |
+ function pointerX(event) { |
+ var docElement = document.documentElement, |
+ body = document.body || { scrollLeft: 0 }; |
+ |
+ return event.pageX || (event.clientX + |
+ (docElement.scrollLeft || body.scrollLeft) - |
+ (docElement.clientLeft || 0)); |
+ } |
+ |
+ function pointerY(event) { |
+ var docElement = document.documentElement, |
+ body = document.body || { scrollTop: 0 }; |
+ |
+ return event.pageY || (event.clientY + |
+ (docElement.scrollTop || body.scrollTop) - |
+ (docElement.clientTop || 0)); |
+ } |
+ |
+ |
+ function stop(event) { |
+ Event.extend(event); |
+ event.preventDefault(); |
+ event.stopPropagation(); |
+ |
+ event.stopped = true; |
+ } |
+ |
+ |
+ Event.Methods = { |
+ isLeftClick: isLeftClick, |
+ isMiddleClick: isMiddleClick, |
+ isRightClick: isRightClick, |
+ |
+ element: element, |
+ findElement: findElement, |
+ |
+ pointer: pointer, |
+ pointerX: pointerX, |
+ pointerY: pointerY, |
+ |
+ stop: stop |
}; |
-})(); |
-Event.extend = (function() { |
var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { |
m[name] = Event.Methods[name].methodize(); |
return m; |
}); |
- if (Prototype.Browser.IE) { |
- Object.extend(methods, { |
+ if (window.attachEvent) { |
+ function _relatedTarget(event) { |
+ var element; |
+ switch (event.type) { |
+ case 'mouseover': |
+ case 'mouseenter': |
+ element = event.fromElement; |
+ break; |
+ case 'mouseout': |
+ case 'mouseleave': |
+ element = event.toElement; |
+ break; |
+ default: |
+ return null; |
+ } |
+ return Element.extend(element); |
+ } |
+ |
+ var additionalMethods = { |
stopPropagation: function() { this.cancelBubble = true }, |
preventDefault: function() { this.returnValue = false }, |
- inspect: function() { return "[object Event]" } |
- }); |
+ inspect: function() { return '[object Event]' } |
+ }; |
- return function(event) { |
+ Event.extend = function(event, element) { |
if (!event) return false; |
- if (event._extendedByPrototype) return event; |
+ if (!isIELegacyEvent(event)) return event; |
+ |
+ if (event._extendedByPrototype) return event; |
event._extendedByPrototype = Prototype.emptyFunction; |
+ |
var pointer = Event.pointer(event); |
+ |
Object.extend(event, { |
- target: event.srcElement, |
- relatedTarget: Event.relatedTarget(event), |
+ target: event.srcElement || element, |
+ relatedTarget: _relatedTarget(event), |
pageX: pointer.x, |
pageY: pointer.y |
}); |
- return Object.extend(event, methods); |
- }; |
+ Object.extend(event, methods); |
+ Object.extend(event, additionalMethods); |
+ |
+ return event; |
+ }; |
} else { |
- Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; |
- Object.extend(Event.prototype, methods); |
- return Prototype.K; |
+ Event.extend = Prototype.K; |
} |
-})(); |
- |
-Object.extend(Event, (function() { |
- var cache = Event.cache; |
- function getEventID(element) { |
- if (element._prototypeEventID) return element._prototypeEventID[0]; |
- arguments.callee.id = arguments.callee.id || 1; |
- return element._prototypeEventID = [++arguments.callee.id]; |
+ if (window.addEventListener) { |
+ Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; |
+ Object.extend(Event.prototype, methods); |
} |
- function getDOMEventName(eventName) { |
- if (eventName && eventName.include(':')) return "dataavailable"; |
- return eventName; |
- } |
+ function _createResponder(element, eventName, handler) { |
+ var registry = Element.retrieve(element, 'prototype_event_registry'); |
- function getCacheForID(id) { |
- return cache[id] = cache[id] || { }; |
- } |
+ if (Object.isUndefined(registry)) { |
+ CACHE.push(element); |
+ registry = Element.retrieve(element, 'prototype_event_registry', $H()); |
+ } |
- function getWrappersForEventName(id, eventName) { |
- var c = getCacheForID(id); |
- return c[eventName] = c[eventName] || []; |
- } |
+ var respondersForEvent = registry.get(eventName); |
+ if (Object.isUndefined(respondersForEvent)) { |
+ respondersForEvent = []; |
+ registry.set(eventName, respondersForEvent); |
+ } |
- function createWrapper(element, eventName, handler) { |
- var id = getEventID(element); |
- var c = getWrappersForEventName(id, eventName); |
- if (c.pluck("handler").include(handler)) return false; |
+ if (respondersForEvent.pluck('handler').include(handler)) return false; |
- var wrapper = function(event) { |
- if (!Event || !Event.extend || |
- (event.eventName && event.eventName != eventName)) |
+ var responder; |
+ if (eventName.include(":")) { |
+ responder = function(event) { |
+ if (Object.isUndefined(event.eventName)) |
return false; |
- Event.extend(event); |
- handler.call(element, event); |
- }; |
+ if (event.eventName !== eventName) |
+ return false; |
- wrapper.handler = handler; |
- c.push(wrapper); |
- return wrapper; |
- } |
+ Event.extend(event, element); |
+ handler.call(element, event); |
+ }; |
+ } else { |
+ if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && |
+ (eventName === "mouseenter" || eventName === "mouseleave")) { |
+ if (eventName === "mouseenter" || eventName === "mouseleave") { |
+ responder = function(event) { |
+ Event.extend(event, element); |
+ |
+ var parent = event.relatedTarget; |
+ while (parent && parent !== element) { |
+ try { parent = parent.parentNode; } |
+ catch(e) { parent = element; } |
+ } |
- function findWrapper(id, eventName, handler) { |
- var c = getWrappersForEventName(id, eventName); |
- return c.find(function(wrapper) { return wrapper.handler == handler }); |
- } |
+ if (parent === element) return; |
- function destroyWrapper(id, eventName, handler) { |
- var c = getCacheForID(id); |
- if (!c[eventName]) return false; |
- c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); |
+ handler.call(element, event); |
+ }; |
+ } |
+ } else { |
+ responder = function(event) { |
+ Event.extend(event, element); |
+ handler.call(element, event); |
+ }; |
+ } |
+ } |
+ |
+ responder.handler = handler; |
+ respondersForEvent.push(responder); |
+ return responder; |
} |
- function destroyCache() { |
- for (var id in cache) |
- for (var eventName in cache[id]) |
- cache[id][eventName] = null; |
+ function _destroyCache() { |
+ for (var i = 0, length = CACHE.length; i < length; i++) { |
+ Event.stopObserving(CACHE[i]); |
+ CACHE[i] = null; |
+ } |
} |
+ var CACHE = []; |
- // Internet Explorer needs to remove event handlers on page unload |
- // in order to avoid memory leaks. |
- if (window.attachEvent) { |
- window.attachEvent("onunload", destroyCache); |
- } |
+ if (Prototype.Browser.IE) |
+ window.attachEvent('onunload', _destroyCache); |
- // Safari has a dummy event handler on page unload so that it won't |
- // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" |
- // object when page is returned to via the back button using its bfcache. |
- if (Prototype.Browser.WebKit) { |
+ if (Prototype.Browser.WebKit) |
window.addEventListener('unload', Prototype.emptyFunction, false); |
+ |
+ |
+ var _getDOMEventName = Prototype.K, |
+ translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; |
+ |
+ if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { |
+ _getDOMEventName = function(eventName) { |
+ return (translations[eventName] || eventName); |
+ }; |
} |
- return { |
- observe: function(element, eventName, handler) { |
- element = $(element); |
- var name = getDOMEventName(eventName); |
+ function observe(element, eventName, handler) { |
+ element = $(element); |
- var wrapper = createWrapper(element, eventName, handler); |
- if (!wrapper) return element; |
+ var responder = _createResponder(element, eventName, handler); |
- if (element.addEventListener) { |
- element.addEventListener(name, wrapper, false); |
- } else { |
- element.attachEvent("on" + name, wrapper); |
+ if (!responder) return element; |
+ |
+ if (eventName.include(':')) { |
+ if (element.addEventListener) |
+ element.addEventListener("dataavailable", responder, false); |
+ else { |
+ element.attachEvent("ondataavailable", responder); |
+ element.attachEvent("onlosecapture", responder); |
} |
+ } else { |
+ var actualEventName = _getDOMEventName(eventName); |
+ |
+ if (element.addEventListener) |
+ element.addEventListener(actualEventName, responder, false); |
+ else |
+ element.attachEvent("on" + actualEventName, responder); |
+ } |
+ |
+ return element; |
+ } |
+ function stopObserving(element, eventName, handler) { |
+ element = $(element); |
+ |
+ var registry = Element.retrieve(element, 'prototype_event_registry'); |
+ if (!registry) return element; |
+ |
+ if (!eventName) { |
+ registry.each( function(pair) { |
+ var eventName = pair.key; |
+ stopObserving(element, eventName); |
+ }); |
return element; |
- }, |
+ } |
- stopObserving: function(element, eventName, handler) { |
- element = $(element); |
- var id = getEventID(element), name = getDOMEventName(eventName); |
+ var responders = registry.get(eventName); |
+ if (!responders) return element; |
- if (!handler && eventName) { |
- getWrappersForEventName(id, eventName).each(function(wrapper) { |
- element.stopObserving(eventName, wrapper.handler); |
- }); |
- return element; |
+ if (!handler) { |
+ responders.each(function(r) { |
+ stopObserving(element, eventName, r.handler); |
+ }); |
+ return element; |
+ } |
- } else if (!eventName) { |
- Object.keys(getCacheForID(id)).each(function(eventName) { |
- element.stopObserving(eventName); |
- }); |
- return element; |
+ var i = responders.length, responder; |
+ while (i--) { |
+ if (responders[i].handler === handler) { |
+ responder = responders[i]; |
+ break; |
+ } |
+ } |
+ if (!responder) return element; |
+ |
+ if (eventName.include(':')) { |
+ if (element.removeEventListener) |
+ element.removeEventListener("dataavailable", responder, false); |
+ else { |
+ element.detachEvent("ondataavailable", responder); |
+ element.detachEvent("onlosecapture", responder); |
} |
+ } else { |
+ var actualEventName = _getDOMEventName(eventName); |
+ if (element.removeEventListener) |
+ element.removeEventListener(actualEventName, responder, false); |
+ else |
+ element.detachEvent('on' + actualEventName, responder); |
+ } |
- var wrapper = findWrapper(id, eventName, handler); |
- if (!wrapper) return element; |
+ registry.set(eventName, responders.without(responder)); |
- if (element.removeEventListener) { |
- element.removeEventListener(name, wrapper, false); |
- } else { |
- element.detachEvent("on" + name, wrapper); |
- } |
+ return element; |
+ } |
- destroyWrapper(id, eventName, handler); |
+ function fire(element, eventName, memo, bubble) { |
+ element = $(element); |
- return element; |
- }, |
+ if (Object.isUndefined(bubble)) |
+ bubble = true; |
- fire: function(element, eventName, memo) { |
- element = $(element); |
- if (element == document && document.createEvent && !element.dispatchEvent) |
- element = document.documentElement; |
+ if (element == document && document.createEvent && !element.dispatchEvent) |
+ element = document.documentElement; |
- var event; |
- if (document.createEvent) { |
- event = document.createEvent("HTMLEvents"); |
- event.initEvent("dataavailable", true, true); |
- } else { |
- event = document.createEventObject(); |
- event.eventType = "ondataavailable"; |
- } |
+ var event; |
+ if (document.createEvent) { |
+ event = document.createEvent('HTMLEvents'); |
+ event.initEvent('dataavailable', bubble, true); |
+ } else { |
+ event = document.createEventObject(); |
+ event.eventType = bubble ? 'ondataavailable' : 'onlosecapture'; |
+ } |
- event.eventName = eventName; |
- event.memo = memo || { }; |
+ event.eventName = eventName; |
+ event.memo = memo || { }; |
- if (document.createEvent) { |
- element.dispatchEvent(event); |
- } else { |
- element.fireEvent(event.eventType, event); |
- } |
+ if (document.createEvent) |
+ element.dispatchEvent(event); |
+ else |
+ element.fireEvent(event.eventType, event); |
+ |
+ return Event.extend(event); |
+ } |
+ |
+ Event.Handler = Class.create({ |
+ initialize: function(element, eventName, selector, callback) { |
+ this.element = $(element); |
+ this.eventName = eventName; |
+ this.selector = selector; |
+ this.callback = callback; |
+ this.handler = this.handleEvent.bind(this); |
+ }, |
+ |
+ start: function() { |
+ Event.observe(this.element, this.eventName, this.handler); |
+ return this; |
+ }, |
+ |
+ stop: function() { |
+ Event.stopObserving(this.element, this.eventName, this.handler); |
+ return this; |
+ }, |
- return Event.extend(event); |
+ handleEvent: function(event) { |
+ var element = Event.findElement(event, this.selector); |
+ if (element) this.callback.call(this.element, event, element); |
} |
- }; |
-})()); |
+ }); |
-Object.extend(Event, Event.Methods); |
+ function on(element, eventName, selector, callback) { |
+ element = $(element); |
+ if (Object.isFunction(selector) && Object.isUndefined(callback)) { |
+ callback = selector, selector = null; |
+ } |
-Element.addMethods({ |
- fire: Event.fire, |
- observe: Event.observe, |
- stopObserving: Event.stopObserving |
-}); |
+ return new Event.Handler(element, eventName, selector, callback).start(); |
+ } |
-Object.extend(document, { |
- fire: Element.Methods.fire.methodize(), |
- observe: Element.Methods.observe.methodize(), |
- stopObserving: Element.Methods.stopObserving.methodize(), |
- loaded: false |
-}); |
+ Object.extend(Event, Event.Methods); |
+ |
+ Object.extend(Event, { |
+ fire: fire, |
+ observe: observe, |
+ stopObserving: stopObserving, |
+ on: on |
+ }); |
+ |
+ Element.addMethods({ |
+ fire: fire, |
+ |
+ observe: observe, |
+ |
+ stopObserving: stopObserving, |
+ |
+ on: on |
+ }); |
+ |
+ Object.extend(document, { |
+ fire: fire.methodize(), |
+ |
+ observe: observe.methodize(), |
+ |
+ stopObserving: stopObserving.methodize(), |
+ |
+ on: on.methodize(), |
+ |
+ loaded: false |
+ }); |
+ |
+ if (window.Event) Object.extend(window.Event, Event); |
+ else window.Event = Event; |
+})(); |
(function() { |
/* Support for the DOMContentLoaded event is based on work by Dan Webb, |
- Matthias Miller, Dean Edwards and John Resig. */ |
+ Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ |
var timer; |
function fireContentLoadedEvent() { |
if (document.loaded) return; |
- if (timer) window.clearInterval(timer); |
- document.fire("dom:loaded"); |
+ if (timer) window.clearTimeout(timer); |
document.loaded = true; |
+ document.fire('dom:loaded'); |
} |
- if (document.addEventListener) { |
- if (Prototype.Browser.WebKit) { |
- timer = window.setInterval(function() { |
- if (/loaded|complete/.test(document.readyState)) |
- fireContentLoadedEvent(); |
- }, 0); |
- |
- Event.observe(window, "load", fireContentLoadedEvent); |
+ function checkReadyState() { |
+ if (document.readyState === 'complete') { |
+ document.stopObserving('readystatechange', checkReadyState); |
+ fireContentLoadedEvent(); |
+ } |
+ } |
- } else { |
- document.addEventListener("DOMContentLoaded", |
- fireContentLoadedEvent, false); |
+ function pollDoScroll() { |
+ try { document.documentElement.doScroll('left'); } |
+ catch(e) { |
+ timer = pollDoScroll.defer(); |
+ return; |
} |
+ fireContentLoadedEvent(); |
+ } |
+ if (document.addEventListener) { |
+ document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); |
} else { |
- document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>"); |
- $("__onDOMContentLoaded").onreadystatechange = function() { |
- if (this.readyState == "complete") { |
- this.onreadystatechange = null; |
- fireContentLoadedEvent(); |
- } |
- }; |
+ document.observe('readystatechange', checkReadyState); |
+ if (window == top) |
+ timer = pollDoScroll.defer(); |
} |
+ |
+ Event.observe(window, 'load', fireContentLoadedEvent); |
})(); |
+ |
+Element.addMethods(); |
+ |
/*------------------------------- DEPRECATED -------------------------------*/ |
Hash.toQueryString = Object.toQueryString; |
@@ -4158,16 +5877,9 @@ var Insertion = { |
var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); |
-// This should be moved to script.aculo.us; notice the deprecated methods |
-// further below, that map to the newer Element methods. |
var Position = { |
- // set to true if needed, warning: firefox performance problems |
- // NOT neeeded for page scrolling, only if draggable contained in |
- // scrollable elements |
includeScrollOffsets: false, |
- // must be called before calling withinIncludingScrolloffset, every time the |
- // page is scrolled |
prepare: function() { |
this.deltaX = window.pageXOffset |
|| document.documentElement.scrollLeft |
@@ -4179,7 +5891,6 @@ var Position = { |
|| 0; |
}, |
- // caches x/y coordinate pair to use with overlap |
within: function(element, x, y) { |
if (this.includeScrollOffsets) |
return this.withinIncludingScrolloffsets(element, x, y); |
@@ -4206,7 +5917,6 @@ var Position = { |
this.xcomp < this.offset[0] + element.offsetWidth); |
}, |
- // within must be called directly before |
overlap: function(mode, element) { |
if (!mode) return 0; |
if (mode == 'vertical') |
@@ -4217,7 +5927,6 @@ var Position = { |
element.offsetWidth; |
}, |
- // Deprecation layer -- use newer Element methods now (1.5.2). |
cumulativeOffset: Element.Methods.cumulativeOffset, |
@@ -4317,4 +6026,57 @@ Object.extend(Element.ClassNames.prototype, Enumerable); |
/*--------------------------------------------------------------------------*/ |
-Element.addMethods(); |
+(function() { |
+ window.Selector = Class.create({ |
+ initialize: function(expression) { |
+ this.expression = expression.strip(); |
+ }, |
+ |
+ findElements: function(rootElement) { |
+ return Prototype.Selector.select(this.expression, rootElement); |
+ }, |
+ |
+ match: function(element) { |
+ return Prototype.Selector.match(element, this.expression); |
+ }, |
+ |
+ toString: function() { |
+ return this.expression; |
+ }, |
+ |
+ inspect: function() { |
+ return "#<Selector: " + this.expression + ">"; |
+ } |
+ }); |
+ |
+ Object.extend(Selector, { |
+ matchElements: function(elements, expression) { |
+ var match = Prototype.Selector.match, |
+ results = []; |
+ |
+ for (var i = 0, length = elements.length; i < length; i++) { |
+ var element = elements[i]; |
+ if (match(element, expression)) { |
+ results.push(Element.extend(element)); |
+ } |
+ } |
+ return results; |
+ }, |
+ |
+ findElement: function(elements, expression, index) { |
+ index = index || 0; |
+ var matchIndex = 0, element; |
+ for (var i = 0, length = elements.length; i < length; i++) { |
+ element = elements[i]; |
+ if (Prototype.Selector.match(element, expression) && index === matchIndex++) { |
+ return Element.extend(element); |
+ } |
+ } |
+ }, |
+ |
+ findChildElements: function(element, expressions) { |
+ var selector = expressions.toArray().join(', '); |
+ return Prototype.Selector.select(selector, element || document); |
+ } |
+ }); |
+})(); |