diff options
author | wei <> | 2007-03-25 07:04:08 +0000 |
---|---|---|
committer | wei <> | 2007-03-25 07:04:08 +0000 |
commit | c9c31d6edb91e22c56ffab3772ce8a29b1480537 (patch) | |
tree | a592860494b2ffd00fd1b6405e86388acbdcf1b5 /framework/Web/Javascripts/js/debug/prado.js | |
parent | 2cdb60e09eb972200cead6414e7aef32ef1432e0 (diff) |
Update TinyMCE to 2.1, Js prototype to 1.5.1rc, effects to 1.7
Diffstat (limited to 'framework/Web/Javascripts/js/debug/prado.js')
-rw-r--r-- | framework/Web/Javascripts/js/debug/prado.js | 3593 |
1 files changed, 2542 insertions, 1051 deletions
diff --git a/framework/Web/Javascripts/js/debug/prado.js b/framework/Web/Javascripts/js/debug/prado.js index 1eaa5216..b9ed0117 100644 --- a/framework/Web/Javascripts/js/debug/prado.js +++ b/framework/Web/Javascripts/js/debug/prado.js @@ -1,31 +1,36 @@ -/* Prototype JavaScript framework, version <%= PROTOTYPE_VERSION %> - * (c) 2005 Sam Stephenson <sam@conio.net> +/* Prototype JavaScript framework, version 1.5.1_rc2 + * (c) 2005-2007 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://prototype.conio.net/ + * For details, see the Prototype web site: http://www.prototypejs.org/ * /*--------------------------------------------------------------------------*/ var Prototype = { - Version: '1.50', + Version: '1.5.1_rc2', + + Browser: { + IE: !!(window.attachEvent && !window.opera), + Opera: !!window.opera, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 + }, + BrowserFeatures: { + XPath: !!document.evaluate, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + (document.createElement('div').__proto__ !== + document.createElement('form').__proto__) + }, + ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', - emptyFunction: function() {}, - K: function(x) {return x} + K: function(x) { return x } } -/* -<%= include 'base.js', 'string.js' %> - -<%= include 'enumerable.js', 'array.js', 'hash.js', 'range.js' %> - -<%= include 'ajax.js', 'dom.js', 'selector.js', 'form.js', 'event.js', 'position.js' %> - -*/ - var Class = { create: function() { - return function() { + return function() { this.initialize.apply(this, arguments); } } @@ -40,16 +45,56 @@ Object.extend = function(destination, source) { return destination; } -Object.inspect = function(object) { - try { - if (object == undefined) return 'undefined'; - if (object == null) return 'null'; - return object.inspect ? object.inspect() : object.toString(); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; +Object.extend(Object, { + inspect: function(object) { + try { + if (object === undefined) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } 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(); + } + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (object.ownerDocument === document) return; + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (value !== undefined) + results.push(property.toJSON() + ':' + value); + } + return '{' + results.join(',') + '}'; + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({}, object); } -} +}); Function.prototype.bind = function() { var __method = this, args = $A(arguments), object = args.shift(); @@ -59,34 +104,50 @@ Function.prototype.bind = function() { } Function.prototype.bindAsEventListener = function(object) { - var __method = this; + var __method = this, args = $A(arguments), object = args.shift(); return function(event) { - return __method.call(object, event || window.event); + return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); } } Object.extend(Number.prototype, { toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; + return this.toPaddedString(2, 16); }, succ: function() { return this + 1; }, - + times: function(iterator) { $R(0, this, true).each(iterator); return this; + }, + + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, + + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; } }); +Date.prototype.toJSON = function() { + return '"' + this.getFullYear() + '-' + + (this.getMonth() + 1).toPaddedString(2) + '-' + + this.getDate().toPaddedString(2) + 'T' + + this.getHours().toPaddedString(2) + ':' + + this.getMinutes().toPaddedString(2) + ':' + + this.getSeconds().toPaddedString(2) + '"'; +}; + var Try = { these: function() { var returnValue; - for (var i = 0; i < arguments.length; i++) { + for (var i = 0, length = arguments.length; i < length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); @@ -111,169 +172,49 @@ PeriodicalExecuter.prototype = { }, registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { - try { + try { this.currentlyExecuting = true; - this.callback(); - } finally { + this.callback(this); + } finally { this.currentlyExecuting = false; } } } } - - -
-/**
- * Similar to bindAsEventLister, but takes additional arguments.
- */
-Function.prototype.bindEvent = function()
-{
- var __method = this, args = $A(arguments), object = args.shift();
- return function(event)
- {
- return __method.apply(object, [event || window.event].concat(args));
- }
-}
-
-/**
- * Creates a new function by copying function definition from
- * the <tt>base</tt> and optional <tt>definition</tt>.
- * @param function a base function to copy from.
- * @param array additional definition
- * @param function return a new function with definition from both
- * <tt>base</tt> and <tt>definition</tt>.
- */
-Class.extend = function(base, definition)
-{
- var component = Class.create();
- Object.extend(component.prototype, base.prototype);
- if(definition)
- Object.extend(component.prototype, definition);
- return component;
-}
-
-/*
- Base, version 1.0.2
- Copyright 2006, Dean Edwards
- License: http://creativecommons.org/licenses/LGPL/2.1/
-*/
-
-var Base = function() {
- if (arguments.length) {
- if (this == window) { // cast an object to this class
- Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
- } else {
- this.extend(arguments[0]);
- }
- }
-};
-
-Base.version = "1.0.2";
-
-Base.prototype = {
- extend: function(source, value) {
- var extend = Base.prototype.extend;
- if (arguments.length == 2) {
- var ancestor = this[source];
- // overriding?
- if ((ancestor instanceof Function) && (value instanceof Function) &&
- ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) {
- var method = value;
- // var _prototype = this.constructor.prototype;
- // var fromPrototype = !Base._prototyping && _prototype[source] == ancestor;
- value = function() {
- var previous = this.base;
- // this.base = fromPrototype ? _prototype[source] : ancestor;
- this.base = ancestor;
- var returnValue = method.apply(this, arguments);
- this.base = previous;
- return returnValue;
- };
- // point to the underlying method
- value.valueOf = function() {
- return method;
- };
- value.toString = function() {
- return String(method);
- };
- }
- return this[source] = value;
- } else if (source) {
- var _prototype = {toSource: null};
- // do the "toString" and other methods manually
- var _protected = ["toString", "valueOf"];
- // if we are prototyping then include the constructor
- if (Base._prototyping) _protected[2] = "constructor";
- for (var i = 0; (name = _protected[i]); i++) {
- if (source[name] != _prototype[name]) {
- extend.call(this, name, source[name]);
- }
- }
- // copy each of the source object's properties to this object
- for (var name in source) {
- if (!_prototype[name]) {
- extend.call(this, name, source[name]);
- }
- }
- }
- return this;
- },
-
- base: function() {
- // call this method from any other method to invoke that method's ancestor
- }
-};
-
-Base.extend = function(_instance, _static) {
- var extend = Base.prototype.extend;
- if (!_instance) _instance = {};
- // build the prototype
- Base._prototyping = true;
- var _prototype = new this;
- extend.call(_prototype, _instance);
- var constructor = _prototype.constructor;
- _prototype.constructor = this;
- delete Base._prototyping;
- // create the wrapper for the constructor function
- var klass = function() {
- if (!Base._prototyping) constructor.apply(this, arguments);
- this.constructor = klass;
- };
- klass.prototype = _prototype;
- // build the class interface
- klass.extend = this.extend;
- klass.implement = this.implement;
- klass.toString = function() {
- return String(constructor);
- };
- extend.call(klass, _static);
- // single instance
- var object = constructor ? klass : _prototype;
- // class initialisation
- if (object.init instanceof Function) object.init();
- return object;
-};
-
-Base.implement = function(_interface) {
- if (_interface instanceof Function) _interface = _interface.prototype;
- this.prototype.extend(_interface);
-};
- +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); Object.extend(String.prototype, { gsub: function(pattern, replacement) { var result = '', source = this, match; replacement = arguments.callee.prepareReplacement(replacement); - + while (source.length > 0) { if (match = source.match(pattern)) { result += source.slice(0, match.index); - result += (replacement(match) || '').toString(); + result += String.interpret(replacement(match)); source = source.slice(match.index + match[0].length); } else { result += source, source = ''; @@ -281,33 +222,33 @@ Object.extend(String.prototype, { } return result; }, - + sub: function(pattern, replacement, count) { replacement = this.gsub.prepareReplacement(replacement); count = count === undefined ? 1 : count; - + return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; return replacement(match); }); }, - + scan: function(pattern, iterator) { this.gsub(pattern, iterator); return this; }, - + truncate: function(length, truncation) { length = length || 30; truncation = truncation === undefined ? '...' : truncation; - return this.length > length ? + return this.length > length ? this.slice(0, length - truncation.length) + truncation : this; }, strip: function() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); }, - + stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, @@ -315,7 +256,7 @@ Object.extend(String.prototype, { stripScripts: function() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); }, - + extractScripts: function() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); @@ -323,55 +264,125 @@ Object.extend(String.prototype, { return (scriptTag.match(matchOne) || ['', ''])[1]; }); }, - + evalScripts: function() { return this.extractScripts().map(function(script) { return eval(script) }); }, escapeHTML: function() { - var div = document.createElement('div'); - var text = document.createTextNode(this); - div.appendChild(text); - return div.innerHTML; + var self = arguments.callee; + self.text.data = this; + return self.div.innerHTML; }, unescapeHTML: function() { var div = document.createElement('div'); div.innerHTML = this.stripTags(); - return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; + 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() { - var pairs = this.match(/^\??(.*)$/)[1].split('&'); - return pairs.inject({}, function(params, pairString) { - var pair = pairString.split('='); - params[pair[0]] = pair[1]; - return params; + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return {}; + + return match[1].split(separator || '&').inject({}, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var name = decodeURIComponent(pair[0]); + var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; + + if (hash[name] !== undefined) { + if (hash[name].constructor != Array) + hash[name] = [hash[name]]; + if (value) hash[name].push(value); + } + else hash[name] = value; + } + return hash; }); }, - + toArray: function() { return this.split(''); }, - + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + times: function(count) { + var result = ''; + for (var i = 0; i < count; i++) result += this; + return result; + }, + camelize: function() { - var oStringList = this.split('-'); - if (oStringList.length == 1) return oStringList[0]; - - var camelizedString = this.indexOf('-') == 0 - ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) - : oStringList[0]; - - for (var i = 1, len = oStringList.length; i < len; i++) { - var s = oStringList[i]; - camelizedString += s.charAt(0).toUpperCase() + s.substring(1); - } - - return camelizedString; + 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; }, - inspect: function() { - return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'"; + capitalize: function() { + 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(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + 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); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + }, + + toJSON: function() { + return this.inspect(true); + }, + + evalJSON: function(sanitize) { + try { + if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(this))) + return eval('(' + this + ')'); + } catch (e) {} + throw new SyntaxError('Badly formated JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) == 0; + }, + + endsWith: function(pattern) { + return this.lastIndexOf(pattern) == (this.length - pattern.length); + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); } }); @@ -383,6 +394,13 @@ String.prototype.gsub.prepareReplacement = function(replacement) { String.prototype.parseQuery = String.prototype.toQueryParams; +Object.extend(String.prototype.escapeHTML, { + div: document.createElement('div'), + text: document.createTextNode('') +}); + +with (String.prototype.escapeHTML) div.appendChild(text); + var Template = Class.create(); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; Template.prototype = { @@ -390,189 +408,16 @@ Template.prototype = { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, - + evaluate: function(object) { return this.template.gsub(this.pattern, function(match) { var before = match[1]; if (before == '\\') return match[2]; - return before + (object[match[3]] || '').toString(); + return before + String.interpret(object[match[3]]); }); } } - -/**
- * @class String extensions
- */
-Object.extend(String.prototype, {
- /**
- * @param {String} "left" to pad the string on the left, "right" to pad right.
- * @param {Number} minimum string length.
- * @param {String} character(s) to pad
- * @return {String} padded character(s) on the left or right to satisfy minimum string length
- */
-
- pad : function(side, len, chr) {
- if (!chr) chr = ' ';
- var s = this;
- var left = side.toLowerCase()=='left';
- while (s.length<len) s = left? chr + s : s + chr;
- return s;
- },
-
- /**
- * @param {Number} minimum string length.
- * @param {String} character(s) to pad
- * @return {String} padded character(s) on the left to satisfy minimum string length
- */
- padLeft : function(len, chr) {
- return this.pad('left',len,chr);
- },
-
- /**
- * @param {Number} minimum string length.
- * @param {String} character(s) to pad
- * @return {String} padded character(s) on the right to satisfy minimum string length
- */
- padRight : function(len, chr) {
- return this.pad('right',len,chr);
- },
-
- /**
- * @param {Number} minimum string length.
- * @return {String} append zeros to the left to satisfy minimum string length.
- */
- zerofill : function(len) {
- return this.padLeft(len,'0');
- },
-
- /**
- * @return {String} removed white spaces from both ends.
- */
- trim : function() {
- return this.replace(/^\s+|\s+$/g,'');
- },
-
- /**
- * @return {String} removed white spaces from the left end.
- */
- trimLeft : function() {
- return this.replace(/^\s+/,'');
- },
-
- /**
- * @return {String} removed white spaces from the right end.
- */
- trimRight : function() {
- return this.replace(/\s+$/,'');
- },
-
- /**
- * Convert period separated function names into a function reference.
- * e.g. "Prado.AJAX.Callback.Action.setValue".toFunction() will return
- * the actual function Prado.AJAX.Callback.Action.setValue()
- * @return {Function} the corresponding function represented by the string.
- */
- toFunction : function()
- {
- var commands = this.split(/\./);
- var command = window;
- commands.each(function(action)
- {
- if(command[new String(action)])
- command=command[new String(action)];
- });
- if(typeof(command) == "function")
- return command;
- else
- {
- if(typeof Logger != "undefined")
- Logger.error("Missing function", this);
-
- throw new Error ("Missing function '"+this+"'");
- }
- },
-
- /**
- * Convert a string into integer, returns null if not integer.
- * @return {Number} null if string does not represent an integer.
- */
- toInteger : function()
- {
- var exp = /^\s*[-\+]?\d+\s*$/;
- if (this.match(exp) == null)
- return null;
- var num = parseInt(this, 10);
- return (isNaN(num) ? null : num);
- },
-
- /**
- * Convert a string into a double/float value. <b>Internationalization
- * is not supported</b>
- * @param {String} the decimal character
- * @return {Double} null if string does not represent a float value
- */
- toDouble : function(decimalchar)
- {
- if(this.length <= 0) return null;
- decimalchar = decimalchar || ".";
- var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$");
- var m = this.match(exp);
-
- if (m == null)
- return null;
- m[1] = m[1] || "";
- m[2] = m[2] || "0";
- m[4] = m[4] || "0";
-
- var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4];
- var num = parseFloat(cleanInput);
- return (isNaN(num) ? null : num);
- },
-
- /**
- * Convert strings that represent a currency value (e.g. a float with grouping
- * characters) to float. E.g. "10,000.50" will become "10000.50". The number
- * of dicimal digits, grouping and decimal characters can be specified.
- * <i>The currency input format is <b>very</b> strict, null will be returned if
- * the pattern does not match</i>.
- * @param {String} the grouping character, default is ","
- * @param {Number} number of decimal digits
- * @param {String} the decimal character, default is "."
- * @type {Double} the currency value as float.
- */
- toCurrency : function(groupchar, digits, decimalchar)
- {
- groupchar = groupchar || ",";
- decimalchar = decimalchar || ".";
- digits = typeof(digits) == "undefined" ? 2 : digits;
-
- var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)"
- + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "")
- + "\\s*$");
- var m = this.match(exp);
- if (m == null)
- return null;
- var intermed = m[2] + m[5] ;
- var cleanInput = m[1] + intermed.replace(
- new RegExp("(\\" + groupchar + ")", "g"), "")
- + ((digits > 0) ? "." + m[7] : "");
- var num = parseFloat(cleanInput);
- return (isNaN(num) ? null : num);
- },
-
- /**
- * Converts the string to a date by finding values that matches the
- * date format pattern.
- * @param string date format pattern, e.g. MM-dd-yyyy
- * @return {Date} the date extracted from the string
- */
- toDate : function(format)
- {
- return Date.SimpleParse(this, format);
- }
-}); - var $break = new Object(); var $continue = new Object(); @@ -581,17 +426,21 @@ var Enumerable = { var index = 0; try { this._each(function(value) { - try { - iterator(value, index++); - } catch (e) { - if (e != $continue) throw e; - } + iterator(value, index++); }); } catch (e) { if (e != $break) throw e; } + return this; }, - + + eachSlice: function(number, iterator) { + var index = -number, slices = [], array = this.toArray(); + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.map(iterator); + }, + all: function(iterator) { var result = true; this.each(function(value, index) { @@ -600,25 +449,25 @@ var Enumerable = { }); return result; }, - + any: function(iterator) { - var result = true; + var result = false; this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) + if (result = !!(iterator || Prototype.K)(value, index)) throw $break; }); return result; }, - + collect: function(iterator) { var results = []; this.each(function(value, index) { - results.push(iterator(value, index)); + results.push((iterator || Prototype.K)(value, index)); }); return results; }, - - detect: function (iterator) { + + detect: function(iterator) { var result; this.each(function(value, index) { if (iterator(value, index)) { @@ -628,7 +477,7 @@ var Enumerable = { }); return result; }, - + findAll: function(iterator) { var results = []; this.each(function(value, index) { @@ -637,7 +486,7 @@ var Enumerable = { }); return results; }, - + grep: function(pattern, iterator) { var results = []; this.each(function(value, index) { @@ -647,7 +496,7 @@ var Enumerable = { }) return results; }, - + include: function(object) { var found = false; this.each(function(value) { @@ -658,21 +507,29 @@ var Enumerable = { }); return found; }, - + + inGroupsOf: function(number, fillWith) { + fillWith = fillWith === undefined ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + inject: function(memo, iterator) { this.each(function(value, index) { memo = iterator(memo, value, index); }); return memo; }, - + invoke: function(method) { var args = $A(arguments).slice(1); - return this.collect(function(value) { + return this.map(function(value) { return value[method].apply(value, args); }); }, - + max: function(iterator) { var result; this.each(function(value, index) { @@ -682,7 +539,7 @@ var Enumerable = { }); return result; }, - + min: function(iterator) { var result; this.each(function(value, index) { @@ -692,16 +549,16 @@ var Enumerable = { }); return result; }, - + partition: function(iterator) { var trues = [], falses = []; this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? + ((iterator || Prototype.K)(value, index) ? trues : falses).push(value); }); return [trues, falses]; }, - + pluck: function(property) { var results = []; this.each(function(value, index) { @@ -709,7 +566,7 @@ var Enumerable = { }); return results; }, - + reject: function(iterator) { var results = []; this.each(function(value, index) { @@ -718,20 +575,20 @@ var Enumerable = { }); return results; }, - + sortBy: function(iterator) { - return this.collect(function(value, index) { + return this.map(function(value, index) { return {value: value, criteria: iterator(value, index)}; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); }, - + toArray: function() { - return this.collect(Prototype.K); + return this.map(); }, - + zip: function() { var iterator = Prototype.K, args = $A(arguments); if (typeof args.last() == 'function') @@ -742,7 +599,11 @@ var Enumerable = { return iterator(collections.pluck(index)); }); }, - + + size: function() { + return this.toArray().length; + }, + inspect: function() { return '#<Enumerable:' + this.toArray().inspect() + '>'; } @@ -755,20 +616,33 @@ Object.extend(Enumerable, { member: Enumerable.include, entries: Enumerable.toArray }); - - var $A = Array.from = function(iterable) { if (!iterable) return []; if (iterable.toArray) { return iterable.toArray(); } else { var results = []; - for (var i = 0; i < iterable.length; i++) + for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } +if (Prototype.Browser.WebKit) { + $A = Array.from = function(iterable) { + if (!iterable) return []; + if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && + iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0, length = iterable.length; i < length; i++) + results.push(iterable[i]); + return results; + } + } +} + Object.extend(Array.prototype, Enumerable); if (!Array.prototype._reverse) @@ -776,108 +650,234 @@ if (!Array.prototype._reverse) Object.extend(Array.prototype, { _each: function(iterator) { - for (var i = 0; i < this.length; i++) + for (var i = 0, length = this.length; i < length; i++) iterator(this[i]); }, - + clear: function() { this.length = 0; return this; }, - + first: function() { return this[0]; }, - + last: function() { return this[this.length - 1]; }, - + compact: function() { return this.select(function(value) { - return value != undefined || value != null; + return value != null; }); }, - + flatten: function() { return this.inject([], function(array, value) { return array.concat(value && value.constructor == Array ? value.flatten() : [value]); }); }, - + without: function() { var values = $A(arguments); return this.select(function(value) { return !values.include(value); }); }, - + indexOf: function(object) { - for (var i = 0; i < this.length; i++) + for (var i = 0, length = this.length; i < length; i++) if (this[i] == object) return i; return -1; }, - + reverse: function(inline) { return (inline !== false ? this : this.toArray())._reverse(); }, - + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + inspect: function() { return '[' + this.map(Object.inspect).join(', ') + ']'; + }, + + toJSON: function() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (value !== undefined) results.push(value); + }); + return '[' + results.join(',') + ']'; } }); +Array.prototype.toArray = Array.prototype.clone; + +function $w(string) { + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if (Prototype.Browser.Opera){ + Array.prototype.concat = function() { + var array = []; + for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for (var i = 0, length = arguments.length; i < length; i++) { + if (arguments[i].constructor == Array) { + for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + } +} +var Hash = function(object) { + if (object instanceof Hash) this.merge(object); + else Object.extend(this, object || {}); +}; + +Object.extend(Hash, { + toQueryString: function(obj) { + var parts = []; + parts.add = arguments.callee.addPair; + + this.prototype._each.call(obj, function(pair) { + if (!pair.key) return; + var value = pair.value; + + if (value && typeof value == 'object') { + if (value.constructor == Array) value.each(function(value) { + parts.add(pair.key, value); + }); + return; + } + parts.add(pair.key, value); + }); + + return parts.join('&'); + }, -var Hash = { + toJSON: function(object) { + var results = []; + this.prototype._each.call(object, function(pair) { + var value = Object.toJSON(pair.value); + if (value !== undefined) results.push(pair.key.toJSON() + ':' + value); + }); + return '{' + results.join(',') + '}'; + } +}); + +Hash.toQueryString.addPair = function(key, value, prefix) { + if (value == null) return; + key = encodeURIComponent(key); + this.push(key + '=' + (value == null ? '' : encodeURIComponent(value))); +} + +Object.extend(Hash.prototype, Enumerable); +Object.extend(Hash.prototype, { _each: function(iterator) { for (var key in this) { var value = this[key]; - if (typeof value == 'function') continue; - + if (value && value == Hash.prototype[key]) continue; + var pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } }, - + keys: function() { return this.pluck('key'); }, - + values: function() { return this.pluck('value'); }, - + merge: function(hash) { - return $H(hash).inject($H(this), function(mergedHash, pair) { + return $H(hash).inject(this, function(mergedHash, pair) { mergedHash[pair.key] = pair.value; return mergedHash; }); }, - + + remove: function() { + var result; + for(var i = 0, length = arguments.length; i < length; i++) { + var value = this[arguments[i]]; + if (value !== undefined){ + if (result === undefined) result = value; + else { + if (result.constructor != Array) result = [result]; + result.push(value) + } + } + delete this[arguments[i]]; + } + return result; + }, + toQueryString: function() { - return this.map(function(pair) { - return pair.map(encodeURIComponent).join('='); - }).join('&'); + return Hash.toQueryString(this); }, - + inspect: function() { return '#<Hash:{' + this.map(function(pair) { return pair.map(Object.inspect).join(': '); }).join(', ') + '}>'; + }, + + toJSON: function() { + return Hash.toJSON(this); } -} +}); function $H(object) { - var hash = Object.extend({}, object || {}); - Object.extend(hash, Enumerable); - Object.extend(hash, Hash); - return hash; -} - + if (object instanceof Hash) return object; + return new Hash(object); +}; +// Safari iterates over shadowed properties +if (function() { + var i = 0, Test = function(value) { this.key = value }; + Test.prototype.key = 'foo'; + for (var property in new Test('bar')) i++; + return i > 1; +}()) Hash.prototype._each = function(iterator) { + var cache = []; + for (var key in this) { + var value = this[key]; + if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; + cache.push(key); + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } +}; ObjectRange = Class.create(); Object.extend(ObjectRange.prototype, Enumerable); Object.extend(ObjectRange.prototype, { @@ -886,17 +886,17 @@ Object.extend(ObjectRange.prototype, { this.end = end; this.exclusive = exclusive; }, - + _each: function(iterator) { var value = this.start; - do { + while (this.include(value)) { iterator(value); value = value.succ(); - } while (this.include(value)); + } }, - + include: function(value) { - if (value < this.start) + if (value < this.start) return false; if (this.exclusive) return value < this.end; @@ -908,47 +908,389 @@ var $R = function(start, end, exclusive) { return new ObjectRange(start, end, exclusive); } -function $() { - var results = [], element; - for (var i = 0; i < arguments.length; i++) { - element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - results.push(Element.extend(element)); +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '' + } + Object.extend(this.options, options || {}); + + this.options.method = this.options.method.toLowerCase(); + if (typeof this.options.parameters == 'string') + this.options.parameters = this.options.parameters.toQueryParams(); } - return results.length < 2 ? results[0] : results; } -document.getElementsByClassName = function(className, parentElement) { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - return $A(children).inject([], function(elements, child) { - if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) - elements.push(Element.extend(child)); +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + _complete: false, + + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Hash.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 += '&_='; + } + + try { + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) + setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (typeof extras.push == 'function') + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + return !this.transport.status + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + this.transport.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.getHeader('Content-type') || 'text/javascript').strip(). + match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + state, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { return null } + }, + + evalJSON: function() { + try { + var json = this.getHeader('X-JSON'); + return json ? eval('(' + json + ')') : null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, param) { + this.updateContent(); + onComplete(transport, param); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.container[this.success() ? 'success' : 'failure']; + var response = this.transport.responseText; + + if (!this.options.evalScripts) response = response.stripScripts(); + + if (receiver = $(receiver)) { + if (this.options.insertion) + new this.options.insertion(receiver, response); + else + receiver.update(response); + } + + if (this.success()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + 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++) + elements.push($(arguments[i])); return elements; - }); + } + if (typeof element == 'string') + element = document.getElementById(element); + return Element.extend(element); } +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(query.snapshotItem(i)); + return results; + }; + + document.getElementsByClassName = function(className, parentElement) { + var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; + return document._getElementsByXPath(q, parentElement); + } + +} else document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + var elements = [], child; + for (var i = 0, length = children.length; i < length; i++) { + child = children[i]; + if (Element.hasClassName(child, className)) + elements.push(Element.extend(child)); + } + return elements; +}; + /*--------------------------------------------------------------------------*/ -if (!window.Element) - var Element = new Object(); +if (!window.Element) var Element = {}; Element.extend = function(element) { - if (!element) return; - if (_nativeExtensions) return element; - - if (!element._extended && element.tagName && element != window) { - var methods = Element.Methods, cache = Element.extend.cache; - for (property in methods) { - var value = methods[property]; - if (typeof value == 'function') - element[property] = cache.findOrStore(value); - } + var F = Prototype.BrowserFeatures; + if (!element || !element.tagName || element.nodeType == 3 || + element._extended || F.SpecificElementExtensions || element == window) + return element; + + var methods = {}, tagName = element.tagName, cache = Element.extend.cache, + T = Element.Methods.ByTag; + + // extend methods for all tags (Safari doesn't need this) + if (!F.ElementExtensions) { + Object.extend(methods, Element.Methods), + Object.extend(methods, Element.Methods.Simulated); } - - element._extended = true; + + // extend methods for specific tags + if (T[tagName]) Object.extend(methods, T[tagName]); + + for (var property in methods) { + var value = methods[property]; + if (typeof value == 'function' && !(property in element)) + element[property] = cache.findOrStore(value); + } + + element._extended = Prototype.emptyFunction; return element; -} +}; Element.extend.cache = { findOrStore: function(value) { @@ -956,46 +1298,45 @@ Element.extend.cache = { return value.apply(null, [this].concat($A(arguments))); } } -} +}; Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; }, - - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - Element[Element.visible(element) ? 'hide' : 'show'](element); - } + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; }, - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } + hide: function(element) { + $(element).style.display = 'none'; + return element; }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } + + show: function(element) { + $(element).style.display = ''; + return element; }, remove: function(element) { element = $(element); element.parentNode.removeChild(element); + return element; }, update: function(element, html) { + html = typeof html == 'undefined' ? '' : html.toString(); $(element).innerHTML = html.stripScripts(); setTimeout(function() {html.evalScripts()}, 10); + return element; }, - + replace: function(element, html) { element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); if (element.outerHTML) { element.outerHTML = html.stripScripts(); } else { @@ -1005,105 +1346,250 @@ Element.Methods = { range.createContextualFragment(html.stripScripts()), element); } setTimeout(function() {html.evalScripts()}, 10); + return element; }, - - getHeight: function(element) { + + inspect: function(element) { element = $(element); - return element.offsetHeight; + 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(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; }, - + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $A($(element).getElementsByTagName('*')).each(Element.extend); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (typeof selector == 'string') + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + var ancestors = $(element).ancestors(); + return expression ? Selector.findElement(ancestors, expression, index) : + ancestors[index || 0]; + }, + + down: function(element, expression, index) { + var descendants = $(element).descendants(); + return expression ? Selector.findElement(descendants, expression, index) : + descendants[index || 0]; + }, + + previous: function(element, expression, index) { + var previousSiblings = $(element).previousSiblings(); + return expression ? Selector.findElement(previousSiblings, expression, index) : + previousSiblings[index || 0]; + }, + + next: function(element, expression, index) { + var nextSiblings = $(element).nextSiblings(); + return expression ? Selector.findElement(nextSiblings, expression, index) : + nextSiblings[index || 0]; + }, + + getElementsBySelector: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + getElementsByClassName: function(element, className) { + return document.getElementsByClassName(className, element); + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + if (!element.attributes) return null; + var t = Element._attributeTranslations; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + var attribute = element.attributes[name]; + return attribute ? attribute.nodeValue : null; + } + return element.getAttribute(name); + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + classNames: function(element) { return new Element.ClassNames(element); }, hasClassName: function(element, className) { if (!(element = $(element))) return; - return Element.classNames(element).include(className); + var elementClassName = element.className; + if (elementClassName.length == 0) return false; + if (elementClassName == className || + elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + return true; + return false; }, addClassName: function(element, className) { if (!(element = $(element))) return; - return Element.classNames(element).add(className); + Element.classNames(element).add(className); + return element; }, removeClassName: function(element, className) { if (!(element = $(element))) return; - return Element.classNames(element).remove(className); + Element.classNames(element).remove(className); + return element; }, - + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); + return element; + }, + + observe: function() { + Event.observe.apply(Event, arguments); + return $A(arguments).first(); + }, + + stopObserving: function() { + Event.stopObserving.apply(Event, arguments); + return $A(arguments).first(); + }, + // removes whitespace-only text node children cleanWhitespace: function(element) { element = $(element); - for (var i = 0; i < element.childNodes.length; i++) { - var node = element.childNodes[i]; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - Element.remove(node); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; } + return element; }, - + empty: function(element) { - return $(element).innerHTML.match(/^\s*$/); + return $(element).innerHTML.blank(); }, - - childOf: function(element, ancestor) { + + descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); while (element = element.parentNode) if (element == ancestor) return true; return false; }, - + scrollTo: function(element) { element = $(element); - var x = element.x ? element.x : element.offsetLeft, - y = element.y ? element.y : element.offsetTop; - window.scrollTo(x, y); + var pos = Position.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; }, - + getStyle: function(element, style) { element = $(element); - var value = element.style[style.camelize()]; + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; if (!value) { - if (document.defaultView && document.defaultView.getComputedStyle) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css.getPropertyValue(style) : null; - } else if (element.currentStyle) { - value = element.currentStyle[style.camelize()]; - } + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) - if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, - return value == 'auto' ? null : value; + setStyle: function(element, styles, camelized) { + element = $(element); + var elementStyle = element.style; + + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]) + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') : + (camelized ? property : property.camelize())] = styles[property]; + + return element; }, - - setStyle: function(element, style) { + + setOpacity: function(element, value) { element = $(element); - for (var name in style) - element.style[name.camelize()] = style[name]; + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; }, - + getDimensions: function(element) { element = $(element); - if (Element.getStyle(element, 'display') != 'none') + 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 = ''; + els.display = 'block'; var originalWidth = element.clientWidth; var originalHeight = element.clientHeight; - els.display = 'none'; + els.display = originalDisplay; els.position = originalPosition; els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; + return {width: originalWidth, height: originalHeight}; }, - + makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); @@ -1115,8 +1601,9 @@ Element.Methods = { if (window.opera) { element.style.top = 0; element.style.left = 0; - } + } } + return element; }, undoPositioned: function(element) { @@ -1127,53 +1614,253 @@ Element.Methods = { element.style.top = element.style.left = element.style.bottom = - element.style.right = ''; + element.style.right = ''; } + return element; }, makeClipping: function(element) { element = $(element); - if (element._overflow) return; - element._overflow = element.style.overflow; + if (element._overflow) return element; + element._overflow = element.style.overflow || 'auto'; if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') element.style.overflow = 'hidden'; + return element; }, undoClipping: function(element) { element = $(element); - if (element._overflow) return; - element.style.overflow = element._overflow; - element._overflow = undefined; + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; } +}; + +Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf}); + +if (Prototype.Browser.Opera) { + Element.Methods._getStyle = Element.Methods.getStyle; + Element.Methods.getStyle = function(element, style) { + switch(style) { + case 'left': + case 'top': + case 'right': + case 'bottom': + if (Element._getStyle(element, 'position') == 'static') return null; + default: return Element._getStyle(element, style); + } + }; } +else if (Prototype.Browser.IE) { + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } -Object.extend(Element, Element.Methods); + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset'+style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + element = $(element); + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + style.filter = filter.replace(/alpha\([^\)]*\)/gi,''); + return element; + } else if (value < 0.00001) value = 0; + style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; -var _nativeExtensions = false; + // IE is missing .innerHTML support for TABLE-related elements + Element.Methods.update = function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + var tagName = element.tagName.toUpperCase(); + if (['THEAD','TBODY','TR','TD'].include(tagName)) { + var div = document.createElement('div'); + switch (tagName) { + case 'THEAD': + case 'TBODY': + div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>'; + depth = 2; + break; + case 'TR': + div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>'; + depth = 3; + break; + case 'TD': + div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>'; + depth = 4; + } + $A(element.childNodes).each(function(node) { element.removeChild(node) }); + depth.times(function() { div = div.firstChild }); + $A(div.childNodes).each(function(node) { element.appendChild(node) }); + } else { + element.innerHTML = html.stripScripts(); + } + setTimeout(function() { html.evalScripts() }, 10); + return element; + } +} +else if (Prototype.Browser.Gecko) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +Element._attributeTranslations = { + names: { + colspan: "colSpan", + rowspan: "rowSpan", + valign: "vAlign", + datetime: "dateTime", + accesskey: "accessKey", + tabindex: "tabIndex", + enctype: "encType", + maxlength: "maxLength", + readonly: "readOnly", + longdesc: "longDesc" + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + var node = element.getAttributeNode('title'); + return node.specified ? node.nodeValue : null; + } + } +}; + +(function() { + Object.extend(this, { + href: this._getAttr, + src: this._getAttr, + disabled: this._flag, + checked: this._flag, + readonly: this._flag, + multiple: this._flag + }); +}).call(Element._attributeTranslations.values); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + var t = Element._attributeTranslations, node; + attribute = t.names[attribute] || attribute; + node = $(element).getAttributeNode(attribute); + return node && node.specified; + } +}; + +Element.Methods.ByTag = {}; -if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - var HTMLElement = {} - HTMLElement.prototype = document.createElement('div').__proto__; +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; } +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + Element.addMethods = function(methods) { - Object.extend(Element.Methods, methods || {}); - - if(typeof HTMLElement != 'undefined') { - var methods = Element.Methods, cache = Element.extend.cache; - for (property in methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || {}); + else { + if (tagName.constructor == Array) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = {}; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + var cache = Element.extend.cache; + for (var property in methods) { var value = methods[property]; - if (typeof value == 'function') - HTMLElement.prototype[property] = cache.findOrStore(value); + if (!onlyIfAbsent || !(property in destination)) + destination[property] = cache.findOrStore(value); } - _nativeExtensions = true; } -} -Element.addMethods(); + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + window[klass] = {}; + window[klass].prototype = document.createElement(tagName).__proto__; + return window[klass]; + } -var Toggle = new Object(); -Toggle.display = Element.toggle; + if (F.ElementExtensions) { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (typeof klass == "undefined") continue; + copy(T[tag], klass.prototype); + } + } +}; + +var Toggle = { display: Element.toggle }; /*--------------------------------------------------------------------------*/ @@ -1185,13 +1872,13 @@ Abstract.Insertion.prototype = { initialize: function(element, content) { this.element = $(element); this.content = content.stripScripts(); - + if (this.adjacency && this.element.insertAdjacentHTML) { try { this.element.insertAdjacentHTML(this.adjacency, this.content); } catch (e) { - var tagName = this.element.tagName.toLowerCase(); - if (tagName == 'tbody' || tagName == 'tr') { + var tagName = this.element.tagName.toUpperCase(); + if (['TBODY', 'TR'].include(tagName)) { this.insertContent(this.contentFromAnonymousTable()); } else { throw e; @@ -1203,9 +1890,9 @@ Abstract.Insertion.prototype = { this.insertContent([this.range.createContextualFragment(this.content)]); } - setTimeout(function() {content.evalScripts()}, 10); + setTimeout(function() {content.evalScripts()}, 10); }, - + contentFromAnonymousTable: function() { var div = document.createElement('div'); div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>'; @@ -1220,7 +1907,7 @@ Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin') initializeRange: function() { this.range.setStartBefore(this.element); }, - + insertContent: function(fragments) { fragments.each((function(fragment) { this.element.parentNode.insertBefore(fragment, this.element); @@ -1234,7 +1921,7 @@ Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { this.range.selectNodeContents(this.element); this.range.collapse(true); }, - + insertContent: function(fragments) { fragments.reverse(false).each((function(fragment) { this.element.insertBefore(fragment, this.element.firstChild); @@ -1248,7 +1935,7 @@ Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), this.range.selectNodeContents(this.element); this.range.collapse(this.element); }, - + insertContent: function(fragments) { fragments.each((function(fragment) { this.element.appendChild(fragment); @@ -1261,10 +1948,10 @@ Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { initializeRange: function() { this.range.setStartAfter(this.element); }, - + insertContent: function(fragments) { fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, + this.element.parentNode.insertBefore(fragment, this.element.nextSibling); }).bind(this)); } @@ -1283,241 +1970,838 @@ Element.ClassNames.prototype = { return name.length > 0; })._each(iterator); }, - + set: function(className) { this.element.className = className; }, - + add: function(classNameToAdd) { if (this.include(classNameToAdd)) return; - this.set(this.toArray().concat(classNameToAdd).join(' ')); + this.set($A(this).concat(classNameToAdd).join(' ')); }, - + remove: function(classNameToRemove) { if (!this.include(classNameToRemove)) return; - this.set(this.select(function(className) { - return className != classNameToRemove; - }).join(' ')); + this.set($A(this).without(classNameToRemove).join(' ')); }, - + toString: function() { - return this.toArray().join(' '); + return $A(this).join(' '); } -} +}; Object.extend(Element.ClassNames.prototype, Enumerable); +/* 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(); -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; +Selector.prototype = { + initialize: function(expression) { + this.expression = expression.strip(); + this.compileMatcher(); }, - focus: function(element) { - $(element).focus(); + compileMatcher: function() { + // Selectors with namespaced attributes can't use the XPath version + if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression)) + return this.compileXPathMatcher(); + + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; return; + } + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + 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(typeof c[i] == 'function' ? c[i](m) : + new Template(c[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.matcher.push("return h.unique(n);\n}"); + eval(this.matcher.join('\n')); + Selector._cache[this.expression] = this.matcher; }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; + + compileXPathMatcher: function() { + var e = this.expression, ps = Selector.patterns, + x = Selector.xpath, le, p, m; + + if (Selector._cache[e]) { + this.xpath = Selector._cache[e]; return; + } + + 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(typeof x[i] == 'function' ? x[i](m) : + new Template(x[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.xpath = this.matcher.join(''); + Selector._cache[this.expression] = this.xpath; }, - - select: function(element) { - $(element).select(); + + findElements: function(root) { + root = root || document; + if (this.xpath) return document._getElementsByXPath(this.xpath, root); + return this.matcher(root); }, - - activate: function(element) { - element = $(element); - element.focus(); - if (element.select) - element.select(); + + match: function(element) { + return this.findElements(document).include(element); + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#<Selector:" + this.expression.inspect() + ">"; } -} +}; -/*--------------------------------------------------------------------------*/ +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() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: "[@#{1}]", + attr: function(m) { + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (typeof h === 'function') return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + 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}-')]" + }, + 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 or translate(text(), ' \t\r\n', '') = '')]", + 'checked': "[@checked]", + 'disabled': "[@disabled]", + 'enabled': "[not(@disabled)]", + 'not': function(m) { + if (!m[6]) return ''; + var p = Selector.patterns, x = Selector.xpath; + for (var i in p) { + if (mm = m[6].match(p[i])) { + var ss = typeof x[i] == 'function' ? x[i](mm) : new Template(x[i]).evaluate(mm); + m[6] = ss.substring(1, ss.length - 1); + break; + } + } + return "[not(" + m[6] + ")]"; + }, + 'nth-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + }, + 'nth-last-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + }, + 'nth-of-type': function(m) { + return Selector.xpath.pseudos.nth("position() ", m); + }, + 'nth-last-of-type': function(m) { + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + }, + 'first-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + }, + 'last-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + }, + 'only-of-type': function(m) { + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + }, + nth: function(predicate, m) { + var mm, formula = m[6]; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + if (mm = formula.match(/^(\d+)$/)) // digit only + predicate += "= " + mm[1]; + if (mm = formula.match(/^(\d+)?n(\+(\d+))?/)) { // an+b + var a = mm[1] ? Number(mm[1]) : 1; + var b = mm[3] ? Number(mm[3]) : 0; + predicate += "mod " + a + " = " + b; + } + return "[" + predicate + "]"; + } + } + }, -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); + 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 = false;', + attr: function(m) { + m[3] = m[5] || m[6]; + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); + }, + pseudo: 'n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;', + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + 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|$)/, + attrPresence: /^\[([\w]+)\]/, + attr: new RegExp(/\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/) + }, + + handlers: { + // UTILITY FUNCTIONS + // joins two collections + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + // marks an array of nodes for counting + mark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = undefined; + return nodes; + }, + + // 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._counted = true; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + }, + + // 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])._counted) { + n._counted = true; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + // COMBINATOR FUNCTIONS + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.descendants(node)); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.immediateDescendants(node)); + return results; + }, + + 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; + }, + + 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; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + // TOKEN FUNCTIONS + tagName: function(nodes, root, tagName, combinator) { + tagName = 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() == tagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + if (!nodes && root == document) return targetNode ? [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] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + 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); + } + return results; + }, + + attrPresence: function(nodes, root, attr) { + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator) { + 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 (combinator) nodes = this[combinator](nodes); + return Selector.pseudos[name](nodes, value, root); } - - return queryComponents.join('&'); }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - for (var tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); + 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); + }, + + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type + nth: function(nodes, formula, root, reverse, ofType) { + 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._counted) { + 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 + var a = m[1] ? Number(m[1]) : 1; + var b = m[3] ? Number(m[3]) : 0; + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex % a == b) results.push(node); + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + '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 && !node.innerHTML.match(/^\s*$/))) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, exclusions = $A(nodes), selectorType, m; + for (var i in Selector.patterns) { + if (m = selector.match(Selector.patterns[i])) { + selectorType = i; break; + } + } + switch(selectorType) { + case 'className': case 'tagName': case 'id': // fallthroughs + case 'attrPresence': exclusions = h[selectorType](exclusions, root, m[1], false); break; + case 'attr': m[3] = m[5] || m[6]; exclusions = h.attr(exclusions, root, m[1], m[3], m[2]); break; + case 'pseudo': exclusions = h.pseudo(exclusions, m[1], m[6], root, false); break; + // only 'simple selectors' (one token) allowed in a :not clause + default: throw 'Illegal selector in :not clause.'; + } + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._counted) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled) results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; } - return elements; }, - + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv.startsWith(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() + '-'); } + }, + + matchElements: function(elements, expression) { + var matches = new Selector(expression).findElements(), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._counted) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (typeof expression == 'number') { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + var exprs = expressions.join(','), expressions = []; + exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + 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)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, getHash) { + var data = elements.inject({}, function(result, element) { + if (!element.disabled && element.name) { + var key = element.name, value = $(element).getValue(); + if (value != null) { + if (key in result) { + if (result[key].constructor != Array) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return getHash ? data : Hash.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, getHash) { + return Form.serializeElements(Form.getElements(form), getHash); + }, + + 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; + } + ); + }, + getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) - return inputs; - - var matchingInputs = new Array(); - for (var i = 0; i < inputs.length; i++) { + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { var input = inputs[i]; - if ((typeName && input.type != typeName) || - (name && input.name != name)) + if ((typeName && input.type != typeName) || (name && input.name != name)) continue; - matchingInputs.push(input); + matchingInputs.push(Element.extend(input)); } return matchingInputs; }, disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; + form = $(form); + form.getElements().each(function(element) { element.blur(); element.disabled = 'true'; - } + }); + return form; }, enable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; + form = $(form); + form.getElements().each(function(element) { element.disabled = ''; - } + }); + return form; }, findFirstElement: function(form) { - return Form.getElements(form).find(function(element) { + return $(form).getElements().find(function(element) { return element.type != 'hidden' && !element.disabled && ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); }); }, focusFirstElement: function(form) { - Field.activate(Form.findFirstElement(form)); + form = $(form); + form.findFirstElement().activate(); + return form; }, - reset: function(form) { - $(form).reset(); + request: function(form, options) { + form = $(form), options = Object.clone(options || {}); + + var params = options.parameters; + options.parameters = form.serialize(true); + + if (params) { + if (typeof params == 'string') params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(form.action, options); } } +Object.extend(Form, Form.Methods); + +/*--------------------------------------------------------------------------*/ + Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +} + +Form.Element.Methods = { serialize: function(element) { element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) { - var key = encodeURIComponent(parameter[0]); - if (key.length == 0) return; - - if (parameter[1].constructor != Array) - parameter[1] = [parameter[1]]; - - return parameter[1].map(function(value) { - return key + '=' + encodeURIComponent(value); - }).join('&'); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = {}; + pair[element.name] = value; + return Hash.toQueryString(pair); + } } + return ''; }, - + getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; + return Form.Element.Serializers[method](element); + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) {} + return element; + }, + + disable: function(element) { + element = $(element); + element.blur(); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; } } +Object.extend(Form.Element, Form.Element.Methods); +Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) +}); + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + Form.Element.Serializers = { input: function(element) { switch (element.type.toLowerCase()) { - case 'submit': - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': + case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element); + default: + return Form.Element.Serializers.textarea(element); } - return false; }, inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; + return element.checked ? element.value : null; }, textarea: function(element) { - return [element.name, element.value]; + return element.value; }, - + select: function(element) { - return Form.Element.Serializers[element.type == 'select-one' ? + return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); }, - + selectOne: function(element) { - var value = '', opt, index = element.selectedIndex; - if (index >= 0) { - opt = element.options[index]; - value = opt.value || opt.text; - } - return [element.name, value]; + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; }, - + selectMany: function(element) { - var value = []; - for (var i = 0; i < element.length; i++) { + 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) - value.push(opt.value || opt.text); + if (opt.selected) values.push(this.optionValue(opt)); } - return [element.name, value]; + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } } /*--------------------------------------------------------------------------*/ -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - Abstract.TimedObserver = function() {} Abstract.TimedObserver.prototype = { initialize: function(element, frequency, callback) { this.frequency = frequency; this.element = $(element); this.callback = callback; - + this.lastValue = this.getValue(); this.registerCallback(); }, - + registerCallback: function() { setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, - + onTimerEvent: function() { var value = this.getValue(); - if (this.lastValue != value) { + var changed = ('string' == typeof this.lastValue && 'string' == typeof value + ? this.lastValue != value : String(this.lastValue) != String(value)); + if (changed) { this.callback(this.element, value); this.lastValue = value; } @@ -1545,14 +2829,14 @@ Abstract.EventObserver.prototype = { initialize: function(element, callback) { this.element = $(element); this.callback = callback; - + this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, - + onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { @@ -1560,29 +2844,23 @@ Abstract.EventObserver.prototype = { this.lastValue = value; } }, - + registerFormCallbacks: function() { - var elements = Form.getElements(this.element); - for (var i = 0; i < elements.length; i++) - this.registerCallback(elements[i]); + Form.getElements(this.element).each(this.registerCallback.bind(this)); }, - + registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { - case 'checkbox': + case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; - case 'password': - case 'text': - case 'textarea': - case 'select-one': - case 'select-multiple': + default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } - } + } } } @@ -1599,9 +2877,6 @@ Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { return Form.serialize(this.element); } }); - - - if (!window.Event) { var Event = new Object(); } @@ -1616,7 +2891,10 @@ Object.extend(Event, { KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, - KEY_SPACEBAR: 32, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, element: function(event) { return event.target || event.srcElement; @@ -1628,19 +2906,19 @@ Object.extend(Event, { }, pointerX: function(event) { - return event.pageX || (event.clientX + + return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)); }, pointerY: function(event) { - return event.pageY || (event.clientY + + return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)); }, stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); } else { event.returnValue = false; event.cancelBubble = true; @@ -1658,7 +2936,7 @@ Object.extend(Event, { }, observers: false, - + _observeAndCache: function(element, name, observer, useCapture) { if (!this.observers) this.observers = []; if (element.addEventListener) { @@ -1669,10 +2947,10 @@ Object.extend(Event, { element.attachEvent('on' + name, observer); } }, - + unloadCache: function() { if (!Event.observers) return; - for (var i = 0; i < Event.observers.length; i++) { + for (var i = 0, length = Event.observers.length; i < length; i++) { Event.stopObserving.apply(this, Event.observers[i]); Event.observers[i][0] = null; } @@ -1680,165 +2958,53 @@ Object.extend(Event, { }, observe: function(element, name, observer, useCapture) { - var element = $(element); + element = $(element); useCapture = useCapture || false; - + if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) + (Prototype.Browser.WebKit || element.attachEvent)) name = 'keydown'; - - this._observeAndCache(element, name, observer, useCapture); + + Event._observeAndCache(element, name, observer, useCapture); }, stopObserving: function(element, name, observer, useCapture) { - var element = $(element); + element = $(element); useCapture = useCapture || false; - + if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.detachEvent)) + (Prototype.Browser.WebKit || element.attachEvent)) name = 'keydown'; - + if (element.removeEventListener) { element.removeEventListener(name, observer, useCapture); } else if (element.detachEvent) { - element.detachEvent('on' + name, observer); + try { + element.detachEvent('on' + name, observer); + } catch (e) {} } } }); /* prevent memory leaks in IE */ -if (navigator.appVersion.match(/\bMSIE\b/)) +if (Prototype.Browser.IE) Event.observe(window, 'unload', Event.unloadCache, false); - - -/**
- * @class Event extensions.
- */
-Object.extend(Event,
-{
- /**
- * Register a function to be executed when the page is loaded.
- * Note that the page is only loaded if all resources (e.g. images)
- * are loaded.
- *
- * Example: Show an alert box with message "Page Loaded!" when the
- * page finished loading.
- * <code>
- * Event.OnLoad(function(){ alert("Page Loaded!"); });
- * </code>
- *
- * @param {Function} function to execute when page is loaded.
- */
- OnLoad : function (fn)
- {
- // opera onload is in document, not window
- var w = document.addEventListener &&
- !window.addEventListener ? document : window;
- Event.observe(w,'load',fn);
- },
-
- /**
- * @param {Event} a keyboard event
- * @return {Number} the Unicode character code generated by the key
- * that was struck.
- */
- keyCode : function(e)
- {
- return e.keyCode != null ? e.keyCode : e.charCode
- },
-
- /**
- * @param {String} event type or event name.
- * @return {Boolean} true if event type is of HTMLEvent, false
- * otherwise
- */
- isHTMLEvent : function(type)
- {
- var events = ['abort', 'blur', 'change', 'error', 'focus',
- 'load', 'reset', 'resize', 'scroll', 'select',
- 'submit', 'unload'];
- return events.include(type);
- },
-
- /**
- * @param {String} event type or event name
- * @return {Boolean} true if event type is of MouseEvent,
- * false otherwise
- */
- isMouseEvent : function(type)
- {
- var events = ['click', 'mousedown', 'mousemove', 'mouseout',
- 'mouseover', 'mouseup'];
- return events.include(type);
- },
-
- /**
- * Dispatch the DOM event of a given <tt>type</tt> on a DOM
- * <tt>element</tt>. Only HTMLEvent and MouseEvent can be
- * dispatched, keyboard events or UIEvent can not be dispatch
- * via javascript consistently.
- * For the "submit" event the submit() method is called.
- * @param {Object} element id string or a DOM element.
- * @param {String} event type to dispatch.
- */
- fireEvent : function(element,type)
- {
- element = $(element);
- if(type == "submit")
- return element.submit();
- if(document.createEvent)
- {
- if(Event.isHTMLEvent(type))
- {
- var event = document.createEvent('HTMLEvents');
- event.initEvent(type, true, true);
- }
- else if(Event.isMouseEvent(type))
- {
- var event = document.createEvent('MouseEvents');
- if (event.initMouseEvent)
- {
- event.initMouseEvent(type,true,true,
- document.defaultView, 1, 0, 0, 0, 0, false,
- false, false, false, 0, null);
- }
- else
- {
- // Safari
- // TODO we should be initialising other mouse-event related attributes here
- event.initEvent(type, true, true);
- }
- }
- element.dispatchEvent(event);
- }
- else if(document.createEventObject)
- {
- var evObj = document.createEventObject();
- element.fireEvent('on'+type, evObj);
- }
- else if(typeof(element['on'+type]) == "function")
- element['on'+type]();
- }
-}); - 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, + includeScrollOffsets: false, // must be called before calling withinIncludingScrolloffset, every time the // page is scrolled prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop || 0; }, @@ -1846,7 +3012,7 @@ var Position = { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; + valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return [valueL, valueT]; @@ -1869,13 +3035,14 @@ var Position = { valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { - p = Element.getStyle(element, 'position'); + if(element.tagName=='BODY') break; + var p = Element.getStyle(element, 'position'); if (p == 'relative' || p == 'absolute') break; } } while (element); return [valueL, valueT]; }, - + offsetParent: function(element) { if (element.offsetParent) return element.offsetParent; if (element == document.body) return element; @@ -1886,7 +3053,7 @@ var Position = { return document.body; }, - + // caches x/y coordinate pair to use with overlap within: function(element, x, y) { if (this.includeScrollOffsets) @@ -1897,7 +3064,7 @@ var Position = { return (y >= this.offset[1] && y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && + x >= this.offset[0] && x < this.offset[0] + element.offsetWidth); }, @@ -1910,32 +3077,21 @@ var Position = { return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && + this.xcomp >= this.offset[0] && this.xcomp < this.offset[0] + element.offsetWidth); }, // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / element.offsetHeight; if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / element.offsetWidth; }, - clone: function(source, target) { - source = $(source); - target = $(target); - target.style.position = 'absolute'; - var offsets = this.cumulativeOffset(source); - target.style.top = offsets[1] + 'px'; - target.style.left = offsets[0] + 'px'; - target.style.width = source.offsetWidth + 'px'; - target.style.height = source.offsetHeight + 'px'; - }, - page: function(forElement) { var valueT = 0, valueL = 0; @@ -1945,15 +3101,17 @@ var Position = { valueL += element.offsetLeft || 0; // Safari fix - if (element.offsetParent==document.body) + if (element.offsetParent == document.body) if (Element.getStyle(element,'position')=='absolute') break; } while (element = element.offsetParent); element = forElement; do { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; + if (!window.opera || element.tagName=='BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } } while (element = element.parentNode); return [valueL, valueT]; @@ -1977,7 +3135,7 @@ var Position = { target = $(target); var delta = [0, 0]; var parent = null; - // delta [0,0] will do fine with position: fixed elements, + // delta [0,0] will do fine with position: fixed elements, // position:absolute needs offsetParent deltas if (Element.getStyle(target,'position') == 'absolute') { parent = Position.offsetParent(target); @@ -1987,7 +3145,7 @@ var Position = { // correct by body offsets (fixes Safari) if (parent == document.body) { delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; + delta[1] -= document.body.offsetTop; } // set position @@ -2014,10 +3172,10 @@ var Position = { 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';; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; }, relativize: function(element) { @@ -2039,7 +3197,7 @@ var Position = { // Safari returns margins on body which is incorrect if the child is absolutely // positioned. For performance reasons, redefine Position.cumulativeOffset for // KHTML/WebKit only. -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { +if (Prototype.Browser.WebKit) { Position.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { @@ -2047,132 +3205,22 @@ if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { valueL += element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; - + element = element.offsetParent; } while (element); - - return [valueL, valueT]; - } -} - - - - -var Selector = Class.create(); -Selector.prototype = { - initialize: function(expression) { - this.params = {classNames: []}; - this.expression = expression.toString().strip(); - this.parseExpression(); - this.compileMatcher(); - }, - - parseExpression: function() { - function abort(message) { throw 'Parse error in selector: ' + message; } - - if (this.expression == '') abort('empty expression'); - - var params = this.params, expr = this.expression, match, modifier, clause, rest; - while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { - params.attributes = params.attributes || []; - params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); - expr = match[1]; - } - - if (expr == '*') return this.params.wildcard = true; - - while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { - modifier = match[1], clause = match[2], rest = match[3]; - switch (modifier) { - case '#': params.id = clause; break; - case '.': params.classNames.push(clause); break; - case '': - case undefined: params.tagName = clause.toUpperCase(); break; - default: abort(expr.inspect()); - } - expr = rest; - } - - if (expr.length > 0) abort(expr.inspect()); - }, - - buildMatchExpression: function() { - var params = this.params, conditions = [], clause; - - if (params.wildcard) - conditions.push('true'); - if (clause = params.id) - conditions.push('element.id == ' + clause.inspect()); - if (clause = params.tagName) - conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); - if ((clause = params.classNames).length > 0) - for (var i = 0; i < clause.length; i++) - conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')'); - if (clause = params.attributes) { - clause.each(function(attribute) { - var value = 'element.getAttribute(' + attribute.name.inspect() + ')'; - var splitValueBy = function(delimiter) { - return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; - } - - switch (attribute.operator) { - case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; - case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; - case '|=': conditions.push( - splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() - ); break; - case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; - case '': - case undefined: conditions.push(value + ' != null'); break; - default: throw 'Unknown operator ' + attribute.operator + ' in selector'; - } - }); - } - return conditions.join(' && '); - }, - - compileMatcher: function() { - this.match = new Function('element', 'if (!element.tagName) return false; \ - return ' + this.buildMatchExpression()); - }, - - findElements: function(scope) { - var element; - - if (element = $(this.params.id)) - if (this.match(element)) - if (!scope || Element.childOf(element, scope)) - return [element]; - - scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); - - var results = []; - for (var i = 0; i < scope.length; i++) - if (this.match(element = scope[i])) - results.push(Element.extend(element)); - - return results; - }, - - toString: function() { - return this.expression; + return [valueL, valueT]; } } -function $$() { - return $A(arguments).map(function(expression) { - return expression.strip().split(/\s+/).inject([null], function(results, expr) { - var selector = new Selector(expr); - return results.map(selector.findElements.bind(selector)).flatten(); - }); - }).flatten(); -} +Element.addMethods(); +// script.aculo.us builder.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // -// See scriptaculous.js for full license. +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ var Builder = { NODEMAP: { @@ -2205,7 +3253,7 @@ var Builder = { var element = parentElement.firstChild || null; // see if browser added wrapping tags - if(element && (element.tagName != elementName)) + if(element && (element.tagName.toUpperCase() != elementName)) element = element.getElementsByTagName(elementName)[0]; // fallback to createElement approach @@ -2233,7 +3281,7 @@ var Builder = { for(attr in arguments[1]) element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; } - if(element.tagName != elementName) + if(element.tagName.toUpperCase() != elementName) element = parentElement.getElementsByTagName(elementName)[0]; } } @@ -2247,10 +3295,16 @@ var Builder = { _text: function(text) { return document.createTextNode(text); }, + + ATTR_MAP: { + 'className': 'class', + 'htmlFor': 'for' + }, + _attributes: function(attributes) { var attrs = []; for(attribute in attributes) - attrs.push((attribute=='className' ? 'class' : attribute) + + attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + '="' + attributes[attribute].toString().escapeHTML() + '"'); return attrs.join(" "); }, @@ -2269,34 +3323,450 @@ var Builder = { }, _isStringOrNumber: function(param) { return(typeof param=='string' || typeof param=='number'); + }, + build: function(html) { + var element = this.node('div'); + $(element).update(html.strip()); + return element.down(); + }, + dump: function(scope) { + if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope + + var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + + "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + + "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ + "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ + "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ + "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); + + tags.each( function(tag){ + scope[tag] = function() { + return Builder.node.apply(Builder, [tag].concat($A(arguments))); + } + }); } } + -Object.extend(Builder,
+/**
+ * Similar to bindAsEventLister, but takes additional arguments.
+ */
+Function.prototype.bindEvent = function()
{
- exportTags:function()
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event)
{
- var tags=["BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG", "CAPTION"];
- tags.each(function(tag)
- {
- window[tag]=function()
- {
- var args=$A(arguments);
- if(args.length==0)
- return Builder.node(tag,null);
- if(args.length==1)
- return Builder.node(tag,args[0]);
- if(args.length>1)
- return Builder.node(tag,args.shift(),args);
+ return __method.apply(object, [event || window.event].concat(args));
+ }
+}
- };
- });
+/**
+ * Creates a new function by copying function definition from
+ * the <tt>base</tt> and optional <tt>definition</tt>.
+ * @param function a base function to copy from.
+ * @param array additional definition
+ * @param function return a new function with definition from both
+ * <tt>base</tt> and <tt>definition</tt>.
+ */
+Class.extend = function(base, definition)
+{
+ var component = Class.create();
+ Object.extend(component.prototype, base.prototype);
+ if(definition)
+ Object.extend(component.prototype, definition);
+ return component;
+}
+
+/*
+ Base, version 1.0.2
+ Copyright 2006, Dean Edwards
+ License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+var Base = function() {
+ if (arguments.length) {
+ if (this == window) { // cast an object to this class
+ Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
+ } else {
+ this.extend(arguments[0]);
+ }
}
-});
+};
-Builder.exportTags();
+Base.version = "1.0.2";
+
+Base.prototype = {
+ extend: function(source, value) {
+ var extend = Base.prototype.extend;
+ if (arguments.length == 2) {
+ var ancestor = this[source];
+ // overriding?
+ if ((ancestor instanceof Function) && (value instanceof Function) &&
+ ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) {
+ var method = value;
+ // var _prototype = this.constructor.prototype;
+ // var fromPrototype = !Base._prototyping && _prototype[source] == ancestor;
+ value = function() {
+ var previous = this.base;
+ // this.base = fromPrototype ? _prototype[source] : ancestor;
+ this.base = ancestor;
+ var returnValue = method.apply(this, arguments);
+ this.base = previous;
+ return returnValue;
+ };
+ // point to the underlying method
+ value.valueOf = function() {
+ return method;
+ };
+ value.toString = function() {
+ return String(method);
+ };
+ }
+ return this[source] = value;
+ } else if (source) {
+ var _prototype = {toSource: null};
+ // do the "toString" and other methods manually
+ var _protected = ["toString", "valueOf"];
+ // if we are prototyping then include the constructor
+ if (Base._prototyping) _protected[2] = "constructor";
+ for (var i = 0; (name = _protected[i]); i++) {
+ if (source[name] != _prototype[name]) {
+ extend.call(this, name, source[name]);
+ }
+ }
+ // copy each of the source object's properties to this object
+ for (var name in source) {
+ if (!_prototype[name]) {
+ extend.call(this, name, source[name]);
+ }
+ }
+ }
+ return this;
+ },
+
+ base: function() {
+ // call this method from any other method to invoke that method's ancestor
+ }
+};
+
+Base.extend = function(_instance, _static) {
+ var extend = Base.prototype.extend;
+ if (!_instance) _instance = {};
+ // build the prototype
+ Base._prototyping = true;
+ var _prototype = new this;
+ extend.call(_prototype, _instance);
+ var constructor = _prototype.constructor;
+ _prototype.constructor = this;
+ delete Base._prototyping;
+ // create the wrapper for the constructor function
+ var klass = function() {
+ if (!Base._prototyping) constructor.apply(this, arguments);
+ this.constructor = klass;
+ };
+ klass.prototype = _prototype;
+ // build the class interface
+ klass.extend = this.extend;
+ klass.implement = this.implement;
+ klass.toString = function() {
+ return String(constructor);
+ };
+ extend.call(klass, _static);
+ // single instance
+ var object = constructor ? klass : _prototype;
+ // class initialisation
+ if (object.init instanceof Function) object.init();
+ return object;
+};
+
+Base.implement = function(_interface) {
+ if (_interface instanceof Function) _interface = _interface.prototype;
+ this.prototype.extend(_interface);
+};
+ + +/**
+ * @class String extensions
+ */
+Object.extend(String.prototype, {
+ /**
+ * @param {String} "left" to pad the string on the left, "right" to pad right.
+ * @param {Number} minimum string length.
+ * @param {String} character(s) to pad
+ * @return {String} padded character(s) on the left or right to satisfy minimum string length
+ */
+
+ pad : function(side, len, chr) {
+ if (!chr) chr = ' ';
+ var s = this;
+ var left = side.toLowerCase()=='left';
+ while (s.length<len) s = left? chr + s : s + chr;
+ return s;
+ },
+
+ /**
+ * @param {Number} minimum string length.
+ * @param {String} character(s) to pad
+ * @return {String} padded character(s) on the left to satisfy minimum string length
+ */
+ padLeft : function(len, chr) {
+ return this.pad('left',len,chr);
+ },
+
+ /**
+ * @param {Number} minimum string length.
+ * @param {String} character(s) to pad
+ * @return {String} padded character(s) on the right to satisfy minimum string length
+ */
+ padRight : function(len, chr) {
+ return this.pad('right',len,chr);
+ },
+
+ /**
+ * @param {Number} minimum string length.
+ * @return {String} append zeros to the left to satisfy minimum string length.
+ */
+ zerofill : function(len) {
+ return this.padLeft(len,'0');
+ },
+
+ /**
+ * @return {String} removed white spaces from both ends.
+ */
+ trim : function() {
+ return this.replace(/^\s+|\s+$/g,'');
+ },
+
+ /**
+ * @return {String} removed white spaces from the left end.
+ */
+ trimLeft : function() {
+ return this.replace(/^\s+/,'');
+ },
+
+ /**
+ * @return {String} removed white spaces from the right end.
+ */
+ trimRight : function() {
+ return this.replace(/\s+$/,'');
+ },
+
+ /**
+ * Convert period separated function names into a function reference.
+ * e.g. "Prado.AJAX.Callback.Action.setValue".toFunction() will return
+ * the actual function Prado.AJAX.Callback.Action.setValue()
+ * @return {Function} the corresponding function represented by the string.
+ */
+ toFunction : function()
+ {
+ var commands = this.split(/\./);
+ var command = window;
+ commands.each(function(action)
+ {
+ if(command[new String(action)])
+ command=command[new String(action)];
+ });
+ if(typeof(command) == "function")
+ return command;
+ else
+ {
+ if(typeof Logger != "undefined")
+ Logger.error("Missing function", this);
+
+ throw new Error ("Missing function '"+this+"'");
+ }
+ },
+
+ /**
+ * Convert a string into integer, returns null if not integer.
+ * @return {Number} null if string does not represent an integer.
+ */
+ toInteger : function()
+ {
+ var exp = /^\s*[-\+]?\d+\s*$/;
+ if (this.match(exp) == null)
+ return null;
+ var num = parseInt(this, 10);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Convert a string into a double/float value. <b>Internationalization
+ * is not supported</b>
+ * @param {String} the decimal character
+ * @return {Double} null if string does not represent a float value
+ */
+ toDouble : function(decimalchar)
+ {
+ if(this.length <= 0) return null;
+ decimalchar = decimalchar || ".";
+ var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$");
+ var m = this.match(exp);
+
+ if (m == null)
+ return null;
+ m[1] = m[1] || "";
+ m[2] = m[2] || "0";
+ m[4] = m[4] || "0";
+
+ var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4];
+ var num = parseFloat(cleanInput);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Convert strings that represent a currency value (e.g. a float with grouping
+ * characters) to float. E.g. "10,000.50" will become "10000.50". The number
+ * of dicimal digits, grouping and decimal characters can be specified.
+ * <i>The currency input format is <b>very</b> strict, null will be returned if
+ * the pattern does not match</i>.
+ * @param {String} the grouping character, default is ","
+ * @param {Number} number of decimal digits
+ * @param {String} the decimal character, default is "."
+ * @type {Double} the currency value as float.
+ */
+ toCurrency : function(groupchar, digits, decimalchar)
+ {
+ groupchar = groupchar || ",";
+ decimalchar = decimalchar || ".";
+ digits = typeof(digits) == "undefined" ? 2 : digits;
+
+ var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)"
+ + ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "")
+ + "\\s*$");
+ var m = this.match(exp);
+ if (m == null)
+ return null;
+ var intermed = m[2] + m[5] ;
+ var cleanInput = m[1] + intermed.replace(
+ new RegExp("(\\" + groupchar + ")", "g"), "")
+ + ((digits > 0) ? "." + m[7] : "");
+ var num = parseFloat(cleanInput);
+ return (isNaN(num) ? null : num);
+ },
+
+ /**
+ * Converts the string to a date by finding values that matches the
+ * date format pattern.
+ * @param string date format pattern, e.g. MM-dd-yyyy
+ * @return {Date} the date extracted from the string
+ */
+ toDate : function(format)
+ {
+ return Date.SimpleParse(this, format);
+ }
+}); +/**
+ * @class Event extensions.
+ */
+Object.extend(Event,
+{
+ /**
+ * Register a function to be executed when the page is loaded.
+ * Note that the page is only loaded if all resources (e.g. images)
+ * are loaded.
+ *
+ * Example: Show an alert box with message "Page Loaded!" when the
+ * page finished loading.
+ * <code>
+ * Event.OnLoad(function(){ alert("Page Loaded!"); });
+ * </code>
+ *
+ * @param {Function} function to execute when page is loaded.
+ */
+ OnLoad : function (fn)
+ {
+ // opera onload is in document, not window
+ var w = document.addEventListener &&
+ !window.addEventListener ? document : window;
+ Event.observe(w,'load',fn);
+ },
+
+ /**
+ * @param {Event} a keyboard event
+ * @return {Number} the Unicode character code generated by the key
+ * that was struck.
+ */
+ keyCode : function(e)
+ {
+ return e.keyCode != null ? e.keyCode : e.charCode
+ },
+
+ /**
+ * @param {String} event type or event name.
+ * @return {Boolean} true if event type is of HTMLEvent, false
+ * otherwise
+ */
+ isHTMLEvent : function(type)
+ {
+ var events = ['abort', 'blur', 'change', 'error', 'focus',
+ 'load', 'reset', 'resize', 'scroll', 'select',
+ 'submit', 'unload'];
+ return events.include(type);
+ },
+
+ /**
+ * @param {String} event type or event name
+ * @return {Boolean} true if event type is of MouseEvent,
+ * false otherwise
+ */
+ isMouseEvent : function(type)
+ {
+ var events = ['click', 'mousedown', 'mousemove', 'mouseout',
+ 'mouseover', 'mouseup'];
+ return events.include(type);
+ },
+
+ /**
+ * Dispatch the DOM event of a given <tt>type</tt> on a DOM
+ * <tt>element</tt>. Only HTMLEvent and MouseEvent can be
+ * dispatched, keyboard events or UIEvent can not be dispatch
+ * via javascript consistently.
+ * For the "submit" event the submit() method is called.
+ * @param {Object} element id string or a DOM element.
+ * @param {String} event type to dispatch.
+ */
+ fireEvent : function(element,type)
+ {
+ element = $(element);
+ if(type == "submit")
+ return element.submit();
+ if(document.createEvent)
+ {
+ if(Event.isHTMLEvent(type))
+ {
+ var event = document.createEvent('HTMLEvents');
+ event.initEvent(type, true, true);
+ }
+ else if(Event.isMouseEvent(type))
+ {
+ var event = document.createEvent('MouseEvents');
+ if (event.initMouseEvent)
+ {
+ event.initMouseEvent(type,true,true,
+ document.defaultView, 1, 0, 0, 0, 0, false,
+ false, false, false, 0, null);
+ }
+ else
+ {
+ // Safari
+ // TODO we should be initialising other mouse-event related attributes here
+ event.initEvent(type, true, true);
+ }
+ }
+ element.dispatchEvent(event);
+ }
+ else if(document.createEventObject)
+ {
+ var evObj = document.createEventObject();
+ element.fireEvent('on'+type, evObj);
+ }
+ else if(typeof(element['on'+type]) == "function")
+ element['on'+type]();
+ }
+}); Object.extend(Date.prototype,
@@ -2451,6 +3921,32 @@ Object.extend(Date, }); +Object.extend(Builder,
+{
+ exportTags:function()
+ {
+ var tags=["BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG", "CAPTION"];
+ tags.each(function(tag)
+ {
+ window[tag]=function()
+ {
+ var args=$A(arguments);
+ if(args.length==0)
+ return Builder.node(tag,null);
+ if(args.length==1)
+ return Builder.node(tag,args[0]);
+ if(args.length>1)
+ return Builder.node(tag,args.shift(),args);
+
+ };
+ });
+ }
+});
+
+Builder.exportTags();
+ + +
var Prado =
{
Version: '3.0.0',
@@ -2890,12 +4386,12 @@ Prado.WebUI.PostBackControl.prototype = initialize : function(options)
{
this.element = $(options['ID']);
-
+
/* if(options.CausesValidation && typeof(Prado.Validation) != 'undefined')
{
Prado.Validation.registerTarget(options);
}
-
+
//TODO: what do the following options do?
//options['PostBackUrl']
//options['ClientSubmit']
@@ -2918,7 +4414,7 @@ Prado.WebUI.TButton = Prado.WebUI.createPostBackComponent(); */
Prado.WebUI.PostBackControl = Class.create();
-Prado.WebUI.PostBackControl.prototype =
+Prado.WebUI.PostBackControl.prototype =
{
_elementOnClick : null, //capture the element's onclick function
@@ -2928,7 +4424,7 @@ Prado.WebUI.PostBackControl.prototype = if(this.onInit)
this.onInit(options);
},
-
+
onInit : function(options)
{
if(typeof(this.element.onclick)=="function")
@@ -2936,7 +4432,7 @@ Prado.WebUI.PostBackControl.prototype = this._elementOnClick = this.element.onclick;
this.element.onclick = null;
}
- Event.observe(this.element, "click", this.onClick.bindEvent(this,options));
+ Event.observe(this.element, "click", this.onClick.bindEvent(this,options));
},
onClick : function(event, options)
@@ -2970,18 +4466,13 @@ Prado.WebUI.TBulletedList = Class.extend(Prado.WebUI.PostBackControl); Prado.WebUI.TImageMap = Class.extend(Prado.WebUI.PostBackControl);
/**
- * TImageButton client-side behaviour. With validation, Firefox needs
+ * TImageButton client-side behaviour. With validation, Firefox needs
* to capture the x,y point of the clicked image in hidden form fields.
*/
Prado.WebUI.TImageButton = Class.extend(Prado.WebUI.PostBackControl);
Object.extend(Prado.WebUI.TImageButton.prototype,
{
/**
- * Only add the hidden inputs once.
- */
- hasXYInput : false,
-
- /**
* Override parent onPostBack function, tried to add hidden forms
* inputs to capture x,y clicked point.
*/
@@ -2994,7 +4485,7 @@ Object.extend(Prado.WebUI.TImageButton.prototype, }
Prado.PostBack(event, options);
},
-
+
/**
* Add hidden inputs to capture the x,y point clicked on the image.
* @param event DOM click event.
@@ -3010,7 +4501,7 @@ Object.extend(Prado.WebUI.TImageButton.prototype, var x_input = INPUT({type:'hidden',name:id+'_x',value:x});
var y_input = INPUT({type:'hidden',name:id+'_y',value:y});
this.element.parentNode.appendChild(x_input);
- this.element.parentNode.appendChild(y_input);
+ this.element.parentNode.appendChild(y_input);
}
});
@@ -3066,7 +4557,7 @@ Prado.WebUI.TListBox = Class.extend(Prado.WebUI.TListControl); Prado.WebUI.TDropDownList = Class.extend(Prado.WebUI.TListControl);
Prado.WebUI.DefaultButton = Class.create();
-Prado.WebUI.DefaultButton.prototype =
+Prado.WebUI.DefaultButton.prototype =
{
initialize : function(options)
{
@@ -3085,7 +4576,7 @@ Prado.WebUI.DefaultButton.prototype = if(defaultButton)
{
this.triggered = true;
- $('PRADO_POSTBACK_TARGET').value = this.options.EventTarget;
+ $('PRADO_POSTBACK_TARGET').value = this.options.EventTarget;
Event.fireEvent(defaultButton, this.options['Event']);
Event.stop(ev);
}
|