Update oojs to v1.0.8
[lhc/web/wiklou.git] / resources / oojs / oojs.js
index d2d61e9..cd966b9 100644 (file)
@@ -1,12 +1,12 @@
 /*!
- * Object Oriented JavaScript Library v1.0.5
- * https://github.com/trevorparscal/oojs
+ * OOjs v1.0.8
+ * https://www.mediawiki.org/wiki/OOjs
  *
- * Copyright 2011-2013 OOJS Team and other contributors.
+ * Copyright 2011-2014 OOjs Team and other contributors.
  * Released under the MIT license
  * http://oojs.mit-license.org
  *
- * Date: Wed Oct 23 2013 02:22:02 GMT+0200 (CEST)
+ * Date: Tue Mar 11 2014 19:27:31 GMT+0100 (CET)
  */
 ( function ( global ) {
 
@@ -23,11 +23,9 @@ var
 
 /* Class Methods */
 
-
 /**
  * Assert whether a value is a plain object or not.
  *
- * @method
  * @param {Mixed} obj
  * @return {boolean}
  */
@@ -62,27 +60,30 @@ oo.isPlainObject = function ( obj ) {
  *  This is how prototypal inheritance works, it can only be one straight chain
  *  (just like classical inheritance in PHP for example). If you need to work with
  *  multiple constructors consider storing an instance of the other constructor in a
- *  property instead, or perhaps use a mixin (see oo.mixinClass).
- *
- *     function Foo() {}
- *     Foo.prototype.jump = function () {};
- *
- *     function FooBar() {}
- *     oo.inheritClass( FooBar, Foo );
- *     FooBar.prop.feet = 2;
- *     FooBar.prototype.walk = function () {};
- *
- *     function FooBarQuux() {}
- *     OO.inheritClass( FooBarQuux, FooBar );
- *     FooBarQuux.prototype.jump = function () {};
+ *  property instead, or perhaps use a mixin (see OO.mixinClass).
+ *
+ *     function Thing() {}
+ *     Thing.prototype.exists = function () {};
+ *
+ *     function Person() {
+ *         Person.super.apply( this, arguments );
+ *     }
+ *     OO.inheritClass( Person, Thing );
+ *     Person.static.defaultEyeCount = 2;
+ *     Person.prototype.walk = function () {};
+ *
+ *     function Jumper() {
+ *         Jumper.super.apply( this, arguments );
+ *     }
+ *     OO.inheritClass( Jumper, Person );
+ *     Jumper.prototype.jump = function () {};
+ *
+ *     Jumper.static.defaultEyeCount === 2;
+ *     var x = new Jumper();
+ *     x.jump();
+ *     x.walk();
+ *     x instanceof Thing && x instanceof Person && x instanceof Jumper;
  *
- *     FooBarQuux.prop.feet === 2;
- *     var fb = new FooBar();
- *     fb.jump();
- *     fb.walk();
- *     fb instanceof Foo && fb instanceof FooBar && fb instanceof FooBarQuux;
- *
- * @method
  * @param {Function} targetFn
  * @param {Function} originFn
  * @throws {Error} If target already inherits from origin
@@ -94,6 +95,7 @@ oo.inheritClass = function ( targetFn, originFn ) {
 
        var targetConstructor = targetFn.prototype.constructor;
 
+       targetFn.super = originFn;
        targetFn.prototype = Object.create( originFn.prototype, {
                // Restore constructor property of targetFn
                constructor: {
@@ -135,7 +137,6 @@ oo.inheritClass = function ( targetFn, originFn ) {
  *     OO.inheritClass( FooBar, Foo );
  *     OO.mixinClass( FooBar, ContextLazyLoad );
  *
- * @method
  * @param {Function} targetFn
  * @param {Function} originFn
  */
@@ -183,7 +184,6 @@ oo.mixinClass = function ( targetFn, originFn ) {
  *     foo2.getAge(); // 21
  *     foo.getAge(); // 22
  *
- * @method
  * @param {Object} origin
  * @return {Object} Clone of origin
  */
@@ -202,11 +202,10 @@ oo.cloneObject = function ( origin ) {
 };
 
 /**
- * Gets an array of all property values in an object.
+ * Get an array of all property values in an object.
  *
- * @method
  * @param {Object} Object to get values from
- * @returns {Array} List of object values
+ * @return {Array} List of object values
  */
 oo.getObjectValues = function ( obj ) {
        var key, values;
@@ -232,11 +231,10 @@ oo.getObjectValues = function ( obj ) {
  * the other. An asymmetrical test may also be performed, which checks only that properties in the
  * first object are present in the second object, but not the inverse.
  *
- * @method
  * @param {Object} a First object to compare
  * @param {Object} b Second object to compare
  * @param {boolean} [asymmetrical] Whether to check only that b contains values from a
- * @returns {boolean} If the objects contain the same values as each other
+ * @return {boolean} If the objects contain the same values as each other
  */
 oo.compare = function ( a, b, asymmetrical ) {
        var aValue, bValue, aType, bType, k;
@@ -265,10 +263,9 @@ oo.compare = function ( a, b, asymmetrical ) {
  *
  * Copies are deep, and will either be an object or an array depending on `source`.
  *
- * @method
  * @param {Object} source Object to copy
  * @param {Function} [callback] Applied to leaf values before they added to the clone
- * @returns {Object} Copy of source object
+ * @return {Object} Copy of source object
  */
 oo.copy = function ( source, callback ) {
        var key, sourceValue, sourceType, destination;
@@ -306,8 +303,9 @@ oo.copy = function ( source, callback ) {
 };
 
 /**
- * Generates a hash of an object based on its name and data.
- * Performance optimization: http://jsperf.com/ve-gethash-201208#/toJson_fnReplacerIfAoForElse
+ * Generate a hash of an object based on its name and data.
+ *
+ * Performance optimization: <http://jsperf.com/ve-gethash-201208#/toJson_fnReplacerIfAoForElse>
  *
  * To avoid two objects with the same values generating different hashes, we utilize the replacer
  * argument of JSON.stringify and sort the object by key as it's being serialized. This may or may
@@ -318,20 +316,21 @@ oo.copy = function ( source, callback ) {
  * ourselves. This allows classes to define custom hashing.
  *
  * @param {Object} val Object to generate hash for
- * @returns {string} Hash of object
+ * @return {string} Hash of object
  */
 oo.getHash = function ( val ) {
        return JSON.stringify( val, oo.getHash.keySortReplacer );
 };
 
 /**
- * Helper function for oo.getHash which sorts objects by key.
+ * Helper function for OO.getHash which sorts objects by key.
  *
  * This is a callback passed into JSON.stringify.
  *
+ * @method getHash_keySortReplacer
  * @param {string} key Property name of value being replaced
  * @param {Mixed} val Property value to replace
- * @returns {Mixed} Replacement value
+ * @return {Mixed} Replacement value
  */
 oo.getHash.keySortReplacer = function ( key, val ) {
        var normalized, keys, i, len;
@@ -361,13 +360,13 @@ oo.getHash.keySortReplacer = function ( key, val ) {
 /**
  * Compute the union (duplicate-free merge) of a set of arrays.
  *
- * Arrays values must be convertable to object keys (strings)
+ * Arrays values must be convertable to object keys (strings).
  *
  * By building an object (with the values for keys) in parallel with
- * the array, a new item's existence in the union can be computed faster
+ * the array, a new item's existence in the union can be computed faster.
  *
  * @param {Array...} arrays Arrays to union
- * @returns {Array} Union of the arrays
+ * @return {Array} Union of the arrays
  */
 oo.simpleArrayUnion = function () {
        var i, ilen, arr, j, jlen,
@@ -392,16 +391,16 @@ oo.simpleArrayUnion = function () {
  *
  * An intersection checks the item exists in 'b' while difference checks it doesn't.
  *
- * Arrays values must be convertable to object keys (strings)
+ * Arrays values must be convertable to object keys (strings).
  *
  * By building an object (with the values for keys) of 'b' we can
- * compute the result faster
+ * compute the result faster.
  *
  * @private
  * @param {Array} a First array
  * @param {Array} b Second array
  * @param {boolean} includeB Whether to items in 'b'
- * @returns {Array} Combination (intersection or difference) of arrays
+ * @return {Array} Combination (intersection or difference) of arrays
  */
 function simpleArrayCombine( a, b, includeB ) {
        var i, ilen, isInB,
@@ -425,11 +424,11 @@ function simpleArrayCombine( a, b, includeB ) {
 /**
  * Compute the intersection of two arrays (items in both arrays).
  *
- * Arrays values must be convertable to object keys (strings)
+ * Arrays values must be convertable to object keys (strings).
  *
  * @param {Array} a First array
  * @param {Array} b Second array
- * @returns {Array} Intersection of arrays
+ * @return {Array} Intersection of arrays
  */
 oo.simpleArrayIntersection = function ( a, b ) {
        return simpleArrayCombine( a, b, true );
@@ -438,25 +437,28 @@ oo.simpleArrayIntersection = function ( a, b ) {
 /**
  * Compute the difference of two arrays (items in 'a' but not 'b').
  *
- * Arrays values must be convertable to object keys (strings)
+ * Arrays values must be convertable to object keys (strings).
  *
  * @param {Array} a First array
  * @param {Array} b Second array
- * @returns {Array} Intersection of arrays
+ * @return {Array} Intersection of arrays
  */
 oo.simpleArrayDifference = function ( a, b ) {
        return simpleArrayCombine( a, b, false );
 };
 /**
- * Event emitter.
- *
  * @class OO.EventEmitter
  *
  * @constructor
- * @property {Object} bindings
  */
 oo.EventEmitter = function OoEventEmitter() {
        // Properties
+
+       /**
+        * Storage of bound event handlers by event name.
+        *
+        * @property
+        */
        this.bindings = {};
 };
 
@@ -467,7 +469,6 @@ oo.EventEmitter = function OoEventEmitter() {
  *
  * If the callback/context are already bound to the event, they will not be bound again.
  *
- * @method
  * @param {string} event Type of event to listen to
  * @param {Function} callback Function to call when event occurs
  * @param {Array} [args] Arguments to pass to listener, will be prepended to emitted arguments
@@ -502,9 +503,9 @@ oo.EventEmitter.prototype.on = function ( event, callback, args, context ) {
        }
        // Add binding
        bindings.push( {
-               'callback': callback,
-               'args': args,
-               'context': context
+               callback: callback,
+               args: args,
+               context: context
        } );
        return this;
 };
@@ -512,7 +513,6 @@ oo.EventEmitter.prototype.on = function ( event, callback, args, context ) {
 /**
  * Adds a one-time listener to a specific event.
  *
- * @method
  * @param {string} event Type of event to listen to
  * @param {Function} listener Listener to call when event occurs
  * @chainable
@@ -528,7 +528,6 @@ oo.EventEmitter.prototype.once = function ( event, listener ) {
 /**
  * Remove a specific listener from a specific event.
  *
- * @method
  * @param {string} event Type of event to remove listener from
  * @param {Function} [callback] Listener to remove, omit to remove all
  * @param {Object} [context=null] Object used context for callback function or method
@@ -573,13 +572,13 @@ oo.EventEmitter.prototype.off = function ( event, callback, context ) {
 
 /**
  * Emit an event.
+ *
  * TODO: Should this be chainable? What is the usefulness of the boolean
  * return value here?
  *
- * @method
  * @param {string} event Type of event
  * @param {Mixed} args First in a list of variadic arguments passed to event handler (optional)
- * @returns {boolean} If event was handled by at least one listener
+ * @return {boolean} If event was handled by at least one listener
  */
 oo.EventEmitter.prototype.emit = function ( event ) {
        var i, len, binding, bindings, args;
@@ -603,12 +602,11 @@ oo.EventEmitter.prototype.emit = function ( event ) {
 /**
  * Connect event handlers to an object.
  *
- * @method
  * @param {Object} context Object to call methods on when events occur
  * @param {Object.<string,string>|Object.<string,Function>|Object.<string,Array>} methods List of
- * event bindings keyed by event name containing either method names, functions or arrays containing
- * method name or function followed by a list of arguments to be passed to callback before emitted
- * arguments
+ *  event bindings keyed by event name containing either method names, functions or arrays containing
+ *  method name or function followed by a list of arguments to be passed to callback before emitted
+ *  arguments
  * @chainable
  */
 oo.EventEmitter.prototype.connect = function ( context, methods ) {
@@ -643,7 +641,6 @@ oo.EventEmitter.prototype.connect = function ( context, methods ) {
 /**
  * Disconnect event handlers from an object.
  *
- * @method
  * @param {Object} context Object to disconnect methods from
  * @param {Object.<string,string>|Object.<string,Function>|Object.<string,Array>} [methods] List of
  * event bindings keyed by event name containing either method names or functions
@@ -684,8 +681,6 @@ oo.EventEmitter.prototype.disconnect = function ( context, methods ) {
        return this;
 };
 /**
- * Data registry.
- *
  * @class OO.Registry
  * @mixins OO.EventEmitter
  *
@@ -718,52 +713,44 @@ oo.mixinClass( oo.Registry, oo.EventEmitter );
  *
  * Only the base name will be registered, overriding any existing entry with the same base name.
  *
- * @method
  * @param {string|string[]} name Symbolic name or list of symbolic names
  * @param {Mixed} data Data to associate with symbolic name
  * @fires register
  * @throws {Error} Name argument must be a string or array
  */
 oo.Registry.prototype.register = function ( name, data ) {
-       if ( typeof name !== 'string' && !Array.isArray( name ) ) {
-               throw new Error( 'Name argument must be a string or array, cannot be a ' + typeof name );
-       }
        var i, len;
-       if ( Array.isArray( name ) ) {
+       if ( typeof name === 'string' ) {
+               this.registry[name] = data;
+               this.emit( 'register', name, data );
+       } else if ( Array.isArray( name ) ) {
                for ( i = 0, len = name.length; i < len; i++ ) {
                        this.register( name[i], data );
                }
-       } else if ( typeof name === 'string' ) {
-               this.registry[name] = data;
-               this.emit( 'register', name, data );
        } else {
-               throw new Error( 'Name must be a string or array of strings, cannot be a ' + typeof name );
+               throw new Error( 'Name must be a string or array, cannot be a ' + typeof name );
        }
 };
 
 /**
- * Gets data for a given symbolic name.
+ * Get data for a given symbolic name.
  *
  * Lookups are done using the base name.
  *
- * @method
  * @param {string} name Symbolic name
- * @returns {Mixed|undefined} Data associated with symbolic name
+ * @return {Mixed|undefined} Data associated with symbolic name
  */
 oo.Registry.prototype.lookup = function ( name ) {
        return this.registry[name];
 };
 /**
- * Object factory.
- *
  * @class OO.Factory
  * @extends OO.Registry
  *
  * @constructor
  */
 oo.Factory = function OoFactory() {
-       // Parent constructor
-       oo.Registry.call( this );
+       oo.Factory.super.call( this );
 
        // Properties
        this.entries = [];
@@ -780,14 +767,12 @@ oo.inheritClass( oo.Factory, oo.Registry );
  *
  * Classes must have a static `name` property to be registered.
  *
- *     @example
  *     function MyClass() {};
  *     // Adds a static property to the class defining a symbolic name
  *     MyClass.static = { 'name': 'mine' };
  *     // Registers class with factory, available via symbolic name 'mine'
  *     factory.register( MyClass );
  *
- * @method
  * @param {Function} constructor Constructor to use when creating object
  * @throws {Error} Name must be a string and must not be empty
  * @throws {Error} Constructor must be a function
@@ -803,7 +788,8 @@ oo.Factory.prototype.register = function ( constructor ) {
                throw new Error( 'Name must be a string and must not be empty' );
        }
        this.entries.push( name );
-       oo.Registry.prototype.register.call( this, name, constructor );
+
+       oo.Factory.super.prototype.register.call( this, name, constructor );
 };
 
 /**
@@ -812,10 +798,9 @@ oo.Factory.prototype.register = function ( constructor ) {
  * Name is used to look up the constructor to use, while all additional arguments are passed to the
  * constructor directly, so leaving one out will pass an undefined to the constructor.
  *
- * @method
  * @param {string} name Object name
  * @param {Mixed...} [args] Arguments to pass to the constructor
- * @returns {Object} The new object
+ * @return {Object} The new object
  * @throws {Error} Unknown object name
  */
 oo.Factory.prototype.create = function ( name ) {