From: <al...@us...> - 2008-08-25 23:46:51
|
Revision: 638 http://sciret.svn.sourceforge.net/sciret/?rev=638&view=rev Author: alpeb Date: 2008-08-25 23:46:39 +0000 (Mon, 25 Aug 2008) Log Message: ----------- upgraded scriptaculous to version 1.8.1 Modified Paths: -------------- trunk/javascript/scriptaculous/CHANGELOG trunk/javascript/scriptaculous/MIT-LICENSE trunk/javascript/scriptaculous/README trunk/javascript/scriptaculous/lib/prototype.js trunk/javascript/scriptaculous/src/builder.js trunk/javascript/scriptaculous/src/controls.js trunk/javascript/scriptaculous/src/dragdrop.js trunk/javascript/scriptaculous/src/effects.js trunk/javascript/scriptaculous/src/scriptaculous.js trunk/javascript/scriptaculous/src/slider.js trunk/javascript/scriptaculous/src/unittest.js Added Paths: ----------- trunk/javascript/scriptaculous/src/sound.js Modified: trunk/javascript/scriptaculous/CHANGELOG =================================================================== --- trunk/javascript/scriptaculous/CHANGELOG 2008-08-25 14:29:37 UTC (rev 637) +++ trunk/javascript/scriptaculous/CHANGELOG 2008-08-25 23:46:39 UTC (rev 638) @@ -1,3 +1,178 @@ +*V1.8.1* (January 3, 2008) + +* Fix Element#getStyles in IE. Closes #10563. [Tobie Langel] + +* Update to Prototype 1.6.0.1 as of 8551. + +* Fix a regression with autocompleters not responding correctly to cursor keys on both Safari and IE. Closes #10107. [thx Zman771] + +*V1.8.0* (November 6, 2007) + +* Update to Prototype 1.6.0 final + +* Ajax.InPlaceEditor now can deal with callbacks that return an object. Closes #10064. [tdd] + +* Fix a potential problem with the loader and Firefox 2.0 on the Mac. Closes #9951. [awaters] + +* Add duration and distance options to Effect.Shake. Closes #8637. [amiel, rmm5t] + +* Update code to use new Hash implemention in Prototype 1.6. Update InPlaceEditor to use new Class.create syntax. [tdd] + +*V1.8.0 preview 0* (October 12, 2007) + +* Update to new Class.create syntax in Prototype 1.6; update to latest Prototype 1.6 trunk. + +* Fix bottom CSS property reassignment and initialization in queues for Effect#SlideUp. Closes #7412, #7761. + +* Fix an issue with String#parseStyle that could sometimes cause errors on Safari 2. + +* Refactoring to use Prototype 1.6. Remove dependency of Effect.tagifyText from builder. Use Prototype code style rules more consistently. + +* Remove the deprecated Effect2 namespace. + +* Update to Prototype 1.6.0_rc0. + +* Some effect code refactoring to take advantage of new Prototype 1.6 features. + +* Effect.ScrollTo is now no longer a core effect (returns a Effect.Tween instance now). + +* Add Effect.Tween, a new core effect. This effect tweens between two values and sets a property or calls a method on an object (including DOM elements); or allows for a callback method, which will be automatically bound to the object. + Examples: + var whatever = { blech: 0 }; + new Effect.Tween(whatever, 5, 0, 'blech'); // sets property on the object + new Effect.Tween('foo', 10, 20, 'innerHTML'); // sets property on the 'foo' DOM element + new Effect.Tween('foo', 10, 20, 'update'); // method call on 'foo' DOM element + new Effect.Tween('foo', 50, 0, { duration: 2.0 }, function(p){ + this.setStyle({border:p.toFixed(3)+'px solid red'}); + }); + new Effect.Tween(null, 0, 100, function(p){ scrollTo(0,p) }); // scrolls the window + +* Revert the workaround for the Firefox issue that makes autocompleter input field values be remembered correctly when the back button is hit to return to a page that contains autocompleted values, as this can cause "Are you sure you want to navigate away?" popups. Closes #8411. [okada] + +* Improve the way deactivating the active droppable is handled. Closes #9072. [Karsten Sperling] + +* Next version will be 1.8.0. Update to Prototype 1.6.0_pre1. + +* Make draggable initialization faster. Closes #8697. [ssinghi] + +* Make BDD-style testing compatible with IE6 and IE7. Closes #8972. [steveluscher] + +* Add BDD methods to booleans. Closes #9147. [steveluscher] + +* Add support for full CSS inheritance in Effect.Morph. Closes #9054. [Tobie] + IMPORTANT: Note that this could potentially change the outcome of classname-based morphs, so be sure to check your morph effects if you use this feature. + For this feature, the new method Element#getStyles is introduced, which returns an objects which properties correspond to the CSS properties found in Element.CSS_PROPERTIES. Note that this method doesn't work seemlessly across browsers for certain non-measurable CSS properties, such as float. + +* Add the externalControlOnly option to the in-place editors to allow for external controls to exclusively trigger the in-place editing. Closes #9024. [tdd] + +* Complete rewrite of Ajax.InPlaceEditor and Ajax.InPlaceCollectionEditor. [tdd] + THIS UPDATE MIGHT AFFECT BACKWARDS COMPATIBILITY. + Be sure to properly test, especially if you're using multi-line editing and/or monkeypatching. + Read more about all the added goodness in this article: + http://mir.aculo.us/2007/7/17/in-place-editing-the-summer-2007-rewrite + +* Update to Prototype 1.5.2_rc0 r7076: + - Works around bugs in Safari 1 and Safari 2 Regexp engines that could cause crashes + - Fixes a rendering issue with opacity-based effects and floating elements on Safari + +* Mild refactoring of sound.js to take advantage of new Prototype features. + +* Add highlight element method as a shortcut to Effect.Highlight. + Example: + $('message').highlight({startcolor:'#ff0000'}).update('KTHXBYE'); + +* Improve performance of String.prototype.parseStyle by caching the dummy element used. + +* Add combined effects as element methods. + Examples: + $('message').appear().update('Oh noes!'); + $('login').shake({ duration: 2 }); + +* Add Effect.Transitions.spring, which simulates a spring which oscillates while coming to rest. This transition is specifically targeted towards use with Effect.Move, for example as a reverteffect when using Draggables, as it will have return values >1 and cause temporary "overshooting" of the effect. Closes #8474. [edg2s] + +* Fix effects initialization if no options are given. Fixes #7809. [thx Kroc Camen] + +* Fix incorrect placement on drop for absolute ghosting elements. Update to Prototype 1.5.2_rc0 r6955 (required for #8581). Closes #8581. [tdd] + +* Make sure the autocompletion happens on the token where the cursor is, not the last token when using tokenized autocompleting text fields. Closes #8588. [tdd] + +* Fix that non-Mozilla browsers would display messages with the autocompleter back-button fix introduced in 1.7.1 beta 2. Fixes #7752, #8411. [josh, stetz] + +*V1.7.1 beta 3* (May 19, 2007) + +* Update to Prototype 1.5.1 final + +* New elements and handles options for Sortable.create which take arrays of elements or element ids. These overrule the normal handle and elements finding options on initialization of the sortable, and can yield huge performance increases in situations where these elements or ids are known at call time. [Thomas Fuchs] + +* Major performance improvement of Sortable.create when using the handle option. [Tobie Langel] + +* Fix Builder.node double quote escaping in attributes, fixes #8125. [Aa!] + +*V1.7.1 beta 2* (April 28, 2007) + +* Update to Prototype 1.5.1_rc4 + - Various optimizations and fixes + - http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/CHANGELOG?rev=6604 + +* Fix autocompleter indicator not appearing when calling activate() directly. Don't show indicator for local autocompleting. Fixes #7770. [pyro8019] + +* Don't clear out autocompleting fields in Mozilla-based browsers when navigating back to a page with the Back button, fixes #7752. [seanc] + +*V1.7.1 beta 1* (March 12, 2007) + +* Update to Prototype 1.5.1 r6386 + - Fixes SlideUp/SlideDown on IE + - Fixes an opacity problem with IE + - Performance optimizations + - See http://dev.rubyonrails.org/browser/spinoffs/prototype/trunk/CHANGELOG?rev=6381 for more information + +* Make builder unit tests work on IE + +* Fix id assignment for sounds on Firefox/Windows, fixes #7709 [Robert Wallis] + +* Add Sound.enable() and Sound.disable() to globally turn off Sound.play() + +* Added Sound.play(url,options) in new sound.js file. scriptaculous.js automatically includes this file. + Based on code by Jules Gravinese, used with permission. + + The sound player uses native sound support on IE, and falls back to using <embed> on other browsers, + which means it uses QuickTime for most cases. The recommended format to use is MP3. + + Examples: + Sound.play('blah.mp3'); + // --> plays sound immediately in 'global' track + Sound.play('blah.mp3',{replace:true}); + // --> stop playing all sounds in 'global' track, and play new sound + Sound.play('blah.mp3',{track:'mytrack'}); + // --> places the sound in the 'mytrack' track + Sound.play('blah.mp3',{track:'mytrack',replace:true}); + // --> stop playing all sounds in 'mytrack' track, and play new sound + + The sound effect used in the functional test is "Sword being drawn" by James Greever, released as freeware. + +* Various effects engine optimizations [Tobie Langel, Thomas Fuchs] + +* Make Ajax.InPlaceEditor more customizable: [thx godlie] + - Add an okLink option to Ajax.InPlaceEditor so you can have a link instead of a button. Uses the 'editor_ok_link' CSS class for styling, fixes #6455 + - Add an cancelButton option to Ajax.InPlaceEditor, uses the 'editor_cancel_button' CSS class + - Add textBefore-, textBetween- and textAfterControls (which default to empty strings) + - For consistency, cancel link now also gets 'editor_cancel_link' CSS class + +* Add an onDropped callback to Draggables, that fires at the end of a drag when the Draggable was dropped on a Droppable + +* Add revert: 'failure' option to Draggables to only revert if not dropped on a valid drop target, fixes #6909 [davidw] + +* Update to new Prototype Browser detection + +* Fix a memory leak with Effect.Morph in Firefox, fixes #7558 [Malard] + +* Add ability to nest single nodes in Builder.node in addition to arrays of nodes. + Examples: + var element = Builder.node('div', Builder.node('span','blah')); + + Builder.dump(); + var element = DIV(SPAN('blah')); + *V1.7.0* (January 19, 2007) * Cleanups for Effect.Morph Modified: trunk/javascript/scriptaculous/MIT-LICENSE =================================================================== --- trunk/javascript/scriptaculous/MIT-LICENSE 2008-08-25 14:29:37 UTC (rev 637) +++ trunk/javascript/scriptaculous/MIT-LICENSE 2008-08-25 23:46:39 UTC (rev 638) @@ -1,4 +1,4 @@ -Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Modified: trunk/javascript/scriptaculous/README =================================================================== --- trunk/javascript/scriptaculous/README 2008-08-25 14:29:37 UTC (rev 637) +++ trunk/javascript/scriptaculous/README 2008-08-25 23:46:39 UTC (rev 638) @@ -17,15 +17,14 @@ == Installation/Usage script.aculo.us includes the Prototype JavaScript Framework -V1.5.0. You can use later versions, as they become available -(see http://prototype.conio.net). +V1.6.0. You can use later versions, as they become available +(see http://prototypejs.org/). Put prototype.js, and the six files scriptaculous.js, builder.js, effects.js, dragdrop.js, controls.js and slider.js in a directory of your website, e.g. /javascripts. -(The unittest.js file is optional and is only needed if you -want to do unit testing on your own javascripts). +(The sound.js and unittest.js files are optional) Now, you can include the scripts by adding the following tags to the HEAD section of your HTML pages: Modified: trunk/javascript/scriptaculous/lib/prototype.js =================================================================== --- trunk/javascript/scriptaculous/lib/prototype.js 2008-08-25 14:29:37 UTC (rev 637) +++ trunk/javascript/scriptaculous/lib/prototype.js 2008-08-25 23:46:39 UTC (rev 638) @@ -1,43 +1,114 @@ -/* Prototype JavaScript framework, version 1.5.0 +/* Prototype JavaScript framework, version 1.6.0.1 * (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.5.0', + Version: '1.6.0.1', + + 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, + MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) + }, + BrowserFeatures: { - XPath: !!document.evaluate + XPath: !!document.evaluate, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + document.createElement('div').__proto__ && + document.createElement('div').__proto__ !== + document.createElement('form').__proto__ }, - ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', - emptyFunction: function() {}, + ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, K: function(x) { return x } -} +}; +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +/* Based on Alex Arnell's inheritance implementation. */ var Class = { create: function() { - return function() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { this.initialize.apply(this, arguments); } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + var subclass = function() { }; + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + + return klass; } -} +}; -var Abstract = new Object(); +Class.Methods = { + addMethods: function(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + if (!Object.keys({ toString: true }).length) + properties.push("toString", "valueOf"); + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value, value = Object.extend((function(m) { + return function() { return ancestor[m].apply(this, arguments) }; + })(property).wrap(method), { + valueOf: function() { return method }, + toString: function() { return method.toString() } + }); + } + this.prototype[property] = value; + } + + return this; + } +}; + +var Abstract = { }; + Object.extend = function(destination, source) { - for (var property in source) { + for (var property in source) destination[property] = source[property]; - } return destination; -} +}; Object.extend(Object, { inspect: function(object) { try { - if (object === undefined) return 'undefined'; + if (Object.isUndefined(object)) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : object.toString(); } catch (e) { @@ -46,6 +117,37 @@ } }, + 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.isElement(object)) return; + + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (!Object.isUndefined(value)) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + }, + + toQueryString: function(object) { + return $H(object).toQueryString(); + }, + + toHTML: function(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + }, + keys: function(object) { var keys = []; for (var property in object) @@ -61,41 +163,101 @@ }, clone: function(object) { - return Object.extend({}, object); + return Object.extend({ }, object); + }, + + isElement: function(object) { + return object && object.nodeType == 1; + }, + + isArray: function(object) { + return object && object.constructor === Array; + }, + + isHash: function(object) { + return object instanceof Hash; + }, + + isFunction: function(object) { + return typeof object == "function"; + }, + + isString: function(object) { + return typeof object == "string"; + }, + + isNumber: function(object) { + return typeof object == "number"; + }, + + isUndefined: function(object) { + return typeof object == "undefined"; } }); -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} +Object.extend(Function.prototype, { + argumentNames: function() { + var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); + return names.length == 1 && !names[0] ? [] : names; + }, -Function.prototype.bindAsEventListener = function(object) { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); - } -} + bind: function() { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } + }, -Object.extend(Number.prototype, { - toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; + bindAsEventListener: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } }, - succ: function() { - return this + 1; + curry: function() { + if (!arguments.length) return this; + var __method = this, args = $A(arguments); + return function() { + return __method.apply(this, args.concat($A(arguments))); + } }, - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; + delay: function() { + var __method = this, args = $A(arguments), timeout = args.shift() * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + }, + + wrap: function(wrapper) { + var __method = this; + return function() { + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); + } + }, + + methodize: function() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + return __method.apply(null, [this].concat($A(arguments))); + }; } }); +Function.prototype.defer = Function.prototype.delay.curry(0.01); + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + var Try = { these: function() { var returnValue; @@ -105,17 +267,22 @@ try { returnValue = lambda(); break; - } catch (e) {} + } catch (e) { } } return returnValue; } -} +}; +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; + /*--------------------------------------------------------------------------*/ -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { +var PeriodicalExecuter = Class.create({ initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; @@ -128,6 +295,10 @@ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, + execute: function() { + this.callback(this); + }, + stop: function() { if (!this.timer) return; clearInterval(this.timer); @@ -138,16 +309,26 @@ if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; - this.callback(this); + this.execute(); } finally { this.currentlyExecuting = false; } } } -} -String.interpret = function(value){ - return value == null ? '' : String(value); -} +}); +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) { @@ -168,7 +349,7 @@ sub: function(pattern, replacement, count) { replacement = this.gsub.prepareReplacement(replacement); - count = count === undefined ? 1 : count; + count = Object.isUndefined(count) ? 1 : count; return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; @@ -178,14 +359,14 @@ scan: function(pattern, iterator) { this.gsub(pattern, iterator); - return this; + return String(this); }, truncate: function(length, truncation) { length = length || 30; - truncation = truncation === undefined ? '...' : truncation; + truncation = Object.isUndefined(truncation) ? '...' : truncation; return this.length > length ? - this.slice(0, length - truncation.length) + truncation : this; + this.slice(0, length - truncation.length) + truncation : String(this); }, strip: function() { @@ -213,35 +394,34 @@ }, 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'); + var div = new Element('div'); div.innerHTML = this.stripTags(); return div.childNodes[0] ? (div.childNodes.length > 1 ? - $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) : + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : div.childNodes[0].nodeValue) : ''; }, toQueryParams: function(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return {}; + if (!match) return { }; - return match[1].split(separator || '&').inject({}, function(hash, pair) { + 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; + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); - if (hash[name] !== undefined) { - if (hash[name].constructor != Array) - hash[name] = [hash[name]]; - if (value) hash[name].push(value); + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); } - else hash[name] = value; + else hash[key] = value; } return hash; }); @@ -256,6 +436,10 @@ String.fromCharCode(this.charCodeAt(this.length - 1) + 1); }, + times: function(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + }, + camelize: function() { var parts = this.split('-'), len = parts.length; if (len == 1) return parts[0]; @@ -270,7 +454,7 @@ return camelized; }, - capitalize: function(){ + capitalize: function() { return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); }, @@ -283,52 +467,131 @@ }, inspect: function(useDoubleQuotes) { - var escapedString = this.replace(/\\/g, '\\\\'); - if (useDoubleQuotes) - return '"' + escapedString.replace(/"/g, '\\"') + '"'; - else - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + 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); + }, + + unfilterJSON: function(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + }, + + isJSON: function() { + var str = this; + if (str.blank()) return false; + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + }, + + evalJSON: function(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) === 0; + }, + + endsWith: function(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); + }, + + interpolate: function(object, pattern) { + return new Template(this, pattern).evaluate(object); } }); +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + }, + unescapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + } +}); + String.prototype.gsub.prepareReplacement = function(replacement) { - if (typeof replacement == 'function') return replacement; + if (Object.isFunction(replacement)) return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; -} +}; String.prototype.parseQuery = String.prototype.toQueryParams; -var Template = Class.create(); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; -Template.prototype = { +Object.extend(String.prototype.escapeHTML, { + div: document.createElement('div'), + text: document.createTextNode('') +}); + +with (String.prototype.escapeHTML) div.appendChild(text); + +var Template = Class.create({ initialize: function(template, pattern) { this.template = template.toString(); - this.pattern = pattern || Template.Pattern; + this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { + if (Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + return this.template.gsub(this.pattern, function(match) { - var before = match[1]; + if (object == null) return ''; + + var before = match[1] || ''; if (before == '\\') return match[2]; - return before + String.interpret(object[match[3]]); - }); + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }.bind(this)); } -} +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; -var $break = new Object(); -var $continue = new Object(); +var $break = { }; var Enumerable = { - each: function(iterator) { + each: function(iterator, context) { var index = 0; + iterator = iterator.bind(context); 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; @@ -336,40 +599,45 @@ return this; }, - eachSlice: function(number, iterator) { + eachSlice: function(number, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var index = -number, slices = [], array = this.toArray(); while ((index += number) < array.length) slices.push(array.slice(index, index+number)); - return slices.map(iterator); + return slices.collect(iterator, context); }, - all: function(iterator) { + all: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result = true; this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); + result = result && !!iterator(value, index); if (!result) throw $break; }); return result; }, - any: function(iterator) { + any: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result = false; this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) + if (result = !!iterator(value, index)) throw $break; }); return result; }, - collect: function(iterator) { + collect: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var results = []; this.each(function(value, index) { - results.push((iterator || Prototype.K)(value, index)); + results.push(iterator(value, index)); }); return results; }, - detect: function(iterator) { + detect: function(iterator, context) { + iterator = iterator.bind(context); var result; this.each(function(value, index) { if (iterator(value, index)) { @@ -380,7 +648,8 @@ return result; }, - findAll: function(iterator) { + findAll: function(iterator, context) { + iterator = iterator.bind(context); var results = []; this.each(function(value, index) { if (iterator(value, index)) @@ -389,17 +658,24 @@ return results; }, - grep: function(pattern, iterator) { + grep: function(filter, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var results = []; + + if (Object.isString(filter)) + filter = new RegExp(filter); + this.each(function(value, index) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(value, index)); - }) + if (filter.match(value)) + results.push(iterator(value, index)); + }); return results; }, include: function(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + var found = false; this.each(function(value) { if (value == object) { @@ -411,14 +687,15 @@ }, inGroupsOf: function(number, fillWith) { - fillWith = fillWith === undefined ? null : fillWith; + fillWith = Object.isUndefined(fillWith) ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); }, - inject: function(memo, iterator) { + inject: function(memo, iterator, context) { + iterator = iterator.bind(context); this.each(function(value, index) { memo = iterator(memo, value, index); }); @@ -432,30 +709,33 @@ }); }, - max: function(iterator) { + max: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result; this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (result == undefined || value >= result) + value = iterator(value, index); + if (result == null || value >= result) result = value; }); return result; }, - min: function(iterator) { + min: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result; this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (result == undefined || value < result) + value = iterator(value, index); + if (result == null || value < result) result = value; }); return result; }, - partition: function(iterator) { + partition: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var trues = [], falses = []; this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? + (iterator(value, index) ? trues : falses).push(value); }); return [trues, falses]; @@ -463,13 +743,14 @@ pluck: function(property) { var results = []; - this.each(function(value, index) { + this.each(function(value) { results.push(value[property]); }); return results; }, - reject: function(iterator) { + reject: function(iterator, context) { + iterator = iterator.bind(context); var results = []; this.each(function(value, index) { if (!iterator(value, index)) @@ -478,7 +759,8 @@ return results; }, - sortBy: function(iterator) { + sortBy: function(iterator, context) { + iterator = iterator.bind(context); return this.map(function(value, index) { return {value: value, criteria: iterator(value, index)}; }).sort(function(left, right) { @@ -493,7 +775,7 @@ zip: function() { var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') + if (Object.isFunction(args.last())) iterator = args.pop(); var collections = [this].concat(args).map($A); @@ -509,31 +791,42 @@ inspect: function() { return '#<Enumerable:' + this.toArray().inspect() + '>'; } -} +}; Object.extend(Enumerable, { map: Enumerable.collect, find: Enumerable.detect, select: Enumerable.findAll, + filter: Enumerable.findAll, member: Enumerable.include, - entries: Enumerable.toArray + entries: Enumerable.toArray, + every: Enumerable.all, + some: Enumerable.any }); -var $A = Array.from = function(iterable) { +function $A(iterable) { if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0, length = iterable.length; i < length; i++) - results.push(iterable[i]); + if (iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +if (Prototype.Browser.WebKit) { + function $A(iterable) { + if (!iterable) return []; + if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && + iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; return results; } } +Array.from = $A; + Object.extend(Array.prototype, Enumerable); -if (!Array.prototype._reverse) - Array.prototype._reverse = Array.prototype.reverse; +if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; Object.extend(Array.prototype, { _each: function(iterator) { @@ -562,7 +855,7 @@ flatten: function() { return this.inject([], function(array, value) { - return array.concat(value && value.constructor == Array ? + return array.concat(Object.isArray(value) ? value.flatten() : [value]); }); }, @@ -574,12 +867,6 @@ }); }, - indexOf: function(object) { - 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(); }, @@ -588,12 +875,20 @@ return this.length > 1 ? this : this[0]; }, - uniq: function() { - return this.inject([], function(array, value) { - return array.include(value) ? array : array.concat([value]); + 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; }); }, + intersect: function(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + }, + clone: function() { return [].concat(this); }, @@ -604,125 +899,187 @@ inspect: function() { return '[' + this.map(Object.inspect).join(', ') + ']'; + }, + + toJSON: function() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (!Object.isUndefined(value)) results.push(value); + }); + return '[' + results.join(', ') + ']'; } }); +// use native browser JS 1.6 implementation if available +if (Object.isFunction(Array.prototype.forEach)) + Array.prototype._each = Array.prototype.forEach; + +if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; +}; + +if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; +}; + Array.prototype.toArray = Array.prototype.clone; -function $w(string){ +function $w(string) { + if (!Object.isString(string)) return []; string = string.strip(); return string ? string.split(/\s+/) : []; } -if(window.opera){ - Array.prototype.concat = function(){ +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++) + 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 (Object.isArray(arguments[i])) { + 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(obj) { - Object.extend(this, obj || {}); -}; +Object.extend(Number.prototype, { + toColorPart: function() { + return this.toPaddedString(2, 16); + }, -Object.extend(Hash, { - toQueryString: function(obj) { - var parts = []; + succ: function() { + return this + 1; + }, - this.prototype._each.call(obj, function(pair) { - if (!pair.key) return; + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + }, - if (pair.value && pair.value.constructor == Array) { - var values = pair.value.compact(); - if (values.length < 2) pair.value = values.reduce(); - else { - key = encodeURIComponent(pair.key); - values.each(function(value) { - value = value != undefined ? encodeURIComponent(value) : ''; - parts.push(key + '=' + encodeURIComponent(value)); - }); - return; - } - } - if (pair.value == undefined) pair[1] = ''; - parts.push(pair.map(encodeURIComponent).join('=')); - }); + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, - return parts.join('&'); + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; } }); -Object.extend(Hash.prototype, Enumerable); -Object.extend(Hash.prototype, { - _each: function(iterator) { - for (var key in this) { - var value = this[key]; - if (value && value == Hash.prototype[key]) continue; +$w('abs round ceil floor').each(function(method){ + Number.prototype[method] = Math[method].methodize(); +}); +function $H(object) { + return new Hash(object); +}; - var pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, +var Hash = Class.create(Enumerable, (function() { - keys: function() { - return this.pluck('key'); - }, + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } - values: function() { - return this.pluck('value'); - }, + return { + initialize: function(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + }, - merge: function(hash) { - return $H(hash).inject(this, function(mergedHash, pair) { - mergedHash[pair.key] = pair.value; - return mergedHash; - }); - }, + _each: function(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, - 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) + set: function(key, value) { + return this._object[key] = value; + }, + + get: function(key) { + return this._object[key]; + }, + + unset: function(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + }, + + toObject: function() { + return Object.clone(this._object); + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + index: function(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + }, + + merge: function(object) { + return this.clone().update(object); + }, + + update: function(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return values.map(toQueryPair.curry(key)).join('&'); } - } - delete this[arguments[i]]; - } - return result; - }, + return toQueryPair(key, values); + }).join('&'); + }, - toQueryString: function() { - return Hash.toQueryString(this); - }, + inspect: function() { + return '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + }, - inspect: function() { - return '#<Hash:{' + this.map(function(pair) { - return pair.map(Object.inspect).join(': '); - }).join(', ') + '}>'; + toJSON: function() { + return Object.toJSON(this.toObject()); + }, + + clone: function() { + return new Hash(this); + } } -}); +})()); -function $H(object) { - if (object && object.constructor == Hash) return object; - return new Hash(object); -}; -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { +Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; +Hash.from = $H; +var ObjectRange = Class.create(Enumerable, { initialize: function(start, end, exclusive) { this.start = start; this.end = end; @@ -748,7 +1105,7 @@ var $R = function(start, end, exclusive) { return new ObjectRange(start, end, exclusive); -} +}; var Ajax = { getTransport: function() { @@ -760,7 +1117,7 @@ }, activeRequestCount: 0 -} +}; Ajax.Responders = { responders: [], @@ -780,10 +1137,10 @@ dispatch: function(callback, request, transport, json) { this.each(function(responder) { - if (typeof responder[callback] == 'function') { + if (Object.isFunction(responder[callback])) { try { responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} + } catch (e) { } } }); } @@ -792,49 +1149,45 @@ Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ - onCreate: function() { - Ajax.activeRequestCount++; - }, - onComplete: function() { - Ajax.activeRequestCount--; - } + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } }); -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { +Ajax.Base = Class.create({ + initialize: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', - parameters: '' - } - Object.extend(this.options, options || {}); + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); this.options.method = this.options.method.toLowerCase(); - if (typeof this.options.parameters == 'string') + + if (Object.isString(this.options.parameters)) this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); } -} +}); -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { +Ajax.Request = Class.create(Ajax.Base, { _complete: false, - initialize: function(url, options) { + initialize: function($super, url, options) { + $super(options); this.transport = Ajax.getTransport(); - this.setOptions(options); this.request(url); }, request: function(url) { this.url = url; this.method = this.options.method; - var params = this.options.parameters; + var params = Object.clone(this.options.parameters); if (!['get', 'post'].include(this.method)) { // simulate other verbs over post @@ -842,29 +1195,32 @@ this.method = 'post'; } - params = Hash.toQueryString(params); - if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_=' + this.parameters = params; - // when GET, append parameters to URL - if (this.method == 'get' && params) - this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params; + if (params = Object.toQueryString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } try { - Ajax.Responders.dispatch('onCreate', this, this.transport); + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); - if (this.options.asynchronous) - setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); - var body = this.method == 'post' ? (this.options.postBody || params) : null; + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); - this.transport.send(body); - /* Force Firefox to handle ready state 4 for synchronous requests */ if (!this.options.asynchronous && this.transport.overrideMimeType) this.onStateChange(); @@ -905,7 +1261,7 @@ if (typeof this.options.requestHeaders == 'object') { var extras = this.options.requestHeaders; - if (typeof extras.push == 'function') + if (Object.isFunction(extras.push)) for (var i = 0, length = extras.length; i < length; i += 2) headers[extras[i]] = extras[i+1]; else @@ -917,32 +1273,39 @@ }, success: function() { - return !this.transport.status - || (this.transport.status >= 200 && this.transport.status < 300); + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); }, + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); if (state == 'Complete') { try { this._complete = true; - (this.options['on' + this.transport.status] + (this.options['on' + response.status] || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); + || Prototype.emptyFunction)(response, response.headerJSON); } catch (e) { this.dispatchException(e); } - if ((this.getHeader('Content-type') || 'text/javascript').strip(). - match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) - this.evalResponse(); + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); } try { - (this.options['on' + state] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + state, this, transport, json); + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); } catch (e) { this.dispatchException(e); } @@ -955,20 +1318,13 @@ getHeader: function(name) { try { - return this.transport.getResponseHeader(name); + return this.transport.getResponseHeader(name) || null; } 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); + return eval((this.transport.responseText || '').unfilterJSON()); } catch (e) { this.dispatchException(e); } @@ -980,57 +1336,126 @@ } }); -Ajax.Updater = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { - initialize: function(container, url, options) { +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, 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); + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); }).bind(this); - this.request(url); + $super(url, options); }, - updateContent: function() { - var receiver = this.container[this.success() ? 'success' : 'failure']; - var response = this.transport.responseText; + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; - if (!this.options.evalScripts) response = response.stripScripts(); + if (!options.evalScripts) responseText = responseText.stripScripts(); if (receiver = $(receiver)) { - if (this.options.insertion) - new this.options.insertion(receiver, response); - else - receiver.update(response); + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); } - - 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); +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); this.decay = (this.options.decay || 1); - this.updater = {}; + this.updater = { }; this.container = container; this.url = url; @@ -1048,15 +1473,14 @@ (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, - updateComplete: function(request) { + updateComplete: function(response) { if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? + this.decay = (response.responseText == this.lastText ? this.decay * this.options.decay : 1); - this.lastText = request.responseText; + this.lastText = response.responseText; } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); }, onTimerEvent: function() { @@ -1069,7 +1493,7 @@ elements.push($(arguments[i])); return elements; } - if (typeof element == 'string') + if (Object.isString(element)) element = document.getElementById(element); return Element.extend(element); } @@ -1080,64 +1504,52 @@ 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)); + results.push(Element.extend(query.snapshotItem(i))); return results; }; } -document.getElementsByClassName = function(className, parentElement) { - if (Prototype.BrowserFeatures.XPath) { - var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; - return document._getElementsByXPath(q, parentElement); - } else { - 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; - } -}; - /*--------... [truncated message content] |