rlm@46: /* Prototype JavaScript framework, version 1.4.0 rlm@46: * (c) 2005 Sam Stephenson rlm@46: * rlm@46: * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff rlm@46: * against the source tree, available from the Prototype darcs repository. rlm@46: * rlm@46: * Prototype is freely distributable under the terms of an MIT-style license. rlm@46: * rlm@46: * For details, see the Prototype web site: http://prototype.conio.net/ rlm@46: * rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: var Prototype = { rlm@46: Version: '1.4.0', rlm@46: ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', rlm@46: rlm@46: emptyFunction: function() {}, rlm@46: K: function(x) {return x} rlm@46: } rlm@46: rlm@46: var Class = { rlm@46: create: function() { rlm@46: return function() { rlm@46: this.initialize.apply(this, arguments); rlm@46: } rlm@46: } rlm@46: } rlm@46: rlm@46: var Abstract = new Object(); rlm@46: rlm@46: Object.extend = function(destination, source) { rlm@46: for (property in source) { rlm@46: destination[property] = source[property]; rlm@46: } rlm@46: return destination; rlm@46: } rlm@46: rlm@46: Object.inspect = function(object) { rlm@46: try { rlm@46: if (object == undefined) return 'undefined'; rlm@46: if (object == null) return 'null'; rlm@46: return object.inspect ? object.inspect() : object.toString(); rlm@46: } catch (e) { rlm@46: if (e instanceof RangeError) return '...'; rlm@46: throw e; rlm@46: } rlm@46: } rlm@46: rlm@46: Function.prototype.bind = function() { rlm@46: var __method = this, args = $A(arguments), object = args.shift(); rlm@46: return function() { rlm@46: return __method.apply(object, args.concat($A(arguments))); rlm@46: } rlm@46: } rlm@46: rlm@46: Function.prototype.bindAsEventListener = function(object) { rlm@46: var __method = this; rlm@46: return function(event) { rlm@46: return __method.call(object, event || window.event); rlm@46: } rlm@46: } rlm@46: rlm@46: Object.extend(Number.prototype, { rlm@46: toColorPart: function() { rlm@46: var digits = this.toString(16); rlm@46: if (this < 16) return '0' + digits; rlm@46: return digits; rlm@46: }, rlm@46: rlm@46: succ: function() { rlm@46: return this + 1; rlm@46: }, rlm@46: rlm@46: times: function(iterator) { rlm@46: $R(0, this, true).each(iterator); rlm@46: return this; rlm@46: } rlm@46: }); rlm@46: rlm@46: var Try = { rlm@46: these: function() { rlm@46: var returnValue; rlm@46: rlm@46: for (var i = 0; i < arguments.length; i++) { rlm@46: var lambda = arguments[i]; rlm@46: try { rlm@46: returnValue = lambda(); rlm@46: break; rlm@46: } catch (e) {} rlm@46: } rlm@46: rlm@46: return returnValue; rlm@46: } rlm@46: } rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: var PeriodicalExecuter = Class.create(); rlm@46: PeriodicalExecuter.prototype = { rlm@46: initialize: function(callback, frequency) { rlm@46: this.callback = callback; rlm@46: this.frequency = frequency; rlm@46: this.currentlyExecuting = false; rlm@46: rlm@46: this.registerCallback(); rlm@46: }, rlm@46: rlm@46: registerCallback: function() { rlm@46: setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); rlm@46: }, rlm@46: rlm@46: onTimerEvent: function() { rlm@46: if (!this.currentlyExecuting) { rlm@46: try { rlm@46: this.currentlyExecuting = true; rlm@46: this.callback(); rlm@46: } finally { rlm@46: this.currentlyExecuting = false; rlm@46: } rlm@46: } rlm@46: } rlm@46: } rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: function $() { rlm@46: var elements = new Array(); rlm@46: rlm@46: for (var i = 0; i < arguments.length; i++) { rlm@46: var element = arguments[i]; rlm@46: if (typeof element == 'string') rlm@46: element = document.getElementById(element); rlm@46: rlm@46: if (arguments.length == 1) rlm@46: return element; rlm@46: rlm@46: elements.push(element); rlm@46: } rlm@46: rlm@46: return elements; rlm@46: } rlm@46: Object.extend(String.prototype, { rlm@46: stripTags: function() { rlm@46: return this.replace(/<\/?[^>]+>/gi, ''); rlm@46: }, rlm@46: rlm@46: stripScripts: function() { rlm@46: return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); rlm@46: }, rlm@46: rlm@46: extractScripts: function() { rlm@46: var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); rlm@46: var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); rlm@46: return (this.match(matchAll) || []).map(function(scriptTag) { rlm@46: return (scriptTag.match(matchOne) || ['', ''])[1]; rlm@46: }); rlm@46: }, rlm@46: rlm@46: evalScripts: function() { rlm@46: return this.extractScripts().map(eval); rlm@46: }, rlm@46: rlm@46: escapeHTML: function() { rlm@46: var div = document.createElement('div'); rlm@46: var text = document.createTextNode(this); rlm@46: div.appendChild(text); rlm@46: return div.innerHTML; rlm@46: }, rlm@46: rlm@46: unescapeHTML: function() { rlm@46: var div = document.createElement('div'); rlm@46: div.innerHTML = this.stripTags(); rlm@46: return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; rlm@46: }, rlm@46: rlm@46: toQueryParams: function() { rlm@46: var pairs = this.match(/^\??(.*)$/)[1].split('&'); rlm@46: return pairs.inject({}, function(params, pairString) { rlm@46: var pair = pairString.split('='); rlm@46: params[pair[0]] = pair[1]; rlm@46: return params; rlm@46: }); rlm@46: }, rlm@46: rlm@46: toArray: function() { rlm@46: return this.split(''); rlm@46: }, rlm@46: rlm@46: camelize: function() { rlm@46: var oStringList = this.split('-'); rlm@46: if (oStringList.length == 1) return oStringList[0]; rlm@46: rlm@46: var camelizedString = this.indexOf('-') == 0 rlm@46: ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) rlm@46: : oStringList[0]; rlm@46: rlm@46: for (var i = 1, len = oStringList.length; i < len; i++) { rlm@46: var s = oStringList[i]; rlm@46: camelizedString += s.charAt(0).toUpperCase() + s.substring(1); rlm@46: } rlm@46: rlm@46: return camelizedString; rlm@46: }, rlm@46: rlm@46: inspect: function() { rlm@46: return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; rlm@46: } rlm@46: }); rlm@46: rlm@46: String.prototype.parseQuery = String.prototype.toQueryParams; rlm@46: rlm@46: var $break = new Object(); rlm@46: var $continue = new Object(); rlm@46: rlm@46: var Enumerable = { rlm@46: each: function(iterator) { rlm@46: var index = 0; rlm@46: try { rlm@46: this._each(function(value) { rlm@46: try { rlm@46: iterator(value, index++); rlm@46: } catch (e) { rlm@46: if (e != $continue) throw e; rlm@46: } rlm@46: }); rlm@46: } catch (e) { rlm@46: if (e != $break) throw e; rlm@46: } rlm@46: }, rlm@46: rlm@46: all: function(iterator) { rlm@46: var result = true; rlm@46: this.each(function(value, index) { rlm@46: result = result && !!(iterator || Prototype.K)(value, index); rlm@46: if (!result) throw $break; rlm@46: }); rlm@46: return result; rlm@46: }, rlm@46: rlm@46: any: function(iterator) { rlm@46: var result = true; rlm@46: this.each(function(value, index) { rlm@46: if (result = !!(iterator || Prototype.K)(value, index)) rlm@46: throw $break; rlm@46: }); rlm@46: return result; rlm@46: }, rlm@46: rlm@46: collect: function(iterator) { rlm@46: var results = []; rlm@46: this.each(function(value, index) { rlm@46: results.push(iterator(value, index)); rlm@46: }); rlm@46: return results; rlm@46: }, rlm@46: rlm@46: detect: function (iterator) { rlm@46: var result; rlm@46: this.each(function(value, index) { rlm@46: if (iterator(value, index)) { rlm@46: result = value; rlm@46: throw $break; rlm@46: } rlm@46: }); rlm@46: return result; rlm@46: }, rlm@46: rlm@46: findAll: function(iterator) { rlm@46: var results = []; rlm@46: this.each(function(value, index) { rlm@46: if (iterator(value, index)) rlm@46: results.push(value); rlm@46: }); rlm@46: return results; rlm@46: }, rlm@46: rlm@46: grep: function(pattern, iterator) { rlm@46: var results = []; rlm@46: this.each(function(value, index) { rlm@46: var stringValue = value.toString(); rlm@46: if (stringValue.match(pattern)) rlm@46: results.push((iterator || Prototype.K)(value, index)); rlm@46: }) rlm@46: return results; rlm@46: }, rlm@46: rlm@46: include: function(object) { rlm@46: var found = false; rlm@46: this.each(function(value) { rlm@46: if (value == object) { rlm@46: found = true; rlm@46: throw $break; rlm@46: } rlm@46: }); rlm@46: return found; rlm@46: }, rlm@46: rlm@46: inject: function(memo, iterator) { rlm@46: this.each(function(value, index) { rlm@46: memo = iterator(memo, value, index); rlm@46: }); rlm@46: return memo; rlm@46: }, rlm@46: rlm@46: invoke: function(method) { rlm@46: var args = $A(arguments).slice(1); rlm@46: return this.collect(function(value) { rlm@46: return value[method].apply(value, args); rlm@46: }); rlm@46: }, rlm@46: rlm@46: max: function(iterator) { rlm@46: var result; rlm@46: this.each(function(value, index) { rlm@46: value = (iterator || Prototype.K)(value, index); rlm@46: if (value >= (result || value)) rlm@46: result = value; rlm@46: }); rlm@46: return result; rlm@46: }, rlm@46: rlm@46: min: function(iterator) { rlm@46: var result; rlm@46: this.each(function(value, index) { rlm@46: value = (iterator || Prototype.K)(value, index); rlm@46: if (value <= (result || value)) rlm@46: result = value; rlm@46: }); rlm@46: return result; rlm@46: }, rlm@46: rlm@46: partition: function(iterator) { rlm@46: var trues = [], falses = []; rlm@46: this.each(function(value, index) { rlm@46: ((iterator || Prototype.K)(value, index) ? rlm@46: trues : falses).push(value); rlm@46: }); rlm@46: return [trues, falses]; rlm@46: }, rlm@46: rlm@46: pluck: function(property) { rlm@46: var results = []; rlm@46: this.each(function(value, index) { rlm@46: results.push(value[property]); rlm@46: }); rlm@46: return results; rlm@46: }, rlm@46: rlm@46: reject: function(iterator) { rlm@46: var results = []; rlm@46: this.each(function(value, index) { rlm@46: if (!iterator(value, index)) rlm@46: results.push(value); rlm@46: }); rlm@46: return results; rlm@46: }, rlm@46: rlm@46: sortBy: function(iterator) { rlm@46: return this.collect(function(value, index) { rlm@46: return {value: value, criteria: iterator(value, index)}; rlm@46: }).sort(function(left, right) { rlm@46: var a = left.criteria, b = right.criteria; rlm@46: return a < b ? -1 : a > b ? 1 : 0; rlm@46: }).pluck('value'); rlm@46: }, rlm@46: rlm@46: toArray: function() { rlm@46: return this.collect(Prototype.K); rlm@46: }, rlm@46: rlm@46: zip: function() { rlm@46: var iterator = Prototype.K, args = $A(arguments); rlm@46: if (typeof args.last() == 'function') rlm@46: iterator = args.pop(); rlm@46: rlm@46: var collections = [this].concat(args).map($A); rlm@46: return this.map(function(value, index) { rlm@46: iterator(value = collections.pluck(index)); rlm@46: return value; rlm@46: }); rlm@46: }, rlm@46: rlm@46: inspect: function() { rlm@46: return '#'; rlm@46: } rlm@46: } rlm@46: rlm@46: Object.extend(Enumerable, { rlm@46: map: Enumerable.collect, rlm@46: find: Enumerable.detect, rlm@46: select: Enumerable.findAll, rlm@46: member: Enumerable.include, rlm@46: entries: Enumerable.toArray rlm@46: }); rlm@46: var $A = Array.from = function(iterable) { rlm@46: if (!iterable) return []; rlm@46: if (iterable.toArray) { rlm@46: return iterable.toArray(); rlm@46: } else { rlm@46: var results = []; rlm@46: for (var i = 0; i < iterable.length; i++) rlm@46: results.push(iterable[i]); rlm@46: return results; rlm@46: } rlm@46: } rlm@46: rlm@46: Object.extend(Array.prototype, Enumerable); rlm@46: rlm@46: Array.prototype._reverse = Array.prototype.reverse; rlm@46: rlm@46: Object.extend(Array.prototype, { rlm@46: _each: function(iterator) { rlm@46: for (var i = 0; i < this.length; i++) rlm@46: iterator(this[i]); rlm@46: }, rlm@46: rlm@46: clear: function() { rlm@46: this.length = 0; rlm@46: return this; rlm@46: }, rlm@46: rlm@46: first: function() { rlm@46: return this[0]; rlm@46: }, rlm@46: rlm@46: last: function() { rlm@46: return this[this.length - 1]; rlm@46: }, rlm@46: rlm@46: compact: function() { rlm@46: return this.select(function(value) { rlm@46: return value != undefined || value != null; rlm@46: }); rlm@46: }, rlm@46: rlm@46: flatten: function() { rlm@46: return this.inject([], function(array, value) { rlm@46: return array.concat(value.constructor == Array ? rlm@46: value.flatten() : [value]); rlm@46: }); rlm@46: }, rlm@46: rlm@46: without: function() { rlm@46: var values = $A(arguments); rlm@46: return this.select(function(value) { rlm@46: return !values.include(value); rlm@46: }); rlm@46: }, rlm@46: rlm@46: indexOf: function(object) { rlm@46: for (var i = 0; i < this.length; i++) rlm@46: if (this[i] == object) return i; rlm@46: return -1; rlm@46: }, rlm@46: rlm@46: reverse: function(inline) { rlm@46: return (inline !== false ? this : this.toArray())._reverse(); rlm@46: }, rlm@46: rlm@46: shift: function() { rlm@46: var result = this[0]; rlm@46: for (var i = 0; i < this.length - 1; i++) rlm@46: this[i] = this[i + 1]; rlm@46: this.length--; rlm@46: return result; rlm@46: }, rlm@46: rlm@46: inspect: function() { rlm@46: return '[' + this.map(Object.inspect).join(', ') + ']'; rlm@46: } rlm@46: }); rlm@46: var Hash = { rlm@46: _each: function(iterator) { rlm@46: for (key in this) { rlm@46: var value = this[key]; rlm@46: if (typeof value == 'function') continue; rlm@46: rlm@46: var pair = [key, value]; rlm@46: pair.key = key; rlm@46: pair.value = value; rlm@46: iterator(pair); rlm@46: } rlm@46: }, rlm@46: rlm@46: keys: function() { rlm@46: return this.pluck('key'); rlm@46: }, rlm@46: rlm@46: values: function() { rlm@46: return this.pluck('value'); rlm@46: }, rlm@46: rlm@46: merge: function(hash) { rlm@46: return $H(hash).inject($H(this), function(mergedHash, pair) { rlm@46: mergedHash[pair.key] = pair.value; rlm@46: return mergedHash; rlm@46: }); rlm@46: }, rlm@46: rlm@46: toQueryString: function() { rlm@46: return this.map(function(pair) { rlm@46: return pair.map(encodeURIComponent).join('='); rlm@46: }).join('&'); rlm@46: }, rlm@46: rlm@46: inspect: function() { rlm@46: return '#'; rlm@46: } rlm@46: } rlm@46: rlm@46: function $H(object) { rlm@46: var hash = Object.extend({}, object || {}); rlm@46: Object.extend(hash, Enumerable); rlm@46: Object.extend(hash, Hash); rlm@46: return hash; rlm@46: } rlm@46: ObjectRange = Class.create(); rlm@46: Object.extend(ObjectRange.prototype, Enumerable); rlm@46: Object.extend(ObjectRange.prototype, { rlm@46: initialize: function(start, end, exclusive) { rlm@46: this.start = start; rlm@46: this.end = end; rlm@46: this.exclusive = exclusive; rlm@46: }, rlm@46: rlm@46: _each: function(iterator) { rlm@46: var value = this.start; rlm@46: do { rlm@46: iterator(value); rlm@46: value = value.succ(); rlm@46: } while (this.include(value)); rlm@46: }, rlm@46: rlm@46: include: function(value) { rlm@46: if (value < this.start) rlm@46: return false; rlm@46: if (this.exclusive) rlm@46: return value < this.end; rlm@46: return value <= this.end; rlm@46: } rlm@46: }); rlm@46: rlm@46: var $R = function(start, end, exclusive) { rlm@46: return new ObjectRange(start, end, exclusive); rlm@46: } rlm@46: rlm@46: var Ajax = { rlm@46: getTransport: function() { rlm@46: return Try.these( rlm@46: function() {return new ActiveXObject('Msxml2.XMLHTTP')}, rlm@46: function() {return new ActiveXObject('Microsoft.XMLHTTP')}, rlm@46: function() {return new XMLHttpRequest()} rlm@46: ) || false; rlm@46: }, rlm@46: rlm@46: activeRequestCount: 0 rlm@46: } rlm@46: rlm@46: Ajax.Responders = { rlm@46: responders: [], rlm@46: rlm@46: _each: function(iterator) { rlm@46: this.responders._each(iterator); rlm@46: }, rlm@46: rlm@46: register: function(responderToAdd) { rlm@46: if (!this.include(responderToAdd)) rlm@46: this.responders.push(responderToAdd); rlm@46: }, rlm@46: rlm@46: unregister: function(responderToRemove) { rlm@46: this.responders = this.responders.without(responderToRemove); rlm@46: }, rlm@46: rlm@46: dispatch: function(callback, request, transport, json) { rlm@46: this.each(function(responder) { rlm@46: if (responder[callback] && typeof responder[callback] == 'function') { rlm@46: try { rlm@46: responder[callback].apply(responder, [request, transport, json]); rlm@46: } catch (e) {} rlm@46: } rlm@46: }); rlm@46: } rlm@46: }; rlm@46: rlm@46: Object.extend(Ajax.Responders, Enumerable); rlm@46: rlm@46: Ajax.Responders.register({ rlm@46: onCreate: function() { rlm@46: Ajax.activeRequestCount++; rlm@46: }, rlm@46: rlm@46: onComplete: function() { rlm@46: Ajax.activeRequestCount--; rlm@46: } rlm@46: }); rlm@46: rlm@46: Ajax.Base = function() {}; rlm@46: Ajax.Base.prototype = { rlm@46: setOptions: function(options) { rlm@46: this.options = { rlm@46: method: 'post', rlm@46: asynchronous: true, rlm@46: parameters: '' rlm@46: } rlm@46: Object.extend(this.options, options || {}); rlm@46: }, rlm@46: rlm@46: responseIsSuccess: function() { rlm@46: return this.transport.status == undefined rlm@46: || this.transport.status == 0 rlm@46: || (this.transport.status >= 200 && this.transport.status < 300); rlm@46: }, rlm@46: rlm@46: responseIsFailure: function() { rlm@46: return !this.responseIsSuccess(); rlm@46: } rlm@46: } rlm@46: rlm@46: Ajax.Request = Class.create(); rlm@46: Ajax.Request.Events = rlm@46: ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; rlm@46: rlm@46: Ajax.Request.prototype = Object.extend(new Ajax.Base(), { rlm@46: initialize: function(url, options) { rlm@46: this.transport = Ajax.getTransport(); rlm@46: this.setOptions(options); rlm@46: this.request(url); rlm@46: }, rlm@46: rlm@46: request: function(url) { rlm@46: var parameters = this.options.parameters || ''; rlm@46: if (parameters.length > 0) parameters += '&_='; rlm@46: rlm@46: try { rlm@46: this.url = url; rlm@46: if (this.options.method == 'get' && parameters.length > 0) rlm@46: this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; rlm@46: rlm@46: Ajax.Responders.dispatch('onCreate', this, this.transport); rlm@46: rlm@46: this.transport.open(this.options.method, this.url, rlm@46: this.options.asynchronous); rlm@46: rlm@46: if (this.options.asynchronous) { rlm@46: this.transport.onreadystatechange = this.onStateChange.bind(this); rlm@46: setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); rlm@46: } rlm@46: rlm@46: this.setRequestHeaders(); rlm@46: rlm@46: var body = this.options.postBody ? this.options.postBody : parameters; rlm@46: this.transport.send(this.options.method == 'post' ? body : null); rlm@46: rlm@46: } catch (e) { rlm@46: this.dispatchException(e); rlm@46: } rlm@46: }, rlm@46: rlm@46: setRequestHeaders: function() { rlm@46: var requestHeaders = rlm@46: ['X-Requested-With', 'XMLHttpRequest', rlm@46: 'X-Prototype-Version', Prototype.Version]; rlm@46: rlm@46: if (this.options.method == 'post') { rlm@46: requestHeaders.push('Content-type', rlm@46: 'application/x-www-form-urlencoded'); rlm@46: rlm@46: /* Force "Connection: close" for Mozilla browsers to work around rlm@46: * a bug where XMLHttpReqeuest sends an incorrect Content-length rlm@46: * header. See Mozilla Bugzilla #246651. rlm@46: */ rlm@46: if (this.transport.overrideMimeType) rlm@46: requestHeaders.push('Connection', 'close'); rlm@46: } rlm@46: rlm@46: if (this.options.requestHeaders) rlm@46: requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); rlm@46: rlm@46: for (var i = 0; i < requestHeaders.length; i += 2) rlm@46: this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); rlm@46: }, rlm@46: rlm@46: onStateChange: function() { rlm@46: var readyState = this.transport.readyState; rlm@46: if (readyState != 1) rlm@46: this.respondToReadyState(this.transport.readyState); rlm@46: }, rlm@46: rlm@46: header: function(name) { rlm@46: try { rlm@46: return this.transport.getResponseHeader(name); rlm@46: } catch (e) {} rlm@46: }, rlm@46: rlm@46: evalJSON: function() { rlm@46: try { rlm@46: return eval(this.header('X-JSON')); rlm@46: } catch (e) {} rlm@46: }, rlm@46: rlm@46: evalResponse: function() { rlm@46: try { rlm@46: return eval(this.transport.responseText); rlm@46: } catch (e) { rlm@46: this.dispatchException(e); rlm@46: } rlm@46: }, rlm@46: rlm@46: respondToReadyState: function(readyState) { rlm@46: var event = Ajax.Request.Events[readyState]; rlm@46: var transport = this.transport, json = this.evalJSON(); rlm@46: rlm@46: if (event == 'Complete') { rlm@46: try { rlm@46: (this.options['on' + this.transport.status] rlm@46: || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] rlm@46: || Prototype.emptyFunction)(transport, json); rlm@46: } catch (e) { rlm@46: this.dispatchException(e); rlm@46: } rlm@46: rlm@46: if ((this.header('Content-type') || '').match(/^text\/javascript/i)) rlm@46: this.evalResponse(); rlm@46: } rlm@46: rlm@46: try { rlm@46: (this.options['on' + event] || Prototype.emptyFunction)(transport, json); rlm@46: Ajax.Responders.dispatch('on' + event, this, transport, json); rlm@46: } catch (e) { rlm@46: this.dispatchException(e); rlm@46: } rlm@46: rlm@46: /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ rlm@46: if (event == 'Complete') rlm@46: this.transport.onreadystatechange = Prototype.emptyFunction; rlm@46: }, rlm@46: rlm@46: dispatchException: function(exception) { rlm@46: (this.options.onException || Prototype.emptyFunction)(this, exception); rlm@46: Ajax.Responders.dispatch('onException', this, exception); rlm@46: } rlm@46: }); rlm@46: rlm@46: Ajax.Updater = Class.create(); rlm@46: rlm@46: Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { rlm@46: initialize: function(container, url, options) { rlm@46: this.containers = { rlm@46: success: container.success ? $(container.success) : $(container), rlm@46: failure: container.failure ? $(container.failure) : rlm@46: (container.success ? null : $(container)) rlm@46: } rlm@46: rlm@46: this.transport = Ajax.getTransport(); rlm@46: this.setOptions(options); rlm@46: rlm@46: var onComplete = this.options.onComplete || Prototype.emptyFunction; rlm@46: this.options.onComplete = (function(transport, object) { rlm@46: this.updateContent(); rlm@46: onComplete(transport, object); rlm@46: }).bind(this); rlm@46: rlm@46: this.request(url); rlm@46: }, rlm@46: rlm@46: updateContent: function() { rlm@46: var receiver = this.responseIsSuccess() ? rlm@46: this.containers.success : this.containers.failure; rlm@46: var response = this.transport.responseText; rlm@46: rlm@46: if (!this.options.evalScripts) rlm@46: response = response.stripScripts(); rlm@46: rlm@46: if (receiver) { rlm@46: if (this.options.insertion) { rlm@46: new this.options.insertion(receiver, response); rlm@46: } else { rlm@46: Element.update(receiver, response); rlm@46: } rlm@46: } rlm@46: rlm@46: if (this.responseIsSuccess()) { rlm@46: if (this.onComplete) rlm@46: setTimeout(this.onComplete.bind(this), 10); rlm@46: } rlm@46: } rlm@46: }); rlm@46: rlm@46: Ajax.PeriodicalUpdater = Class.create(); rlm@46: Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { rlm@46: initialize: function(container, url, options) { rlm@46: this.setOptions(options); rlm@46: this.onComplete = this.options.onComplete; rlm@46: rlm@46: this.frequency = (this.options.frequency || 2); rlm@46: this.decay = (this.options.decay || 1); rlm@46: rlm@46: this.updater = {}; rlm@46: this.container = container; rlm@46: this.url = url; rlm@46: rlm@46: this.start(); rlm@46: }, rlm@46: rlm@46: start: function() { rlm@46: this.options.onComplete = this.updateComplete.bind(this); rlm@46: this.onTimerEvent(); rlm@46: }, rlm@46: rlm@46: stop: function() { rlm@46: this.updater.onComplete = undefined; rlm@46: clearTimeout(this.timer); rlm@46: (this.onComplete || Prototype.emptyFunction).apply(this, arguments); rlm@46: }, rlm@46: rlm@46: updateComplete: function(request) { rlm@46: if (this.options.decay) { rlm@46: this.decay = (request.responseText == this.lastText ? rlm@46: this.decay * this.options.decay : 1); rlm@46: rlm@46: this.lastText = request.responseText; rlm@46: } rlm@46: this.timer = setTimeout(this.onTimerEvent.bind(this), rlm@46: this.decay * this.frequency * 1000); rlm@46: }, rlm@46: rlm@46: onTimerEvent: function() { rlm@46: this.updater = new Ajax.Updater(this.container, this.url, this.options); rlm@46: } rlm@46: }); rlm@46: document.getElementsByClassName = function(className, parentElement) { rlm@46: var children = ($(parentElement) || document.body).getElementsByTagName('*'); rlm@46: return $A(children).inject([], function(elements, child) { rlm@46: if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) rlm@46: elements.push(child); rlm@46: return elements; rlm@46: }); rlm@46: } rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: if (!window.Element) { rlm@46: var Element = new Object(); rlm@46: } rlm@46: rlm@46: Object.extend(Element, { rlm@46: visible: function(element) { rlm@46: return $(element).style.display != 'none'; rlm@46: }, rlm@46: rlm@46: toggle: function() { rlm@46: for (var i = 0; i < arguments.length; i++) { rlm@46: var element = $(arguments[i]); rlm@46: Element[Element.visible(element) ? 'hide' : 'show'](element); rlm@46: } rlm@46: }, rlm@46: rlm@46: hide: function() { rlm@46: for (var i = 0; i < arguments.length; i++) { rlm@46: var element = $(arguments[i]); rlm@46: element.style.display = 'none'; rlm@46: } rlm@46: }, rlm@46: rlm@46: show: function() { rlm@46: for (var i = 0; i < arguments.length; i++) { rlm@46: var element = $(arguments[i]); rlm@46: element.style.display = ''; rlm@46: } rlm@46: }, rlm@46: rlm@46: remove: function(element) { rlm@46: element = $(element); rlm@46: element.parentNode.removeChild(element); rlm@46: }, rlm@46: rlm@46: update: function(element, html) { rlm@46: $(element).innerHTML = html.stripScripts(); rlm@46: setTimeout(function() {html.evalScripts()}, 10); rlm@46: }, rlm@46: rlm@46: getHeight: function(element) { rlm@46: element = $(element); rlm@46: return element.offsetHeight; rlm@46: }, rlm@46: rlm@46: classNames: function(element) { rlm@46: return new Element.ClassNames(element); rlm@46: }, rlm@46: rlm@46: hasClassName: function(element, className) { rlm@46: if (!(element = $(element))) return; rlm@46: return Element.classNames(element).include(className); rlm@46: }, rlm@46: rlm@46: addClassName: function(element, className) { rlm@46: if (!(element = $(element))) return; rlm@46: return Element.classNames(element).add(className); rlm@46: }, rlm@46: rlm@46: removeClassName: function(element, className) { rlm@46: if (!(element = $(element))) return; rlm@46: return Element.classNames(element).remove(className); rlm@46: }, rlm@46: rlm@46: // removes whitespace-only text node children rlm@46: cleanWhitespace: function(element) { rlm@46: element = $(element); rlm@46: for (var i = 0; i < element.childNodes.length; i++) { rlm@46: var node = element.childNodes[i]; rlm@46: if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) rlm@46: Element.remove(node); rlm@46: } rlm@46: }, rlm@46: rlm@46: empty: function(element) { rlm@46: return $(element).innerHTML.match(/^\s*$/); rlm@46: }, rlm@46: rlm@46: scrollTo: function(element) { rlm@46: element = $(element); rlm@46: var x = element.x ? element.x : element.offsetLeft, rlm@46: y = element.y ? element.y : element.offsetTop; rlm@46: window.scrollTo(x, y); rlm@46: }, rlm@46: rlm@46: getStyle: function(element, style) { rlm@46: element = $(element); rlm@46: var value = element.style[style.camelize()]; rlm@46: if (!value) { rlm@46: if (document.defaultView && document.defaultView.getComputedStyle) { rlm@46: var css = document.defaultView.getComputedStyle(element, null); rlm@46: value = css ? css.getPropertyValue(style) : null; rlm@46: } else if (element.currentStyle) { rlm@46: value = element.currentStyle[style.camelize()]; rlm@46: } rlm@46: } rlm@46: rlm@46: if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) rlm@46: if (Element.getStyle(element, 'position') == 'static') value = 'auto'; rlm@46: rlm@46: return value == 'auto' ? null : value; rlm@46: }, rlm@46: rlm@46: setStyle: function(element, style) { rlm@46: element = $(element); rlm@46: for (name in style) rlm@46: element.style[name.camelize()] = style[name]; rlm@46: }, rlm@46: rlm@46: getDimensions: function(element) { rlm@46: element = $(element); rlm@46: if (Element.getStyle(element, 'display') != 'none') rlm@46: return {width: element.offsetWidth, height: element.offsetHeight}; rlm@46: rlm@46: // All *Width and *Height properties give 0 on elements with display none, rlm@46: // so enable the element temporarily rlm@46: var els = element.style; rlm@46: var originalVisibility = els.visibility; rlm@46: var originalPosition = els.position; rlm@46: els.visibility = 'hidden'; rlm@46: els.position = 'absolute'; rlm@46: els.display = ''; rlm@46: var originalWidth = element.clientWidth; rlm@46: var originalHeight = element.clientHeight; rlm@46: els.display = 'none'; rlm@46: els.position = originalPosition; rlm@46: els.visibility = originalVisibility; rlm@46: return {width: originalWidth, height: originalHeight}; rlm@46: }, rlm@46: rlm@46: makePositioned: function(element) { rlm@46: element = $(element); rlm@46: var pos = Element.getStyle(element, 'position'); rlm@46: if (pos == 'static' || !pos) { rlm@46: element._madePositioned = true; rlm@46: element.style.position = 'relative'; rlm@46: // Opera returns the offset relative to the positioning context, when an rlm@46: // element is position relative but top and left have not been defined rlm@46: if (window.opera) { rlm@46: element.style.top = 0; rlm@46: element.style.left = 0; rlm@46: } rlm@46: } rlm@46: }, rlm@46: rlm@46: undoPositioned: function(element) { rlm@46: element = $(element); rlm@46: if (element._madePositioned) { rlm@46: element._madePositioned = undefined; rlm@46: element.style.position = rlm@46: element.style.top = rlm@46: element.style.left = rlm@46: element.style.bottom = rlm@46: element.style.right = ''; rlm@46: } rlm@46: }, rlm@46: rlm@46: makeClipping: function(element) { rlm@46: element = $(element); rlm@46: if (element._overflow) return; rlm@46: element._overflow = element.style.overflow; rlm@46: if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') rlm@46: element.style.overflow = 'hidden'; rlm@46: }, rlm@46: rlm@46: undoClipping: function(element) { rlm@46: element = $(element); rlm@46: if (element._overflow) return; rlm@46: element.style.overflow = element._overflow; rlm@46: element._overflow = undefined; rlm@46: } rlm@46: }); rlm@46: rlm@46: var Toggle = new Object(); rlm@46: Toggle.display = Element.toggle; rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: Abstract.Insertion = function(adjacency) { rlm@46: this.adjacency = adjacency; rlm@46: } rlm@46: rlm@46: Abstract.Insertion.prototype = { rlm@46: initialize: function(element, content) { rlm@46: this.element = $(element); rlm@46: this.content = content.stripScripts(); rlm@46: rlm@46: if (this.adjacency && this.element.insertAdjacentHTML) { rlm@46: try { rlm@46: this.element.insertAdjacentHTML(this.adjacency, this.content); rlm@46: } catch (e) { rlm@46: if (this.element.tagName.toLowerCase() == 'tbody') { rlm@46: this.insertContent(this.contentFromAnonymousTable()); rlm@46: } else { rlm@46: throw e; rlm@46: } rlm@46: } rlm@46: } else { rlm@46: this.range = this.element.ownerDocument.createRange(); rlm@46: if (this.initializeRange) this.initializeRange(); rlm@46: this.insertContent([this.range.createContextualFragment(this.content)]); rlm@46: } rlm@46: rlm@46: setTimeout(function() {content.evalScripts()}, 10); rlm@46: }, rlm@46: rlm@46: contentFromAnonymousTable: function() { rlm@46: var div = document.createElement('div'); rlm@46: div.innerHTML = '' + this.content + '
'; rlm@46: return $A(div.childNodes[0].childNodes[0].childNodes); rlm@46: } rlm@46: } rlm@46: rlm@46: var Insertion = new Object(); rlm@46: rlm@46: Insertion.Before = Class.create(); rlm@46: Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { rlm@46: initializeRange: function() { rlm@46: this.range.setStartBefore(this.element); rlm@46: }, rlm@46: rlm@46: insertContent: function(fragments) { rlm@46: fragments.each((function(fragment) { rlm@46: this.element.parentNode.insertBefore(fragment, this.element); rlm@46: }).bind(this)); rlm@46: } rlm@46: }); rlm@46: rlm@46: Insertion.Top = Class.create(); rlm@46: Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { rlm@46: initializeRange: function() { rlm@46: this.range.selectNodeContents(this.element); rlm@46: this.range.collapse(true); rlm@46: }, rlm@46: rlm@46: insertContent: function(fragments) { rlm@46: fragments.reverse(false).each((function(fragment) { rlm@46: this.element.insertBefore(fragment, this.element.firstChild); rlm@46: }).bind(this)); rlm@46: } rlm@46: }); rlm@46: rlm@46: Insertion.Bottom = Class.create(); rlm@46: Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { rlm@46: initializeRange: function() { rlm@46: this.range.selectNodeContents(this.element); rlm@46: this.range.collapse(this.element); rlm@46: }, rlm@46: rlm@46: insertContent: function(fragments) { rlm@46: fragments.each((function(fragment) { rlm@46: this.element.appendChild(fragment); rlm@46: }).bind(this)); rlm@46: } rlm@46: }); rlm@46: rlm@46: Insertion.After = Class.create(); rlm@46: Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { rlm@46: initializeRange: function() { rlm@46: this.range.setStartAfter(this.element); rlm@46: }, rlm@46: rlm@46: insertContent: function(fragments) { rlm@46: fragments.each((function(fragment) { rlm@46: this.element.parentNode.insertBefore(fragment, rlm@46: this.element.nextSibling); rlm@46: }).bind(this)); rlm@46: } rlm@46: }); rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: Element.ClassNames = Class.create(); rlm@46: Element.ClassNames.prototype = { rlm@46: initialize: function(element) { rlm@46: this.element = $(element); rlm@46: }, rlm@46: rlm@46: _each: function(iterator) { rlm@46: this.element.className.split(/\s+/).select(function(name) { rlm@46: return name.length > 0; rlm@46: })._each(iterator); rlm@46: }, rlm@46: rlm@46: set: function(className) { rlm@46: this.element.className = className; rlm@46: }, rlm@46: rlm@46: add: function(classNameToAdd) { rlm@46: if (this.include(classNameToAdd)) return; rlm@46: this.set(this.toArray().concat(classNameToAdd).join(' ')); rlm@46: }, rlm@46: rlm@46: remove: function(classNameToRemove) { rlm@46: if (!this.include(classNameToRemove)) return; rlm@46: this.set(this.select(function(className) { rlm@46: return className != classNameToRemove; rlm@46: }).join(' ')); rlm@46: }, rlm@46: rlm@46: toString: function() { rlm@46: return this.toArray().join(' '); rlm@46: } rlm@46: } rlm@46: rlm@46: Object.extend(Element.ClassNames.prototype, Enumerable); rlm@46: var Field = { rlm@46: clear: function() { rlm@46: for (var i = 0; i < arguments.length; i++) rlm@46: $(arguments[i]).value = ''; rlm@46: }, rlm@46: rlm@46: focus: function(element) { rlm@46: $(element).focus(); rlm@46: }, rlm@46: rlm@46: present: function() { rlm@46: for (var i = 0; i < arguments.length; i++) rlm@46: if ($(arguments[i]).value == '') return false; rlm@46: return true; rlm@46: }, rlm@46: rlm@46: select: function(element) { rlm@46: $(element).select(); rlm@46: }, rlm@46: rlm@46: activate: function(element) { rlm@46: element = $(element); rlm@46: element.focus(); rlm@46: if (element.select) rlm@46: element.select(); rlm@46: } rlm@46: } rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: var Form = { rlm@46: serialize: function(form) { rlm@46: var elements = Form.getElements($(form)); rlm@46: var queryComponents = new Array(); rlm@46: rlm@46: for (var i = 0; i < elements.length; i++) { rlm@46: var queryComponent = Form.Element.serialize(elements[i]); rlm@46: if (queryComponent) rlm@46: queryComponents.push(queryComponent); rlm@46: } rlm@46: rlm@46: return queryComponents.join('&'); rlm@46: }, rlm@46: rlm@46: getElements: function(form) { rlm@46: form = $(form); rlm@46: var elements = new Array(); rlm@46: rlm@46: for (tagName in Form.Element.Serializers) { rlm@46: var tagElements = form.getElementsByTagName(tagName); rlm@46: for (var j = 0; j < tagElements.length; j++) rlm@46: elements.push(tagElements[j]); rlm@46: } rlm@46: return elements; rlm@46: }, rlm@46: rlm@46: getInputs: function(form, typeName, name) { rlm@46: form = $(form); rlm@46: var inputs = form.getElementsByTagName('input'); rlm@46: rlm@46: if (!typeName && !name) rlm@46: return inputs; rlm@46: rlm@46: var matchingInputs = new Array(); rlm@46: for (var i = 0; i < inputs.length; i++) { rlm@46: var input = inputs[i]; rlm@46: if ((typeName && input.type != typeName) || rlm@46: (name && input.name != name)) rlm@46: continue; rlm@46: matchingInputs.push(input); rlm@46: } rlm@46: rlm@46: return matchingInputs; rlm@46: }, rlm@46: rlm@46: disable: function(form) { rlm@46: var elements = Form.getElements(form); rlm@46: for (var i = 0; i < elements.length; i++) { rlm@46: var element = elements[i]; rlm@46: element.blur(); rlm@46: element.disabled = 'true'; rlm@46: } rlm@46: }, rlm@46: rlm@46: enable: function(form) { rlm@46: var elements = Form.getElements(form); rlm@46: for (var i = 0; i < elements.length; i++) { rlm@46: var element = elements[i]; rlm@46: element.disabled = ''; rlm@46: } rlm@46: }, rlm@46: rlm@46: findFirstElement: function(form) { rlm@46: return Form.getElements(form).find(function(element) { rlm@46: return element.type != 'hidden' && !element.disabled && rlm@46: ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); rlm@46: }); rlm@46: }, rlm@46: rlm@46: focusFirstElement: function(form) { rlm@46: Field.activate(Form.findFirstElement(form)); rlm@46: }, rlm@46: rlm@46: reset: function(form) { rlm@46: $(form).reset(); rlm@46: } rlm@46: } rlm@46: rlm@46: Form.Element = { rlm@46: serialize: function(element) { rlm@46: element = $(element); rlm@46: var method = element.tagName.toLowerCase(); rlm@46: var parameter = Form.Element.Serializers[method](element); rlm@46: rlm@46: if (parameter) { rlm@46: var key = encodeURIComponent(parameter[0]); rlm@46: if (key.length == 0) return; rlm@46: rlm@46: if (parameter[1].constructor != Array) rlm@46: parameter[1] = [parameter[1]]; rlm@46: rlm@46: return parameter[1].map(function(value) { rlm@46: return key + '=' + encodeURIComponent(value); rlm@46: }).join('&'); rlm@46: } rlm@46: }, rlm@46: rlm@46: getValue: function(element) { rlm@46: element = $(element); rlm@46: var method = element.tagName.toLowerCase(); rlm@46: var parameter = Form.Element.Serializers[method](element); rlm@46: rlm@46: if (parameter) rlm@46: return parameter[1]; rlm@46: } rlm@46: } rlm@46: rlm@46: Form.Element.Serializers = { rlm@46: input: function(element) { rlm@46: switch (element.type.toLowerCase()) { rlm@46: case 'submit': rlm@46: case 'hidden': rlm@46: case 'password': rlm@46: case 'text': rlm@46: return Form.Element.Serializers.textarea(element); rlm@46: case 'checkbox': rlm@46: case 'radio': rlm@46: return Form.Element.Serializers.inputSelector(element); rlm@46: } rlm@46: return false; rlm@46: }, rlm@46: rlm@46: inputSelector: function(element) { rlm@46: if (element.checked) rlm@46: return [element.name, element.value]; rlm@46: }, rlm@46: rlm@46: textarea: function(element) { rlm@46: return [element.name, element.value]; rlm@46: }, rlm@46: rlm@46: select: function(element) { rlm@46: return Form.Element.Serializers[element.type == 'select-one' ? rlm@46: 'selectOne' : 'selectMany'](element); rlm@46: }, rlm@46: rlm@46: selectOne: function(element) { rlm@46: var value = '', opt, index = element.selectedIndex; rlm@46: if (index >= 0) { rlm@46: opt = element.options[index]; rlm@46: value = opt.value; rlm@46: if (!value && !('value' in opt)) rlm@46: value = opt.text; rlm@46: } rlm@46: return [element.name, value]; rlm@46: }, rlm@46: rlm@46: selectMany: function(element) { rlm@46: var value = new Array(); rlm@46: for (var i = 0; i < element.length; i++) { rlm@46: var opt = element.options[i]; rlm@46: if (opt.selected) { rlm@46: var optValue = opt.value; rlm@46: if (!optValue && !('value' in opt)) rlm@46: optValue = opt.text; rlm@46: value.push(optValue); rlm@46: } rlm@46: } rlm@46: return [element.name, value]; rlm@46: } rlm@46: } rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: var $F = Form.Element.getValue; rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: Abstract.TimedObserver = function() {} rlm@46: Abstract.TimedObserver.prototype = { rlm@46: initialize: function(element, frequency, callback) { rlm@46: this.frequency = frequency; rlm@46: this.element = $(element); rlm@46: this.callback = callback; rlm@46: rlm@46: this.lastValue = this.getValue(); rlm@46: this.registerCallback(); rlm@46: }, rlm@46: rlm@46: registerCallback: function() { rlm@46: setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); rlm@46: }, rlm@46: rlm@46: onTimerEvent: function() { rlm@46: var value = this.getValue(); rlm@46: if (this.lastValue != value) { rlm@46: this.callback(this.element, value); rlm@46: this.lastValue = value; rlm@46: } rlm@46: } rlm@46: } rlm@46: rlm@46: Form.Element.Observer = Class.create(); rlm@46: Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { rlm@46: getValue: function() { rlm@46: return Form.Element.getValue(this.element); rlm@46: } rlm@46: }); rlm@46: rlm@46: Form.Observer = Class.create(); rlm@46: Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { rlm@46: getValue: function() { rlm@46: return Form.serialize(this.element); rlm@46: } rlm@46: }); rlm@46: rlm@46: /*--------------------------------------------------------------------------*/ rlm@46: rlm@46: Abstract.EventObserver = function() {} rlm@46: Abstract.EventObserver.prototype = { rlm@46: initialize: function(element, callback) { rlm@46: this.element = $(element); rlm@46: this.callback = callback; rlm@46: rlm@46: this.lastValue = this.getValue(); rlm@46: if (this.element.tagName.toLowerCase() == 'form') rlm@46: this.registerFormCallbacks(); rlm@46: else rlm@46: this.registerCallback(this.element); rlm@46: }, rlm@46: rlm@46: onElementEvent: function() { rlm@46: var value = this.getValue(); rlm@46: if (this.lastValue != value) { rlm@46: this.callback(this.element, value); rlm@46: this.lastValue = value; rlm@46: } rlm@46: }, rlm@46: rlm@46: registerFormCallbacks: function() { rlm@46: var elements = Form.getElements(this.element); rlm@46: for (var i = 0; i < elements.length; i++) rlm@46: this.registerCallback(elements[i]); rlm@46: }, rlm@46: rlm@46: registerCallback: function(element) { rlm@46: if (element.type) { rlm@46: switch (element.type.toLowerCase()) { rlm@46: case 'checkbox': rlm@46: case 'radio': rlm@46: Event.observe(element, 'click', this.onElementEvent.bind(this)); rlm@46: break; rlm@46: case 'password': rlm@46: case 'text': rlm@46: case 'textarea': rlm@46: case 'select-one': rlm@46: case 'select-multiple': rlm@46: Event.observe(element, 'change', this.onElementEvent.bind(this)); rlm@46: break; rlm@46: } rlm@46: } rlm@46: } rlm@46: } rlm@46: rlm@46: Form.Element.EventObserver = Class.create(); rlm@46: Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { rlm@46: getValue: function() { rlm@46: return Form.Element.getValue(this.element); rlm@46: } rlm@46: }); rlm@46: rlm@46: Form.EventObserver = Class.create(); rlm@46: Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { rlm@46: getValue: function() { rlm@46: return Form.serialize(this.element); rlm@46: } rlm@46: }); rlm@46: if (!window.Event) { rlm@46: var Event = new Object(); rlm@46: } rlm@46: rlm@46: Object.extend(Event, { rlm@46: KEY_BACKSPACE: 8, rlm@46: KEY_TAB: 9, rlm@46: KEY_RETURN: 13, rlm@46: KEY_ESC: 27, rlm@46: KEY_LEFT: 37, rlm@46: KEY_UP: 38, rlm@46: KEY_RIGHT: 39, rlm@46: KEY_DOWN: 40, rlm@46: KEY_DELETE: 46, rlm@46: rlm@46: element: function(event) { rlm@46: return event.target || event.srcElement; rlm@46: }, rlm@46: rlm@46: isLeftClick: function(event) { rlm@46: return (((event.which) && (event.which == 1)) || rlm@46: ((event.button) && (event.button == 1))); rlm@46: }, rlm@46: rlm@46: pointerX: function(event) { rlm@46: return event.pageX || (event.clientX + rlm@46: (document.documentElement.scrollLeft || document.body.scrollLeft)); rlm@46: }, rlm@46: rlm@46: pointerY: function(event) { rlm@46: return event.pageY || (event.clientY + rlm@46: (document.documentElement.scrollTop || document.body.scrollTop)); rlm@46: }, rlm@46: rlm@46: stop: function(event) { rlm@46: if (event.preventDefault) { rlm@46: event.preventDefault(); rlm@46: event.stopPropagation(); rlm@46: } else { rlm@46: event.returnValue = false; rlm@46: event.cancelBubble = true; rlm@46: } rlm@46: }, rlm@46: rlm@46: // find the first node with the given tagName, starting from the rlm@46: // node the event was triggered on; traverses the DOM upwards rlm@46: findElement: function(event, tagName) { rlm@46: var element = Event.element(event); rlm@46: while (element.parentNode && (!element.tagName || rlm@46: (element.tagName.toUpperCase() != tagName.toUpperCase()))) rlm@46: element = element.parentNode; rlm@46: return element; rlm@46: }, rlm@46: rlm@46: observers: false, rlm@46: rlm@46: _observeAndCache: function(element, name, observer, useCapture) { rlm@46: if (!this.observers) this.observers = []; rlm@46: if (element.addEventListener) { rlm@46: this.observers.push([element, name, observer, useCapture]); rlm@46: element.addEventListener(name, observer, useCapture); rlm@46: } else if (element.attachEvent) { rlm@46: this.observers.push([element, name, observer, useCapture]); rlm@46: element.attachEvent('on' + name, observer); rlm@46: } rlm@46: }, rlm@46: rlm@46: unloadCache: function() { rlm@46: if (!Event.observers) return; rlm@46: for (var i = 0; i < Event.observers.length; i++) { rlm@46: Event.stopObserving.apply(this, Event.observers[i]); rlm@46: Event.observers[i][0] = null; rlm@46: } rlm@46: Event.observers = false; rlm@46: }, rlm@46: rlm@46: observe: function(element, name, observer, useCapture) { rlm@46: var element = $(element); rlm@46: useCapture = useCapture || false; rlm@46: rlm@46: if (name == 'keypress' && rlm@46: (navigator.appVersion.match(/Konqueror|Safari|KHTML/) rlm@46: || element.attachEvent)) rlm@46: name = 'keydown'; rlm@46: rlm@46: this._observeAndCache(element, name, observer, useCapture); rlm@46: }, rlm@46: rlm@46: stopObserving: function(element, name, observer, useCapture) { rlm@46: var element = $(element); rlm@46: useCapture = useCapture || false; rlm@46: rlm@46: if (name == 'keypress' && rlm@46: (navigator.appVersion.match(/Konqueror|Safari|KHTML/) rlm@46: || element.detachEvent)) rlm@46: name = 'keydown'; rlm@46: rlm@46: if (element.removeEventListener) { rlm@46: element.removeEventListener(name, observer, useCapture); rlm@46: } else if (element.detachEvent) { rlm@46: element.detachEvent('on' + name, observer); rlm@46: } rlm@46: } rlm@46: }); rlm@46: rlm@46: /* prevent memory leaks in IE */ rlm@46: Event.observe(window, 'unload', Event.unloadCache, false); rlm@46: var Position = { rlm@46: // set to true if needed, warning: firefox performance problems rlm@46: // NOT neeeded for page scrolling, only if draggable contained in rlm@46: // scrollable elements rlm@46: includeScrollOffsets: false, rlm@46: rlm@46: // must be called before calling withinIncludingScrolloffset, every time the rlm@46: // page is scrolled rlm@46: prepare: function() { rlm@46: this.deltaX = window.pageXOffset rlm@46: || document.documentElement.scrollLeft rlm@46: || document.body.scrollLeft rlm@46: || 0; rlm@46: this.deltaY = window.pageYOffset rlm@46: || document.documentElement.scrollTop rlm@46: || document.body.scrollTop rlm@46: || 0; rlm@46: }, rlm@46: rlm@46: realOffset: function(element) { rlm@46: var valueT = 0, valueL = 0; rlm@46: do { rlm@46: valueT += element.scrollTop || 0; rlm@46: valueL += element.scrollLeft || 0; rlm@46: element = element.parentNode; rlm@46: } while (element); rlm@46: return [valueL, valueT]; rlm@46: }, rlm@46: rlm@46: cumulativeOffset: function(element) { rlm@46: var valueT = 0, valueL = 0; rlm@46: do { rlm@46: valueT += element.offsetTop || 0; rlm@46: valueL += element.offsetLeft || 0; rlm@46: element = element.offsetParent; rlm@46: } while (element); rlm@46: return [valueL, valueT]; rlm@46: }, rlm@46: rlm@46: positionedOffset: function(element) { rlm@46: var valueT = 0, valueL = 0; rlm@46: do { rlm@46: valueT += element.offsetTop || 0; rlm@46: valueL += element.offsetLeft || 0; rlm@46: element = element.offsetParent; rlm@46: if (element) { rlm@46: p = Element.getStyle(element, 'position'); rlm@46: if (p == 'relative' || p == 'absolute') break; rlm@46: } rlm@46: } while (element); rlm@46: return [valueL, valueT]; rlm@46: }, rlm@46: rlm@46: offsetParent: function(element) { rlm@46: if (element.offsetParent) return element.offsetParent; rlm@46: if (element == document.body) return element; rlm@46: rlm@46: while ((element = element.parentNode) && element != document.body) rlm@46: if (Element.getStyle(element, 'position') != 'static') rlm@46: return element; rlm@46: rlm@46: return document.body; rlm@46: }, rlm@46: rlm@46: // caches x/y coordinate pair to use with overlap rlm@46: within: function(element, x, y) { rlm@46: if (this.includeScrollOffsets) rlm@46: return this.withinIncludingScrolloffsets(element, x, y); rlm@46: this.xcomp = x; rlm@46: this.ycomp = y; rlm@46: this.offset = this.cumulativeOffset(element); rlm@46: rlm@46: return (y >= this.offset[1] && rlm@46: y < this.offset[1] + element.offsetHeight && rlm@46: x >= this.offset[0] && rlm@46: x < this.offset[0] + element.offsetWidth); rlm@46: }, rlm@46: rlm@46: withinIncludingScrolloffsets: function(element, x, y) { rlm@46: var offsetcache = this.realOffset(element); rlm@46: rlm@46: this.xcomp = x + offsetcache[0] - this.deltaX; rlm@46: this.ycomp = y + offsetcache[1] - this.deltaY; rlm@46: this.offset = this.cumulativeOffset(element); rlm@46: rlm@46: return (this.ycomp >= this.offset[1] && rlm@46: this.ycomp < this.offset[1] + element.offsetHeight && rlm@46: this.xcomp >= this.offset[0] && rlm@46: this.xcomp < this.offset[0] + element.offsetWidth); rlm@46: }, rlm@46: rlm@46: // within must be called directly before rlm@46: overlap: function(mode, element) { rlm@46: if (!mode) return 0; rlm@46: if (mode == 'vertical') rlm@46: return ((this.offset[1] + element.offsetHeight) - this.ycomp) / rlm@46: element.offsetHeight; rlm@46: if (mode == 'horizontal') rlm@46: return ((this.offset[0] + element.offsetWidth) - this.xcomp) / rlm@46: element.offsetWidth; rlm@46: }, rlm@46: rlm@46: clone: function(source, target) { rlm@46: source = $(source); rlm@46: target = $(target); rlm@46: target.style.position = 'absolute'; rlm@46: var offsets = this.cumulativeOffset(source); rlm@46: target.style.top = offsets[1] + 'px'; rlm@46: target.style.left = offsets[0] + 'px'; rlm@46: target.style.width = source.offsetWidth + 'px'; rlm@46: target.style.height = source.offsetHeight + 'px'; rlm@46: }, rlm@46: rlm@46: page: function(forElement) { rlm@46: var valueT = 0, valueL = 0; rlm@46: rlm@46: var element = forElement; rlm@46: do { rlm@46: valueT += element.offsetTop || 0; rlm@46: valueL += element.offsetLeft || 0; rlm@46: rlm@46: // Safari fix rlm@46: if (element.offsetParent==document.body) rlm@46: if (Element.getStyle(element,'position')=='absolute') break; rlm@46: rlm@46: } while (element = element.offsetParent); rlm@46: rlm@46: element = forElement; rlm@46: do { rlm@46: valueT -= element.scrollTop || 0; rlm@46: valueL -= element.scrollLeft || 0; rlm@46: } while (element = element.parentNode); rlm@46: rlm@46: return [valueL, valueT]; rlm@46: }, rlm@46: rlm@46: clone: function(source, target) { rlm@46: var options = Object.extend({ rlm@46: setLeft: true, rlm@46: setTop: true, rlm@46: setWidth: true, rlm@46: setHeight: true, rlm@46: offsetTop: 0, rlm@46: offsetLeft: 0 rlm@46: }, arguments[2] || {}) rlm@46: rlm@46: // find page position of source rlm@46: source = $(source); rlm@46: var p = Position.page(source); rlm@46: rlm@46: // find coordinate system to use rlm@46: target = $(target); rlm@46: var delta = [0, 0]; rlm@46: var parent = null; rlm@46: // delta [0,0] will do fine with position: fixed elements, rlm@46: // position:absolute needs offsetParent deltas rlm@46: if (Element.getStyle(target,'position') == 'absolute') { rlm@46: parent = Position.offsetParent(target); rlm@46: delta = Position.page(parent); rlm@46: } rlm@46: rlm@46: // correct by body offsets (fixes Safari) rlm@46: if (parent == document.body) { rlm@46: delta[0] -= document.body.offsetLeft; rlm@46: delta[1] -= document.body.offsetTop; rlm@46: } rlm@46: rlm@46: // set position rlm@46: if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; rlm@46: if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; rlm@46: if(options.setWidth) target.style.width = source.offsetWidth + 'px'; rlm@46: if(options.setHeight) target.style.height = source.offsetHeight + 'px'; rlm@46: }, rlm@46: rlm@46: absolutize: function(element) { rlm@46: element = $(element); rlm@46: if (element.style.position == 'absolute') return; rlm@46: Position.prepare(); rlm@46: rlm@46: var offsets = Position.positionedOffset(element); rlm@46: var top = offsets[1]; rlm@46: var left = offsets[0]; rlm@46: var width = element.clientWidth; rlm@46: var height = element.clientHeight; rlm@46: rlm@46: element._originalLeft = left - parseFloat(element.style.left || 0); rlm@46: element._originalTop = top - parseFloat(element.style.top || 0); rlm@46: element._originalWidth = element.style.width; rlm@46: element._originalHeight = element.style.height; rlm@46: rlm@46: element.style.position = 'absolute'; rlm@46: element.style.top = top + 'px';; rlm@46: element.style.left = left + 'px';; rlm@46: element.style.width = width + 'px';; rlm@46: element.style.height = height + 'px';; rlm@46: }, rlm@46: rlm@46: relativize: function(element) { rlm@46: element = $(element); rlm@46: if (element.style.position == 'relative') return; rlm@46: Position.prepare(); rlm@46: rlm@46: element.style.position = 'relative'; rlm@46: var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); rlm@46: var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); rlm@46: rlm@46: element.style.top = top + 'px'; rlm@46: element.style.left = left + 'px'; rlm@46: element.style.height = element._originalHeight; rlm@46: element.style.width = element._originalWidth; rlm@46: } rlm@46: } rlm@46: rlm@46: // Safari returns margins on body which is incorrect if the child is absolutely rlm@46: // positioned. For performance reasons, redefine Position.cumulativeOffset for rlm@46: // KHTML/WebKit only. rlm@46: if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { rlm@46: Position.cumulativeOffset = function(element) { rlm@46: var valueT = 0, valueL = 0; rlm@46: do { rlm@46: valueT += element.offsetTop || 0; rlm@46: valueL += element.offsetLeft || 0; rlm@46: if (element.offsetParent == document.body) rlm@46: if (Element.getStyle(element, 'position') == 'absolute') break; rlm@46: rlm@46: element = element.offsetParent; rlm@46: } while (element); rlm@46: rlm@46: return [valueL, valueT]; rlm@46: } rlm@46: }