Merge branch 'master' of git@github.com:sstephenson/prototype

This commit is contained in:
Andrew Dupont 2009-09-15 18:27:56 -05:00
commit 4dedcd3b62
15 changed files with 566 additions and 116 deletions

View File

@ -8,7 +8,7 @@
*
* Actual requests are made by creating instances of [[Ajax.Request]].
*
* <h4>Request headers</h4>
* <h5>Request headers</h5>
*
* The following headers are sent with all Ajax requests (and can be
* overridden with the `requestHeaders` option described below):
@ -21,7 +21,7 @@
* * `Content-type` is automatically determined based on the `contentType`
* and `encoding` options.
*
* <h4>Ajax options</h4>
* <h5>Ajax options</h5>
*
* All Ajax classes share a common set of _options_ and _callbacks_.
* Callbacks are called at various points in the life-cycle of a request, and
@ -64,7 +64,7 @@
* `true` otherwise): Sanitizes the contents of
* [[Ajax.Response#responseText]] before evaluating it.
*
* <h4>Common callbacks</h4>
* <h5>Common callbacks</h5>
*
* When used on individual instances, all callbacks (except `onException`) are
* invoked with two parameters: the `XMLHttpRequest` object and the result of

View File

@ -16,7 +16,7 @@
* keeping track of the response text so it can (optionally) react to
* receiving the exact same response consecutively.
*
* <h4>Additional options</h4>
* <h5>Additional options</h5>
*
* `Ajax.PeriodicalUpdater` features all the common options and callbacks
* described in the [[Ajax section]] &mdash; _plus_ those added by `Ajax.Updater`.
@ -34,7 +34,7 @@
* is the same; when the result is different once again, `frequency` will
* revert to its original value.
*
* <h4>Disabling and re-enabling a <code>PeriodicalUpdater</code></h4>
* <h5>Disabling and re-enabling a <code>PeriodicalUpdater</code></h5>
*
* You can hit the brakes on a running `PeriodicalUpdater` by calling
* [[Ajax.PeriodicalUpdater#stop]]. If you wish to re-enable it later, call

View File

@ -5,7 +5,7 @@
*
* `Ajax.Request` is a general-purpose class for making HTTP requests.
*
* <h4>Automatic JavaScript response evaluation</h4>
* <h5>Automatic JavaScript response evaluation</h5>
*
* If an Ajax request follows the _same-origin policy_ **and** its response
* has a JavaScript-related `Content-type`, the content of the `responseText`
@ -28,7 +28,7 @@
*
* The MIME-type string is examined in a case-insensitive manner.
*
* <h4>Methods you may find useful</h4>
* <h5>Methods you may find useful</h5>
*
* Instances of the `Request` object provide several methods that can come in
* handy in your callback functions, especially once the request is complete.

View File

@ -34,7 +34,7 @@
* }
* });
*
* <h4>Responder callbacks</h4>
* <h5>Responder callbacks</h5>
*
* The callbacks for responders are similar to the callbacks described in
* the [[Ajax section]], but take a different signature. They're invoked with

View File

@ -7,7 +7,7 @@
* `Ajax.Updater` is a subclass of [[Ajax.Request]] built for a common
* use-case.
*
* <h4>Example</h4>
* <h5>Example</h5>
*
* new Ajax.Updater('items', '/items', {
* parameters: { text: $F('text') }
@ -17,13 +17,13 @@
* parameters); it will then replace the contents of the element with the ID
* of `items` with whatever response it receives.
*
* <h4>Callbacks</h4>
* <h5>Callbacks</h5>
*
* `Ajax.Updater` supports all the callbacks listed in the [[Ajax section]].
* Note that the `onComplete` callback will be invoked **after** the element
* is updated.
*
* <h4>Additional options</h4>
* <h5>Additional options</h5>
*
* `Ajax.Updater` has some options of its own apart from the common options
* described in the [[Ajax section]]:
@ -37,7 +37,7 @@
* `top`, `bottom`, `before`, or `after` &mdash; and _inserts_ the contents of the
* response in the manner described by [[Element#insert]].
*
* <h4>More About `evalScripts`</h4>
* <h5>More About `evalScripts`</h5>
*
* If you use `evalScripts: true`, any _inline_ `<script>` block will be evaluated.
* This **does not** mean it will be evaluated in the global scope; it won't, and that
@ -45,7 +45,7 @@
* that only inline `<script>` blocks are supported; external scripts are ignored.
* See [[String#evalScripts]] for the details.
*
* <h4>Single container, or success/failure split?</h4>
* <h5>Single container, or success/failure split?</h5>
*
* The examples above all assume you're going to update the same container
* whether your request succeeds or fails. Instead, you may want to update

View File

@ -5,7 +5,7 @@
*
* The namespace for Prototype's event system.
*
* <h4>Events: a fine mess</h4>
* <h5>Events: a fine mess</h5>
*
* Event management is one of the really sore spots of cross-browser
* scripting.
@ -17,7 +17,7 @@
* Safari). Also, MSIE has a tendency to leak memory when it comes to
* discarding event handlers.
*
* <h4>Prototype to the rescue</h4>
* <h5>Prototype to the rescue</h5>
*
* Of course, Prototype smooths it over so well you'll forget these
* troubles even exist. Enter the `Event` namespace. It is replete with

View File

@ -490,7 +490,7 @@ Form.Element.Serializers = {
* [[Form.Observer]], which serializes a form and triggers when the result has changed; and
* [[Form.Element.Observer]], which triggers when the value of a given form field changes.
*
* <h4>Creating Your Own TimedObserver Implementations</h4>
* <h5>Creating Your Own TimedObserver Implementations</h5>
*
* It's easy to create your own `TimedObserver` implementations: Simply subclass `TimedObserver`
* and provide the `getValue()` method. For example, this is the complete source code for

View File

@ -52,7 +52,7 @@ Array.from = $A;
* their `[]` indexing operator. They become very powerful objects that
* greatly simplify the code for 99% of the common use cases involving them.
*
* <h4>Why you should stop using for...in to iterate</h4>
* <h5>Why you should stop using for...in to iterate</h5>
*
* Many JavaScript authors have been misled into using the `for...in` JavaScript
* construct to loop over array elements. This kind of code just won't work
@ -77,7 +77,7 @@ Array.from = $A;
* those coming from the [[Enumerable]] module, and those Prototype puts in the
* Array namespace (listed further below).
*
* <h4>What you should use instead</h4>
* <h5>What you should use instead</h5>
*
* You can revert to vanilla loops:
*
@ -99,7 +99,7 @@ Array.from = $A;
* module. So manual loops should be fairly rare.
*
*
* <h4>A note on performance</h4>
* <h5>A note on performance</h5>
*
* Should you have a very large array, using iterators with lexical closures
* (anonymous functions that you pass to the iterators and that get invoked at
@ -134,7 +134,7 @@ Array.from = $A;
*
* Clears the array (makes it empty) and returns the array reference.
*
* ### Example
* <h5>Example</h5>
*
* var guys = ['Sam', 'Justin', 'Andrew', 'Dan'];
* guys.clear();
@ -170,7 +170,7 @@ Array.from = $A;
*
* Returns a **copy** of the array without any `null` or `undefined` values.
*
* ### Example
* <h5>Example</h5>
*
* var orig = [undefined, 'A', undefined, 'B', null, 'C'];
* var copy = orig.compact();
@ -193,7 +193,7 @@ Array.from = $A;
* useful when handling the results of a recursive collection algorithm,
* for instance.
*
* ### Example
* <h5>Example</h5>
*
* var a = ['frank', ['bob', 'lisa'], ['jill', ['tom', 'sally']]];
* var b = a.flatten();
@ -216,7 +216,7 @@ Array.from = $A;
* Produces a new version of the array that does not contain any of the
* specified values, leaving the original array unchanged.
*
* ### Examples
* <h5>Examples</h5>
*
* [3, 5, 6].without(3)
* // -> [5, 6]
@ -238,7 +238,7 @@ Array.from = $A;
*
* Reverses the array's contents, optionally cloning it first.
*
* ### Examples
* <h5>Examples</h5>
*
* // Making a copy
* var nums = [3, 5, 6, 1, 20];
@ -266,7 +266,7 @@ Array.from = $A;
* On large arrays when `sorted` is `false`, this method has a potentially
* large performance cost.
*
* ### Examples
* <h5>Examples</h5>
*
* [1, 3, 2, 1].uniq();
* // -> [1, 2, 3]
@ -325,7 +325,7 @@ Array.from = $A;
*
* Returns the debug-oriented string representation of an array.
*
* ### Example
* <h5>Example</h5>
*
* ['Apples', {good: 'yes', bad: 'no'}, 3, 34].inspect()
* // -> "['Apples', [object Object], 3, 34]"
@ -339,7 +339,7 @@ Array.from = $A;
*
* Returns a JSON string representation of the array.
*
* ### Example
* <h5>Example</h5>
*
* ['a', {b: null}].toJSON();
* //-> '["a", {"b": null}]'
@ -363,7 +363,7 @@ Array.from = $A;
* or `-1` if `item` doesn't exist in the array. `Array#indexOf` compares
* items using *strict equality* (`===`).
*
* ### Examples
* <h5>Examples</h5>
*
* [3, 5, 6, 1, 20].indexOf(1)
* // -> 3

View File

@ -10,7 +10,7 @@
* Produces a string representation of the date in ISO 8601 format.
* The time zone is always UTC, as denoted by the suffix "Z".
*
* ### Example
* <h5>Example</h5>
*
* var d = new Date(1969, 11, 31, 19);
* d.getTimezoneOffset();

View File

@ -12,7 +12,7 @@
* are [[Array]] and [[Hash]], but you'll find it in less obvious spots as
* well, such as in [[ObjectRange]] and various DOM- or Ajax-related objects.
*
* <h4>The <code>context</code> parameter</h4>
* <h5>The <code>context</code> parameter</h5>
*
* Every method of `Enumerable` that takes an iterator also takes the "context
* object" as the next (optional) parameter. The context object is what the
@ -31,7 +31,7 @@
* If there is no `context` argument, the iterator function will execute in
* the scope from which the `Enumerable` method itself was called.
*
* <h4>Mixing <code>Enumerable</code> into your own objects</h4>
* <h5>Mixing <code>Enumerable</code> into your own objects</h5>
*
* So, let's say you've created your very own collection-like object (say,
* some sort of Set, or perhaps something that dynamically fetches data
@ -93,12 +93,12 @@ var Enumerable = (function() {
*
* Calls `iterator` for each item in the collection.
*
* ### Examples
* <h5>Examples</h5>
*
* ['one', 'two', 'three'].each(alert);
* // Alerts "one", then alerts "two", then alerts "three"
*
* ### Built-In Variants
* <h5>Built-In Variants</h5>
*
* Most of the common use cases for `each` are already available pre-coded
* as other methods on `Enumerable`. Whether you want to find the first
@ -131,7 +131,7 @@ var Enumerable = (function() {
* fewer than `number` items; it won't "pad" the last group with empty
* values. For that behavior, use [[Enumerable#inGroupsOf]].
*
* ### Example
* <h5>Example</h5>
*
* var students = [
* { name: 'Sunny', age: 20 },
@ -168,7 +168,7 @@ var Enumerable = (function() {
* is boolean-equivalent to `false`, such as `undefined`, `0`, or indeed
* `false`);
*
* ### Examples
* <h5>Examples</h5>
*
* [].all();
* // -> true (empty arrays have no elements that could be falsy)
@ -203,7 +203,7 @@ var Enumerable = (function() {
* Determines whether at least one element is truthy (boolean-equivalent to
* `true`), either directly or through computation by the provided iterator.
*
* ### Examples
* <h5>Examples</h5>
*
* [].any();
* // -> false (empty arrays have no elements that could be truthy)
@ -235,7 +235,7 @@ var Enumerable = (function() {
* `iterator` is provided, the elements are simply copied to the
* returned array.
*
* ### Examples
* <h5>Examples</h5>
*
* ['Hitch', "Hiker's", 'Guide', 'to', 'the', 'Galaxy'].collect(function(s) {
* return s.charAt(0).toUpperCase();
@ -266,7 +266,7 @@ var Enumerable = (function() {
* Returns the first element for which the iterator returns a truthy value.
* Aliased by the [[Enumerable#find]] method.
*
* ### Example
* <h5>Example</h5>
*
* [1, 7, -2, -4, 5].detect(function(n) { return n < 0; });
* // -> -2
@ -291,7 +291,7 @@ var Enumerable = (function() {
* Returns all the elements for which the iterator returned a truthy value.
* For the opposite operation, see [[Enumerable#reject]].
*
* ### Example
* <h5>Example</h5>
*
* [1, 'two', 3, 'four', 5].findAll(Object.isString);
* // -> ['two', 'four']
@ -326,7 +326,7 @@ var Enumerable = (function() {
* or a falsy value not to. Note that the `RegExp` `match` function will
* convert elements to Strings to perform matching.
*
* ### Examples
* <h5>Examples</h5>
*
* // Get all strings containing a repeated letter
* ['hello', 'world', 'this', 'is', 'cool'].grep(/(.)\1/);
@ -358,7 +358,7 @@ var Enumerable = (function() {
* based on the `==` comparison operator (equality with implicit type
* conversion).
*
* ### Examples
* <h5>Examples</h5>
*
* $R(1, 15).include(10);
* // -> true
@ -392,7 +392,7 @@ var Enumerable = (function() {
* Like [[Enumerable#eachSlice]], but pads out the last chunk with the
* specified value if necessary and doesn't support the `iterator` function.
*
* ### Examples
* <h5>Examples</h5>
*
* var students = [
* { name: 'Sunny', age: 20 },
@ -434,7 +434,7 @@ var Enumerable = (function() {
* argument, the element as its second argument, and the element's index as
* its third. It returns the new value for the accumulator.
*
* ### Examples
* <h5>Examples</h5>
*
* $R(1,10).inject(0, function(acc, n) { return acc + n; });
* // -> 55 (sum of 1 to 10)
@ -462,7 +462,7 @@ var Enumerable = (function() {
* Invokes the same method, with the same arguments, for all items in a
* collection. Returns an array of the results of the method calls.
*
* ### Examples
* <h5>Examples</h5>
*
* ['hello', 'world'].invoke('toUpperCase');
* // -> ['HELLO', 'WORLD']
@ -499,7 +499,7 @@ var Enumerable = (function() {
* evaluated, and its index in the enumeration; it should return the value
* `max` should consider (and potentially return).
*
* ### Examples
* <h5>Examples</h5>
*
* ['c', 'b', 'a'].max();
* // -> 'c'
@ -539,7 +539,7 @@ var Enumerable = (function() {
* evaluated, and its index in the enumeration; it should return the value
* `min` should consider (and potentially return).
*
* ### Examples
* <h5>Examples</h5>
*
* ['c', 'b', 'a'].min();
* // -> 'a'
@ -578,7 +578,7 @@ var Enumerable = (function() {
* then using [[Enumerable#reject]] because the enumeration is only processed
* once.
*
* ### Examples
* <h5>Examples</h5>
*
* ['hello', null, 42, false, true, , 17].partition();
* // -> [['hello', 42, true, 17], [null, false, undefined]]
@ -606,7 +606,7 @@ var Enumerable = (function() {
* and [[Enumerable#each]]: fetching the same property for all of the
* elements. Returns an array of the property values.
*
* ### Example
* <h5>Example</h5>
*
* ['hello', 'world', 'this', 'is', 'nice'].pluck('length');
* // -> [5, 5, 4, 2, 4]
@ -628,7 +628,7 @@ var Enumerable = (function() {
* Returns all the elements for which the iterator returns a falsy value.
* For the opposite operation, see [[Enumerable#findAll]].
*
* ### Example
* <h5>Example</h5>
*
* [1, "two", 3, "four", 5].reject(Object.isString);
* // -> [1, 3, 5]
@ -657,7 +657,7 @@ var Enumerable = (function() {
* `sortBy` does not guarantee a *stable* sort; adjacent equivalent elements
* may be swapped.
*
* ### Example
* <h5>Example</h5>
*
* ['hello', 'world', 'this', 'is', 'nice'].sortBy(function(s) {
* return s.length;
@ -681,7 +681,7 @@ var Enumerable = (function() {
*
* Returns an Array containing the elements of the enumeration.
*
* ### Example
* <h5>Example</h5>
*
* $R(1, 5).toArray();
* // -> [1, 2, 3, 4, 5]
@ -708,7 +708,7 @@ var Enumerable = (function() {
* If supplied, `iterator` is called with each tuple as its only argument
* and should return the value to use in place of that tuple.
*
* ### Examples
* <h5>Examples</h5>
*
* var firstNames = ['Jane', 'Nitin', 'Guy'];
* var lastNames = ['Doe', 'Patel', 'Forcier'];

View File

@ -23,6 +23,17 @@ Object.extend(Function.prototype, (function() {
* Reads the argument names as stated in the function definition and returns
* the values as an array of strings (or an empty array if the function is
* defined without parameters).
*
* <h5>Examples</h5>
*
* function fn(foo, bar) {
* return foo + bar;
* }
* fn.argumentNames();
* //-> ['foo', 'bar']
*
* Prototype.emptyFunction.argumentNames();
* //-> []
**/
function argumentNames() {
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
@ -31,12 +42,68 @@ Object.extend(Function.prototype, (function() {
return names.length == 1 && !names[0] ? [] : names;
}
/**
* Function#bind(object[, args...]) -> Function
* - object (Object): The object to bind to.
/** related to: Function#bindAsEventListener
* Function#bind(context[, args...]) -> Function
* - context (Object): The object to bind to.
* - args (?): Optional additional arguments to curry for the function.
*
* Wraps the function in another, locking its execution scope to an object
* specified by `object`.
* Binds this function to the given `context` by wrapping it in another
* function and returning the wrapper. Whenever the resulting "bound"
* function is called, it will call the original ensuring that `this` is set
* to `context`. Also optionally curries arguments for the function.
*
* <h5>Examples</h5>
*
* A typical use of `Function#bind` is to ensure that a callback (event
* handler, etc.) that is an object method gets called with the correct
* object as its context (`this` value):
*
* var AlertOnClick = Class.create({
* initialize: function(msg) {
* this.msg = msg;
* },
* handleClick: function(event) {
* event.stop();
* alert(this.msg);
* }
* });
* var myalert = new AlertOnClick("Clicked!");
* $('foo').observe('click', myalert.handleClick); // <= WRONG
* // -> If 'foo' is clicked, the alert will be blank; "this" is wrong
* $('bar').observe('click', myalert.handleClick.bind(myalert)); // <= RIGHT
* // -> If 'bar' is clicked, the alert will be "Clicked!"
*
* `bind` can also *curry* (burn in) arguments for the function if you
* provide them after the `context` argument:
*
* var Averager = Class.create({
* initialize: function() {
* this.count = 0;
* this.total = 0;
* },
* add: function(addend) {
* ++this.count;
* this.total += addend;
* },
* getAverage: function() {
* return this.count == 0 ? NaN : this.total / this.count;
* }
* });
* var a = new Averager();
* var b = new Averager();
* var aAdd5 = a.add.bind(a, 5); // Bind to a, curry 5
* var aAdd10 = a.add.bind(a, 10); // Bind to a, curry 10
* var bAdd20 = b.add.bind(b, 20); // Bind to b, curry 20
* aAdd5();
* aAdd10();
* bAdd20();
* bAdd20();
* alert(a.getAverage());
* // -> Alerts "7.5" (average of [5, 10])
* alert(b.getAverage());
* // -> Alerts "20" (average of [20, 20])
*
* (To curry without binding, see [[Function#curry]].)
**/
function bind(context) {
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
@ -48,12 +115,59 @@ Object.extend(Function.prototype, (function() {
}
/** related to: Function#bind
* Function#bindAsEventListener(object[, args...]) -> Function
* - object (Object): The object to bind to.
* Function#bindAsEventListener(context[, args...]) -> Function
* - context (Object): The object to bind to.
* - args (?): Optional arguments to curry after the event argument.
*
* An event-specific variant of [[Function#bind]] which ensures the function
* will recieve the current event object as the first argument when
* executing.
*
* It is not necessary to use `bindAsEventListener` for all bound event
* handlers; [[Function#bind]] works well for the vast majority of cases.
* `bindAsEventListener` is only needed when:
*
* - Using old-style DOM0 handlers rather than handlers hooked up via
* [[Event.observe]], because `bindAsEventListener` gets the event object
* from the right place (even on MSIE). (If you're using `Event.observe`,
* that's already handled.)
* - You want to bind an event handler and curry additional arguments but
* have those arguments appear after, rather than before, the event object.
* This mostly happens if the number of arguments will vary, and so you
* want to know the event object is the first argument.
*
* <h5>Example</h5>
*
* var ContentUpdater = Class.create({
* initialize: function(initialData) {
* this.data = Object.extend({}, initialData);
* },
* // On an event, update the content in the elements whose
* // IDs are passed as arguments from our data
* updateTheseHandler: function(event) {
* var argIndex, id, element;
* event.stop();
* for (argIndex = 1; argIndex < arguments.length; ++argIndex) {
* id = arguments[argIndex];
* element = $(id);
* if (element) {
* element.update(String(this.data[id]).escapeHTML());
* }
* }
* }
* });
* var cu = new ContentUpdater({
* dispName: 'Joe Bloggs',
* dispTitle: 'Manager <provisional>',
* dispAge: 47
* });
* // Using bindAsEventListener because of the variable arg lists:
* $('btnUpdateName').observe('click',
* cu.updateTheseHandler.bindAsEventListener(cu, 'dispName')
* );
* $('btnUpdateAll').observe('click',
* cu.updateTheseHandler.bindAsEventListener(cu, 'dispName', 'dispTitle', 'dispAge')
* );
**/
function bindAsEventListener(context) {
var __method = this, args = slice.call(arguments, 1);
@ -65,12 +179,27 @@ Object.extend(Function.prototype, (function() {
/**
* Function#curry(args...) -> Function
* Partially applies the function, returning a function with one or more
* arguments already "filled in."
* - args (?): The arguments to curry.
*
* Function#curry works just like [[Function#bind]] without the initial
* scope argument. Use the latter if you need to partially apply a function
* _and_ modify its execution scope at the same time.
* *Curries* (burns in) arguments to a function, returning a new function
* that when called with call the original passing in the curried arguments
* (along with any new ones):
*
* function showArguments() {
* alert($A(arguments).join(', '));
* }
* showArguments(1, 2,, 3);
* // -> alerts "1, 2, 3"
*
* var f = showArguments.curry(1, 2, 3);
* f('a', 'b');
* // -> alerts "1, 2, 3, a, b"
*
* `Function#curry` works just like [[Function#bind]] without the initial
* context argument. Use `bind` if you need to curry arguments _and_ set
* context at the same time.
*
* The name "curry" comes from [mathematics](http://en.wikipedia.org/wiki/Currying).
**/
function curry() {
if (!arguments.length) return this;
@ -82,21 +211,32 @@ Object.extend(Function.prototype, (function() {
}
/**
* Function#delay(seconds[, args...]) -> Number
* - seconds (Number): How long to wait before calling the function.
* Function#delay(timeout[, args...]) -> Number
* - timeout (Number): The time, in seconds, to wait before calling the
* function.
* - args (?): Optional arguments to pass to the function when calling it.
*
* Schedules the function to run after the specified amount of time, passing
* any arguments given.
*
* Behaves much like `window.setTimeout`. Returns an integer ID that can be
* used to clear the timeout with `window.clearTimeout` before it runs.
* Behaves much like `window.setTimeout`, but the timeout is in seconds
* rather than milliseconds. Returns an integer ID that can be used to
* clear the timeout with `window.clearTimeout` before it runs.
*
* To schedule a function to run as soon as the interpreter is idle, use
* [[Function#defer]].
*
* <h5>Example</h5>
*
* function showMsg(msg) {
* alert(msg);
* }
* showMsg.delay(0.1, "Hi there!");
* // -> Waits a 10th of a second, then alerts "Hi there!"
**/
function delay(timeout) {
var __method = this, args = slice.call(arguments, 1);
timeout = timeout * 1000
timeout = timeout * 1000;
return window.setTimeout(function() {
return __method.apply(__method, args);
}, timeout);
@ -104,6 +244,8 @@ Object.extend(Function.prototype, (function() {
/**
* Function#defer(args...) -> Number
* - args (?): Optional arguments to pass into the function.
*
* Schedules the function to run as soon as the interpreter is idle.
*
* A "deferred" function will not run immediately; rather, it will run as soon
@ -112,6 +254,18 @@ Object.extend(Function.prototype, (function() {
* Behaves much like `window.setTimeout` with a delay set to `0`. Returns an
* ID that can be used to clear the timeout with `window.clearTimeout` before
* it runs.
*
* <h5>Example</h5>
*
* function showMsg(msg) {
* alert(msg);
* }
*
* showMsg("One");
* showMsg.defer("Two");
* showMsg("Three");
* // Alerts "One", then "Three", then (after a brief pause) "Two"
* // Note that "Three" happens before "Two"
**/
function defer() {
var args = update([0.01], arguments);
@ -119,8 +273,8 @@ Object.extend(Function.prototype, (function() {
}
/**
* Function#wrap(wrapperFunction) -> Function
* - wrapperFunction (Function): The function to act as a wrapper.
* Function#wrap(wrapper) -> Function
* - wrapper (Function): The function to use as a wrapper.
*
* Returns a function "wrapped" around the original function.
*
@ -128,6 +282,35 @@ Object.extend(Function.prototype, (function() {
* a single method, letting you easily build on existing functions by
* specifying before and after behavior, transforming the return value, or
* even preventing the original function from being called.
*
* The wraper function is called with this signature:
*
* function wrapper(callOriginal[, args...])
*
* ...where `callOriginal` is a function that can be used to call the
* original (wrapped) function (or not, as appropriate). (`callOriginal` is
* not a direct reference to the original function, there's a layer of
* indirection in-between that sets up the proper context \[`this` value\] for
* it.)
*
* <h5>Example</h5>
*
* // Wrap String#capitalize so it accepts an additional argument
* String.prototype.capitalize = String.prototype.capitalize.wrap(
* function(callOriginal, eachWord) {
* if (eachWord && this.include(" ")) {
* // capitalize each word in the string
* return this.split(" ").invoke("capitalize").join(" ");
* } else {
* // proceed using the original function
* return callOriginal();
* }
* });
*
* "hello world".capitalize();
* // -> "Hello world" (only the 'H' is capitalized)
* "hello world".capitalize(true);
* // -> "Hello World" (both 'H' and 'W' are capitalized)
**/
function wrap(wrapper) {
var __method = this;
@ -139,10 +322,51 @@ Object.extend(Function.prototype, (function() {
/**
* Function#methodize() -> Function
* Wraps the function inside another function that, at call time, pushes
* `this` to the original function as the first argument.
*
* Used to define both a generic method and an instance method.
* Wraps the function inside another function that, when called, pushes
* `this` to the original function as the first argument (with any further
* arguments following it).
*
* The `methodize` method transforms the original function that has an
* explicit first argument to a function that passes `this` (the current
* context) as an implicit first argument at call time. It is useful when we
* want to transform a function that takes an object to a method of that
* object or its prototype, shortening its signature by one argument.
*
* <h5>Example</h5>
*
* // A function that sets a name on a target object
* function setName(target, name) {
* target.name = name;
* }
*
* // Use it
* obj = {};
* setName(obj, 'Fred');
* obj.name;
* // -> "Fred"
*
* // Make it a method of the object
* obj.setName = setName.methodize();
*
* // Use the method instead
* obj.setName('Barney');
* obj.name;
* // -> "Barney"
*
* The example above is quite simplistic. It's more useful to copy methodized
* functions to object prototypes so that new methods are immediately shared
* among instances. In the Prototype library, `methodize` is used in various
* places such as the DOM module, so that (for instance) you can hide an
* element either by calling the static version of `Element.hide` and passing in
* an element reference or ID, like so:
*
* Element.hide('myElement');
*
* ...or if you already have an element reference, just calling the
* methodized form instead:
*
* myElement.hide();
**/
function methodize() {
if (this._methodized) return this._methodized;

View File

@ -1,11 +1,9 @@
/** section: Language, related to: Hash
* $H([object]) -> Hash
*
* Creates a `Hash`.
*
* `$H` is a convenience wrapper around the Hash constructor, with a safeguard
* that lets you pass an existing Hash object and get it back untouched
* (instead of uselessly cloning it).
* Creates a `Hash`. This is purely a convenience wrapper around the Hash
* constructor, it does not do anything other than pass any argument it's
* given into the Hash constructor and return the result.
**/
function $H(object) {
return new Hash(object);
@ -24,13 +22,12 @@ function $H(object) {
* methods that let you enumerate keys and values, iterate over key/value
* pairs, merge two hashes together, and much more.
*
* <h4>Creating a hash</h4>
* <h5>Creating a hash</h5>
*
* There are two ways to construct a Hash instance: the first is regular
* JavaScript object instantiation with the `new` keyword, and the second is
* using the [[$H]] function. There is one difference between them: if a `Hash`
* is passed to `$H`, it will be returned as-is, wherease the same hash passed
* to `new Hash` will be _cloned_ instead.
* You can create a Hash either via `new Hash()` or the convenience alias
* `$H()`; there is **no** difference between them. In either case, you may
* optionally pass in an object to seed the `Hash`. If you pass in a `Hash`,
* it will be cloned.
*
**/
var Hash = Class.create(Enumerable, (function() {
@ -44,6 +41,45 @@ var Hash = Class.create(Enumerable, (function() {
this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
}
// Docs for #each even though technically it's implemented by Enumerable
/**
* Hash#each(iterator[, context]) -> Hash
* - iterator (Function): A function that expects each item in the `Hash`
* as the first argument and a numerical index as the second.
* - context (Object): The scope in which to call `iterator`. Determines what
* `this` means inside `iterator`.
*
* Iterates over the name/value pairs in the hash.
*
* This is actually just the [[Enumerable#each #each]] method from the
* mixed-in [[Enumerable]] module. It is documented here to describe the
* structure of the elements passed to the iterator and the order of
* iteration.
*
* The iterator's first argument (the "item") is an object with two
* properties:
*
* - `key`: the key name as a `String`
* - `value`: the corresponding value (which may be `undefined`)
*
* The order of iteration is implementation-dependent, as it relies on
* the order of the native `for..in` loop. Although most modern
* implementations exhibit *ordered* behavior, this is not standardized and
* may not always be the case, and so cannot be relied upon.
*
* <h5>Example</h5>
*
* var h = $H({version: 1.6, author: 'The Core Team'});
*
* h.each(function(pair) {
* alert(pair.key + ' = "' + pair.value + '"');
* });
* // Alerts 'version = "1.6"' and 'author = "The Core Team"'
* // -or-
* // Alerts 'author = "The Core Team"' and 'version = "1.6"'
**/
// Our _internal_ each
function _each(iterator) {
for (var key in this._object) {
var value = this._object[key], pair = [key, value];
@ -55,8 +91,22 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#set(key, value) -> value
* - key (String): The key to use for this value.
* - value (?): The value to use for this key.
*
* Sets the hash's `key` property to `value` and returns `value`.
* Stores `value` in the hash using the key `key` and returns `value`.
*
* <h5>Example</h5>
*
* var h = $H();
* h.keys();
* // -> [] (initially empty)
* h.set('a', 'apple');
* // -> "apple"
* h.keys();
* // -> ["a"] (has the new entry)
* h.get('a');
* // -> "apple"
**/
function set(key, value) {
return this._object[key] = value;
@ -65,7 +115,13 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#get(key) -> value
*
* Returns the value of the hash's `key` property.
* Returns the stored value for the given `key`.
*
* <h5>Examples</h5>
*
* var h = new Hash({a: 'apple', b: 'banana', c: 'coconut'});
* h.get('a');
* // -> 'apple'
**/
function get(key) {
// simulating poorly supported hasOwnProperty
@ -76,7 +132,18 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#unset(key) -> value
*
* Deletes the hash's `key` property and returns its value.
* Deletes the stored pair for the given `key` from the hash and returns its
* value.
*
* <h5>Example</h5>
*
* var h = new Hash({a: 'apple', b: 'banana', c: 'coconut'});
* h.keys();
* // -> ["a", "b", "c"]
* h.unset('a');
* // -> 'apple'
* h.keys();
* // -> ["b", "c"] ("a" is no longer in the hash)
**/
function unset(key) {
var value = this._object[key];
@ -87,7 +154,15 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#toObject() -> Object
*
* Returns a cloned, vanilla object.
* Returns a cloned, vanilla object whose properties (and property values)
* match the keys (and values) from the hash.
*
* <h5>Example</h5>
*
* var h = new Hash({ a: 'apple', b: 'banana', c: 'coconut' });
* var obj = h.toObject();
* obj.a;
* // -> "apple"
**/
function toObject() {
return Object.clone(this._object);
@ -96,7 +171,15 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#keys() -> [String...]
*
* Provides an Array of keys (that is, property names) for the hash.
* Provides an Array containing the keys for items stored in the hash.
*
* The order of the keys is not guaranteed.
*
* <h5>Example</h5>
*
* var h = $H({one: "uno", two: "due", three: "tre"});
* h.keys();
* // -> ["one", "three", "two"] (these may be in any order)
**/
function keys() {
return this.pluck('key');
@ -105,7 +188,15 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#values() -> Array
*
* Collect the values of a hash and returns them in an array.
* Collects the values of the hash and returns them in an array.
*
* The order of the values is not guaranteed.
*
* <h5>Example</h5>
*
* var h = $H({one: "uno", two: "due", three: "tre"});
* h.values();
* // -> ["uno", "tre", "due"] (these may be in any order)
**/
function values() {
return this.pluck('value');
@ -126,10 +217,22 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#merge(object) -> Hash
* - object (Object | Hash): The object to merge with this hash to produce
* the resulting hash.
*
* Returns a new `Hash` instance with `object`'s key/value pairs merged in;
* this hash remains unchanged.
*
* Returns a new hash with `object`'s key/value pairs merged in.
* To modify the original hash in place, use [[Hash#update]].
*
* <h5>Example</h5>
*
* var h = $H({one: "uno", two: "due"});
* var h2 = h.merge({three: "tre"});
* h.keys();
* // -> ["one", "two"] (unchanged)
* h2.keys();
* // -> ["one", "two", "three"] (has merged contents)
**/
function merge(object) {
return this.clone().update(object);
@ -137,10 +240,22 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#update(object) -> Hash
* - object (Object | Hash): The object to merge with this hash to produce
* the resulting hash.
*
* Updates hash with the key/value pairs of `object`.
* The original hash will be modified. To return a new hash instead, use
* Updates a hash *in place* with the key/value pairs of `object`, returns
* the hash.
*
* `update` modifies the hash. To get a new hash instead, use
* [[Hash#merge]].
*
* <h5>Example</h5>
*
* var h = $H({one: "uno", two: "due"});
* h.update({three: "tre"});
* // -> h (a reference to the original hash)
* h.keys();
* // -> ["one", "two", "three"] (has merged contents)
**/
function update(object) {
return new Hash(object).inject(this, function(result, pair) {
@ -158,7 +273,41 @@ var Hash = Class.create(Enumerable, (function() {
/** related to: String#toQueryParams
* Hash#toQueryString() -> String
*
* Turns a hash into its URL-encoded query string representation.
* Returns a URL-encoded string containing the hash's contents as query
* parameters according to the following rules:
*
* - An undefined value results a parameter with no value portion at all
* (simply the key name, no equal sign).
* - A null value results a parameter with a blank value (the key followed
* by an equal sign and nothing else).
* - A boolean value results a parameter with the value "true" or "false".
* - An Array value results in a parameter for each array element, in
* array order, each using the same key.
* - All keys and values are URI-encoded using JavaScript's native
* `encodeURIComponent` function.
*
* The order of pairs in the string is not guaranteed, other than the order
* of array values described above.
*
* <h5>Example</h5>
*
* $H({action: 'ship',
* order_id: 123,
* fees: ['f1', 'f2']
* }).toQueryString();
* // -> "action=ship&order_id=123&fees=f1&fees=f2"
*
* $H({comment: '',
* 'key with spaces': true,
* related_order: undefined,
* contents: null,
* 'label': 'a demo'
* }).toQueryString();
* // -> "comment=&key%20with%20spaces=true&related_order&contents=&label=a%20demo"
*
* // an empty hash is an empty query string:
* $H().toQueryString();
* // -> ""
**/
function toQueryString() {
return this.inject([], function(results, pair) {
@ -175,7 +324,7 @@ var Hash = Class.create(Enumerable, (function() {
/** related to: Object.inspect
* Hash#inspect() -> String
*
* Returns the debug-oriented string representation of the hash.
* Returns the debug-oriented string representation of the Hash.
**/
function inspect() {
return '#<Hash:{' + this.map(function(pair) {
@ -186,7 +335,13 @@ var Hash = Class.create(Enumerable, (function() {
/** related to: Object.toJSON
* Hash#toJSON() -> String
*
* Returns a JSON string.
* Returns a JSON string containing the keys and values in this hash.
*
* <h5>Example</h5>
*
* var h = $H({'a': 'apple', 'b': 23, 'c': false});
* h.toJSON();
* // -> {"a": "apple", "b": 23, "c": false}
**/
function toJSON() {
return Object.toJSON(this.toObject());
@ -195,7 +350,7 @@ var Hash = Class.create(Enumerable, (function() {
/**
* Hash#clone() -> Hash
*
* Returns a clone of hash.
* Returns a clone of this Hash.
**/
function clone() {
return new Hash(this);

View File

@ -6,7 +6,7 @@
* Prototype extends native JavaScript numbers in order to provide:
*
* * [[ObjectRange]] compatibility, through [[Number#succ]].
* * Ruby-like numerical loops with [[Number#times]].
* * Numerical loops with [[Number#times]].
* * Simple utility methods such as [[Number#toColorPart]] and
* [[Number#toPaddedString]].
* * Instance-method aliases of many functions in the `Math` namespace.
@ -17,8 +17,13 @@ Object.extend(Number.prototype, (function() {
* Number#toColorPart() -> String
*
* Produces a 2-digit hexadecimal representation of the number
* (which is therefore assumed to be in the [0..255] range).
* (which is therefore assumed to be in the \[0..255\] range, inclusive).
* Useful for composing CSS color strings.
*
* <h5>Example</h5>
*
* 10.toColorPart()
* // -> "0a"
**/
function toColorPart() {
return this.toPaddedString(2, 16);
@ -35,11 +40,31 @@ Object.extend(Number.prototype, (function() {
}
/**
* Number#times(iterator) -> Number
* Number#times(iterator[,context]) -> Number
* - iterator (Function): An iterator function to call.
* - context (Object): An optional context (`this` value) to use when
* calling `iterator`.
*
* Calls `iterator` the specified number of times.
* The function takes an integer as the first parameter; it will start at 0
* and be incremented after each invocation.
* Calls `iterator` the specified number of times, passing in a number as
* the first parameter. The number will be 0 on first call, 1 on second
* call, etc. `times` returns the number instance it was called on.
*
* <h5>Example</h5>
*
* (3).times(alert);
* // -> Alerts "0", then "1", then "2"; returns 3
*
* var obj = {count: 0, total: 0};
* function add(addend) {
* ++this.count;
* this.total += addend;
* }
* (4).times(add, obj);
* // -> 4
* obj.count;
* // -> 4
* obj.total;
* // -> 6 (e.g., 0 + 1 + 2 + 3)
**/
function times(iterator, context) {
$R(0, this, true).each(iterator, context);
@ -48,10 +73,30 @@ Object.extend(Number.prototype, (function() {
/**
* Number#toPaddedString(length[, radix]) -> String
* - length (Number): The minimum length for the resulting string.
* - radix (Number): An optional radix for the string representation,
* defaults to 10 (decimal).
*
* Converts the number into a string padded with 0s so that the string's length
* is at least equal to `length`.
* Takes an optional `radix` argument which specifies the base to use for conversion.
* Returns a string representation of the number padded with leading 0s so
* that the string's length is at least equal to `length`. Takes an optional
* `radix` argument which specifies the base to use for conversion.
*
* <h5>Examples</h5>
*
* (13).toPaddedString(4);
* // -> "0013"
*
* (13).toPaddedString(2);
* // -> "13"
*
* (13).toPaddedString(1);
* // -> "13"
*
* (13).toPaddedString(4, 16)
* // -> "000d"
*
* (13).toPaddedString(4, 2);
* // -> "1101"
**/
function toPaddedString(length, radix) {
var string = this.toString(radix || 10);
@ -70,7 +115,8 @@ Object.extend(Number.prototype, (function() {
/**
* Number#abs() -> Number
*
* Returns the absolute value of the number.
* Returns the absolute value of the number. Convenience method that simply
* calls `Math.abs` on this instance and returns the result.
**/
function abs() {
return Math.abs(this);
@ -79,7 +125,8 @@ Object.extend(Number.prototype, (function() {
/**
* Number#round() -> Number
*
* Rounds the number to the nearest integer.
* Rounds the number to the nearest integer. Convenience method that simply
* calls `Math.round` on this instance and returns the result.
**/
function round() {
return Math.round(this);
@ -89,6 +136,8 @@ Object.extend(Number.prototype, (function() {
* Number#ceil() -> Number
*
* Returns the smallest integer greater than or equal to the number.
* Convenience method that simply calls `Math.ceil` on this instance and
* returns the result.
**/
function ceil() {
return Math.ceil(this);
@ -98,6 +147,8 @@ Object.extend(Number.prototype, (function() {
* Number#floor() -> Number
*
* Returns the largest integer less than or equal to the number.
* Convenience method that simply calls `Math.floor` on this instance and
* returns the result.
**/
function floor() {
return Math.floor(this);

View File

@ -167,12 +167,32 @@
* Object.clone(object) -> Object
* - object (Object): The object to clone.
*
* Duplicates the passed object.
*
* Copies all the original's key/value pairs onto an empty object.
* Creates and returns a shallow duplicate of the passed object by copying
* all of the original's key/value pairs onto an empty object.
*
* Do note that this is a _shallow_ copy, not a _deep_ copy. Nested objects
* will retain their references.
*
* <h5>Examples</h5>
*
* var original = {name: 'primaryColors', values: ['red', 'green', 'blue']};
* var copy = Object.clone(original);
* original.name;
* // -> "primaryColors"
* original.values[0];
* // -> "red"
* copy.name;
* // -> "primaryColors"
* copy.name = "secondaryColors";
* original.name;
* // -> "primaryColors"
* copy.name;
* // -> "secondaryColors"
* copy.values[0] = 'magenta';
* copy.values[1] = 'cyan';
* copy.values[2] = 'yellow';
* original.values[0];
* // -> "magenta" (it was a shallow copy, so they shared the array)
**/
function clone(object) {
return extend({ }, object);

View File

@ -14,7 +14,7 @@
* expression. The `Template` class provides a much nicer and clearer way of
* achieving this formatting.
*
* <h4>Straightforward templates</h4>
* <h5>Straightforward templates</h5>
*
* The `Template` class uses a basic formatting syntax, similar to what is
* used in Ruby. The templates are created from strings that have embedded
@ -36,7 +36,7 @@
* myTemplate.evaluate(show);
* // -> "The TV show The Simpsons was created by Matt Groening."
*
* <h4>Templates are meant to be reused</h4>
* <h5>Templates are meant to be reused</h5>
*
* As the example illustrates, `Template` objects are not tied to specific
* data. The data is bound to the template only during the evaluation of the
@ -60,7 +60,7 @@
* // -> Multiply by 0.9478 to convert from kilojoules to BTUs.
* // -> Multiply by 1024 to convert from megabytes to gigabytes.
*
* <h4>Escape sequence</h4>
* <h5>Escape sequence</h5>
*
* There's always the chance that one day you'll need to have a literal in your
* template that looks like a symbol, but is not supposed to be replaced. For
@ -75,7 +75,7 @@
* t.evaluate(data);
* // -> in Ruby we also use the #{variable} syntax for templates.
*
* <h4>Custom syntaxes</h4>
* <h5>Custom syntaxes</h5>
*
* The default syntax of the template strings will probably be enough for most
* scenarios. In the rare occasion where the default Ruby-like syntax is