/*!
- * OOjs v1.1.4 optimised for jQuery
+ * OOjs v1.1.7 optimised for jQuery
* https://www.mediawiki.org/wiki/OOjs
*
* Copyright 2011-2015 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-01-23T20:11:25Z
+ * Date: 2015-04-29T01:13:49Z
*/
( function ( global ) {
*
* The 'constructor' (whether implicit or explicit) is not copied over.
*
- * This does not create inheritance to the origin. If inheritance is needed
- * use oo.inheritClass instead.
+ * This does not create inheritance to the origin. If you need inheritance,
+ * use OO.inheritClass instead.
*
* Beware: This can redefine a prototype property, call before setting your prototypes.
*
- * Beware: Don't call before oo.inheritClass.
+ * Beware: Don't call before OO.inheritClass.
*
* function Foo() {}
* function Context() {}
a = a || {};
b = b || {};
+ if ( typeof a.nodeType === 'number' && typeof a.isEqualNode === 'function' ) {
+ return a.isEqualNode( b );
+ }
+
for ( k in a ) {
- if ( !hasOwn.call( a, k ) || a[k] === undefined ) {
+ if ( !hasOwn.call( a, k ) || a[k] === undefined || a[k] === b[k] ) {
// Support es3-shim: Without the hasOwn filter, comparing [] to {} will be false in ES3
// because the shimmed "forEach" is enumerable and shows up in Array but not Object.
// Also ignore undefined values, because there is no conceptual difference between
( aType === 'string' || aType === 'number' || aType === 'boolean' ) &&
aValue !== bValue
) ||
- ( aValue === Object( aValue ) && !oo.compare( aValue, bValue, asymmetrical ) ) ) {
+ ( aValue === Object( aValue ) && !oo.compare( aValue, bValue, true ) ) ) {
return false;
}
}
}
};
+/**
+ * Get the unique values of an array, removing duplicates
+ *
+ * @param {Array} arr Array
+ * @return {Array} Unique values in array
+ */
+oo.unique = function ( arr ) {
+ return arr.reduce( function ( result, current ) {
+ if ( result.indexOf( current ) === -1 ) {
+ result.push( current );
+ }
+ return result;
+ }, [] );
+};
+
/**
* Compute the union (duplicate-free merge) of a set of arrays.
*
*/
oo.EventEmitter.prototype.once = function ( event, listener ) {
var eventEmitter = this,
- listenerWrapper = function () {
- eventEmitter.off( event, listenerWrapper );
- listener.apply( eventEmitter, Array.prototype.slice.call( arguments, 0 ) );
+ wrapper = function () {
+ eventEmitter.off( event, wrapper );
+ return listener.apply( this, arguments );
};
- return this.on( event, listenerWrapper );
+ return this.on( event, wrapper );
};
/**
* @param {Mixed} data
*/
+/**
+ * @event unregister
+ * @param {string} name
+ * @param {Mixed} data Data removed from registry
+ */
+
/* Methods */
/**
* Associate one or more symbolic names with some data.
*
- * Only the base name will be registered, overriding any existing entry with the same base name.
+ * Any existing entry with the same name will be overridden.
*
* @param {string|string[]} name Symbolic name or list of symbolic names
* @param {Mixed} data Data to associate with symbolic name
};
/**
- * Get data for a given symbolic name.
+ * Remove one or more symbolic names from the registry
*
- * Lookups are done using the base name.
+ * @param {string|string[]} name Symbolic name or list of symbolic names
+ * @fires unregister
+ * @throws {Error} Name argument must be a string or array
+ */
+oo.Registry.prototype.unregister = function ( name ) {
+ var i, len, data;
+ if ( typeof name === 'string' ) {
+ data = this.lookup( name );
+ if ( data !== undefined ) {
+ delete this.registry[name];
+ this.emit( 'unregister', name, data );
+ }
+ } else if ( Array.isArray( name ) ) {
+ for ( i = 0, len = name.length; i < len; i++ ) {
+ this.unregister( name[i] );
+ }
+ } else {
+ throw new Error( 'Name must be a string or array, cannot be a ' + typeof name );
+ }
+};
+
+/**
+ * Get data for a given symbolic name.
*
* @param {string} name Symbolic name
* @return {Mixed|undefined} Data associated with symbolic name
* @constructor
*/
oo.Factory = function OoFactory() {
+ // Parent constructor
oo.Factory.parent.call( this );
-
- // Properties
- this.entries = [];
};
/* Inheritance */
if ( typeof name !== 'string' || name === '' ) {
throw new Error( 'Name must be a string and must not be empty' );
}
- this.entries.push( name );
+ // Parent method
oo.Factory.parent.prototype.register.call( this, name, constructor );
};
+/**
+ * Unregister a constructor from the factory.
+ *
+ * @param {Function} constructor Constructor to unregister
+ * @throws {Error} Name must be a string and must not be empty
+ * @throws {Error} Constructor must be a function
+ */
+oo.Factory.prototype.unregister = function ( constructor ) {
+ var name;
+
+ if ( typeof constructor !== 'function' ) {
+ throw new Error( 'constructor must be a function, cannot be a ' + typeof constructor );
+ }
+ name = constructor.static && constructor.static.name;
+ if ( typeof name !== 'string' || name === '' ) {
+ throw new Error( 'Name must be a string and must not be empty' );
+ }
+
+ // Parent method
+ oo.Factory.parent.prototype.unregister.call( this, name );
+};
+
/**
* Create an object based on a name.
*