2011-11-02 21:00:55 +00:00
|
|
|
/**
|
2012-02-09 22:04:06 +00:00
|
|
|
* VisualEditor namespace.
|
2012-07-19 21:25:16 +00:00
|
|
|
*
|
2012-07-19 00:11:26 +00:00
|
|
|
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
|
|
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Namespace for all VisualEditor classes, static methods and static properties.
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-03-29 22:55:33 +00:00
|
|
|
window.ve = {
|
2012-06-20 01:20:28 +00:00
|
|
|
// List of instances of visual editors
|
2012-03-29 22:55:33 +00:00
|
|
|
'instances': []
|
|
|
|
};
|
2011-11-02 21:00:55 +00:00
|
|
|
|
2012-08-11 08:14:56 +00:00
|
|
|
/* Utility functions */
|
2011-11-02 21:00:55 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Extends a constructor with the prototype of another.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* When using this, it's required to include a call to the constructor of the parent class as the
|
|
|
|
* first code in the child class's constructor.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @example
|
|
|
|
* // Define parent class
|
|
|
|
* function Foo() {
|
|
|
|
* // code here
|
|
|
|
* }
|
|
|
|
* // Define child class
|
|
|
|
* function Bar() {
|
|
|
|
* // Call parent constructor
|
|
|
|
* Foo.call( this );
|
|
|
|
* }
|
|
|
|
* // Extend prototype
|
2012-02-06 23:50:56 +00:00
|
|
|
* ve.extendClass( Bar, Foo );
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Function} dst Class to extend
|
2012-06-22 17:50:41 +00:00
|
|
|
* @param {Function} [..] List of base classed to use methods from
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.extendClass = function ( dst ) {
|
2012-08-02 18:46:13 +00:00
|
|
|
var i, method, base,
|
|
|
|
length = arguments.length;
|
|
|
|
for ( i = 1; i < length; i++ ) {
|
|
|
|
base = arguments[i].prototype;
|
|
|
|
for ( method in base ) {
|
2012-06-22 17:50:41 +00:00
|
|
|
if ( typeof base[method] === 'function' && !( method in dst.prototype ) ) {
|
|
|
|
dst.prototype[method] = base[method];
|
|
|
|
}
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-02-06 23:50:56 +00:00
|
|
|
ve.isPlainObject = $.isPlainObject;
|
2011-11-02 21:00:55 +00:00
|
|
|
|
2012-02-06 23:50:56 +00:00
|
|
|
ve.isEmptyObject = $.isEmptyObject;
|
2011-11-03 19:01:55 +00:00
|
|
|
|
2012-08-11 08:14:56 +00:00
|
|
|
/**
|
|
|
|
* Check whether given variable is an array. Should not use `instanceof` or
|
|
|
|
* `constructor` due to the inability to detect arrays from a different
|
|
|
|
* scope.
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @until ES5: Array.isArray.
|
|
|
|
* @param {Mixed} x
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
2012-02-06 23:50:56 +00:00
|
|
|
ve.isArray = $.isArray;
|
2011-11-02 21:00:55 +00:00
|
|
|
|
2012-08-11 08:14:56 +00:00
|
|
|
/**
|
|
|
|
* Create a function calls the given function in a certain context.
|
|
|
|
* If a function does not have an explicit context, it is determined at
|
|
|
|
* executin time based on how it is invoked (e.g. object member, call/apply,
|
|
|
|
* global scope, etc.).
|
|
|
|
* Performance optimization: http://jsperf.com/function-bind-shim-perf
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @until ES5: Function.prototype.bind.
|
|
|
|
* @param {Function} func Function to bind.
|
|
|
|
* @param {Object} context Context for the function.
|
|
|
|
* @param {Mixed} [..] Variadic list of arguments to prepend to arguments
|
|
|
|
* to the bound function.
|
|
|
|
* @return {Function} The bound.
|
|
|
|
*/
|
|
|
|
ve.bind = $.proxy;
|
2012-06-20 01:20:28 +00:00
|
|
|
|
2011-11-15 12:54:18 +00:00
|
|
|
/**
|
|
|
|
* Wrapper for Array.prototype.indexOf
|
2012-08-11 08:14:56 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @until ES5
|
|
|
|
* @param {Mixed} value Element to search for.
|
|
|
|
* @param {Array} array Array to search in.
|
|
|
|
* @param {Integer} [fromIndex=0] Index to being searching from.
|
|
|
|
* @return {Number} Index of value in array, or -1 if not found.
|
|
|
|
* Values are compared without type coersion.
|
|
|
|
*/
|
|
|
|
ve.indexOf = $.inArray;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Merge properties of one or more objects into another.
|
|
|
|
* Preserves original object's inheritance (e.g. Array, Object, whatever).
|
|
|
|
* In case of array or array-like objects only the indexed properties
|
|
|
|
* are copied over.
|
|
|
|
* Beware: If called with only one argument, it will consider
|
|
|
|
* 'target' as 'source' and 'this' as 'target'. Which means
|
|
|
|
* ve.extendObject( { a: 1 } ); sets ve.a = 1;
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2012-08-11 08:14:56 +00:00
|
|
|
* @param {Boolean} [recursive=false]
|
|
|
|
* @param {Mixed} target Object that will receive the new properties.
|
|
|
|
* @param {Mixed} [..] Variadic list of objects containing properties
|
|
|
|
* to be merged into the targe.
|
|
|
|
* @return {Mixed} Modified version of first or second argument.
|
2011-11-15 12:54:18 +00:00
|
|
|
*/
|
2012-08-11 08:14:56 +00:00
|
|
|
ve.extendObject = $.extend;
|
2011-11-15 12:54:18 +00:00
|
|
|
|
2012-06-20 01:20:28 +00:00
|
|
|
/**
|
2012-06-20 23:01:02 +00:00
|
|
|
* Generates a hash of an object based on its name and data.
|
2012-08-12 18:27:31 +00:00
|
|
|
* Performance optimization: http://jsperf.com/ve-gethash-201208#/toJson_fnReplacerIfAoForElse
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2012-08-15 18:14:44 +00:00
|
|
|
* 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
|
|
|
|
* not be the fastest way to do this; we should investigate this further.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
2012-08-12 18:27:31 +00:00
|
|
|
* @param {Object} val Object to generate hash for
|
2012-06-20 01:20:28 +00:00
|
|
|
* @returns {String} Hash of object
|
|
|
|
*/
|
2012-08-12 18:27:31 +00:00
|
|
|
ve.getHash = function ( val ) {
|
|
|
|
return JSON.stringify( val, ve.getHash.keySortReplacer );
|
2012-08-15 18:14:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper function for ve.getHash which sorts objects by key.
|
|
|
|
*
|
|
|
|
* This is a callback passed into JSON.stringify.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {String} key Property name of value being replaced
|
2012-08-12 18:27:31 +00:00
|
|
|
* @param {Mixed} val Property value to replace
|
2012-08-15 18:14:44 +00:00
|
|
|
* @returns {Mixed} Replacement value
|
|
|
|
*/
|
2012-08-12 18:27:31 +00:00
|
|
|
ve.getHash.keySortReplacer = function ( key, val ) {
|
|
|
|
/*jshint newcap: false */
|
|
|
|
var normalized, keys, i, len;
|
|
|
|
// Only normalize objects when the key-order is ambiguous
|
|
|
|
// (e.g. any object not an array).
|
|
|
|
if ( !ve.isArray( val ) && Object( val ) === val ) {
|
|
|
|
normalized = {};
|
|
|
|
keys = ve.getObjectKeys( val ).sort();
|
|
|
|
i = 0;
|
|
|
|
len = keys.length;
|
|
|
|
for ( ; i < len; i += 1 ) {
|
|
|
|
normalized[keys[i]] = val[keys[i]];
|
2012-08-15 18:14:44 +00:00
|
|
|
}
|
2012-08-12 18:27:31 +00:00
|
|
|
return normalized;
|
|
|
|
|
|
|
|
// Primitive values and arrays get stable hashes
|
|
|
|
// by default. Lets those be stringified as-is.
|
2012-08-15 18:14:44 +00:00
|
|
|
} else {
|
2012-08-12 18:27:31 +00:00
|
|
|
return val;
|
2012-08-15 18:14:44 +00:00
|
|
|
}
|
|
|
|
};
|
2012-06-20 01:20:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets an array of all property names in an object.
|
|
|
|
*
|
|
|
|
* This falls back to the native impelentation of Object.keys if available.
|
2012-08-12 18:27:31 +00:00
|
|
|
* Performance optimization: http://jsperf.com/object-keys-shim-perf#/fnHasown_fnForIfcallLength
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
2012-08-11 08:14:56 +00:00
|
|
|
* @until ES5
|
2012-06-20 01:20:28 +00:00
|
|
|
* @param {Object} Object to get properties from
|
|
|
|
* @returns {String[]} List of object keys
|
|
|
|
*/
|
2012-08-12 18:27:31 +00:00
|
|
|
ve.getObjectKeys = Object.hasOwnProperty( 'keys' ) ? Object.keys : ( function () {
|
|
|
|
var hasOwn = Object.prototype.hasOwnProperty;
|
|
|
|
|
|
|
|
return function ( obj ) {
|
|
|
|
/*jshint newcap: false */
|
|
|
|
var key, keys;
|
|
|
|
|
|
|
|
if ( Object( obj ) !== obj ) {
|
|
|
|
throw new TypeError( 'Called on non-object' );
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
2012-08-12 18:27:31 +00:00
|
|
|
|
|
|
|
keys = [];
|
|
|
|
for ( key in obj ) {
|
|
|
|
if ( hasOwn.call( obj, key ) ) {
|
|
|
|
keys[keys.length] = key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return keys;
|
|
|
|
};
|
|
|
|
}() );
|
2012-06-20 01:20:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets an array of all property values in an object.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Object} Object to get values from
|
|
|
|
* @returns {Array} List of object values
|
|
|
|
*/
|
2012-08-12 18:27:31 +00:00
|
|
|
ve.getObjectValues = ( function () {
|
|
|
|
var hasOwn = Object.prototype.hasOwnProperty;
|
|
|
|
|
|
|
|
return function ( obj ) {
|
|
|
|
/*jshint newcap: false */
|
|
|
|
var key, values;
|
|
|
|
|
|
|
|
if ( Object( obj ) !== obj ) {
|
|
|
|
throw new TypeError( 'Called on non-object' );
|
2012-06-20 01:20:28 +00:00
|
|
|
}
|
2012-08-12 18:27:31 +00:00
|
|
|
|
|
|
|
values = [];
|
|
|
|
for ( key in obj ) {
|
|
|
|
if ( hasOwn.call( obj, key ) ) {
|
|
|
|
values[values.length] = obj[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return values;
|
|
|
|
};
|
|
|
|
}() );
|
2012-06-20 01:20:28 +00:00
|
|
|
|
2011-11-02 21:00:55 +00:00
|
|
|
/**
|
|
|
|
* Recursively compares string and number property between two objects.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* A false result may be caused by property inequality or by properties in one object missing from
|
|
|
|
* 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.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @static
|
|
|
|
* @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
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.compareObjects = function ( a, b, asymmetrical ) {
|
2012-08-02 18:46:13 +00:00
|
|
|
var aValue, bValue, aType, bType, k;
|
2011-11-02 21:00:55 +00:00
|
|
|
for ( k in a ) {
|
|
|
|
aValue = a[k];
|
|
|
|
bValue = b[k];
|
|
|
|
aType = typeof aValue;
|
|
|
|
bType = typeof bValue;
|
|
|
|
if ( aType !== bType ||
|
|
|
|
( ( aType === 'string' || aType === 'number' ) && aValue !== bValue ) ||
|
2012-02-06 23:50:56 +00:00
|
|
|
( ve.isPlainObject( aValue ) && !ve.compareObjects( aValue, bValue ) ) ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If the check is not asymmetrical, recursing with the arguments swapped will verify our result
|
2012-02-06 23:50:56 +00:00
|
|
|
return asymmetrical ? true : ve.compareObjects( b, a, true );
|
2011-11-02 21:00:55 +00:00
|
|
|
};
|
|
|
|
|
2011-11-15 11:10:21 +00:00
|
|
|
/**
|
|
|
|
* Recursively compare two arrays.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-15 11:10:21 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Array} a First array to compare
|
|
|
|
* @param {Array} b Second array to compare
|
2012-06-28 10:53:15 +00:00
|
|
|
* @param {Boolean} [objectsByValue] Use ve.compareObjects() to compare objects instead of ===
|
2011-11-15 11:10:21 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.compareArrays = function ( a, b, objectsByValue ) {
|
2012-06-28 10:53:15 +00:00
|
|
|
var i,
|
|
|
|
aValue,
|
|
|
|
bValue,
|
|
|
|
aType,
|
|
|
|
bType;
|
2011-11-15 11:10:21 +00:00
|
|
|
if ( a.length !== b.length ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for ( i = 0; i < a.length; i++ ) {
|
|
|
|
aValue = a[i];
|
|
|
|
bValue = b[i];
|
|
|
|
aType = typeof aValue;
|
|
|
|
bType = typeof bValue;
|
2012-06-28 10:53:15 +00:00
|
|
|
if (
|
|
|
|
aType !== bType ||
|
|
|
|
!(
|
|
|
|
(
|
|
|
|
ve.isArray( aValue ) &&
|
|
|
|
ve.isArray( bValue ) &&
|
|
|
|
ve.compareArrays( aValue, bValue )
|
|
|
|
) ||
|
|
|
|
(
|
|
|
|
objectsByValue &&
|
|
|
|
ve.isPlainObject( aValue ) &&
|
|
|
|
ve.compareObjects( aValue, bValue )
|
|
|
|
) ||
|
|
|
|
aValue === bValue
|
|
|
|
)
|
|
|
|
) {
|
2011-11-15 11:10:21 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2011-11-02 21:00:55 +00:00
|
|
|
/**
|
2012-08-30 19:27:40 +00:00
|
|
|
* Gets a deep copy of an array's string, number, array, plain-object and cloneable object contents.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Array} source Array to copy
|
|
|
|
* @returns {Array} Copy of source array
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.copyArray = function ( source ) {
|
2012-08-02 18:46:13 +00:00
|
|
|
var i, sourceValue, sourceType,
|
|
|
|
destination = [];
|
|
|
|
for ( i = 0; i < source.length; i++ ) {
|
|
|
|
sourceValue = source[i];
|
|
|
|
sourceType = typeof sourceValue;
|
2012-09-04 22:13:59 +00:00
|
|
|
if ( sourceType === 'string' || sourceType === 'number' || sourceType === 'undefined' ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
destination.push( sourceValue );
|
2012-02-06 23:50:56 +00:00
|
|
|
} else if ( ve.isPlainObject( sourceValue ) ) {
|
|
|
|
destination.push( ve.copyObject( sourceValue ) );
|
|
|
|
} else if ( ve.isArray( sourceValue ) ) {
|
|
|
|
destination.push( ve.copyArray( sourceValue ) );
|
2012-09-04 22:13:59 +00:00
|
|
|
} else if ( sourceValue && typeof sourceValue.clone === 'function' ) {
|
2012-08-30 19:27:40 +00:00
|
|
|
destination.push( sourceValue.clone() );
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return destination;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a deep copy of an object's string, number, array and plain-object properties.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Object} source Object to copy
|
|
|
|
* @returns {Object} Copy of source object
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.copyObject = function ( source ) {
|
2012-08-02 18:46:13 +00:00
|
|
|
var key, sourceValue, sourceType,
|
|
|
|
destination = {};
|
2012-09-04 22:16:45 +00:00
|
|
|
if ( typeof source.clone === 'function' ) {
|
|
|
|
return source.clone();
|
|
|
|
}
|
2012-08-02 18:46:13 +00:00
|
|
|
for ( key in source ) {
|
|
|
|
sourceValue = source[key];
|
|
|
|
sourceType = typeof sourceValue;
|
2012-09-04 22:16:45 +00:00
|
|
|
if ( sourceType === 'string' || sourceType === 'number' || sourceType === 'undefined' ) {
|
2011-11-02 21:00:55 +00:00
|
|
|
destination[key] = sourceValue;
|
2012-02-06 23:50:56 +00:00
|
|
|
} else if ( ve.isPlainObject( sourceValue ) ) {
|
|
|
|
destination[key] = ve.copyObject( sourceValue );
|
|
|
|
} else if ( ve.isArray( sourceValue ) ) {
|
|
|
|
destination[key] = ve.copyArray( sourceValue );
|
2012-09-04 22:16:45 +00:00
|
|
|
} else if ( sourceValue && typeof sourceValue.clone === 'function' ) {
|
|
|
|
destination[key] = sourceValue.clone();
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return destination;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2012-06-28 10:53:15 +00:00
|
|
|
* Splice one array into another.
|
|
|
|
*
|
|
|
|
* This is the equivalent of arr.splice( offset, remove, d1, d2, d3, ... ) except that arguments are
|
|
|
|
* specified as an array rather than separate parameters.
|
|
|
|
*
|
|
|
|
* This method has been proven to be faster than using slice and concat to create a new array, but
|
|
|
|
* performance tests should be conducted on each use of this method to verify this is true for the
|
|
|
|
* particular use. Also, browsers change fast, never assume anything, always test everything.
|
2012-06-20 01:20:28 +00:00
|
|
|
*
|
2011-11-02 21:00:55 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
2012-03-08 23:21:18 +00:00
|
|
|
* @param {Array} arr Array to remove from and insert into. Will be modified
|
|
|
|
* @param {Number} offset Offset in arr to splice at. May be negative; see the 'index'
|
2011-12-05 18:31:39 +00:00
|
|
|
* parameter for Array.prototype.splice()
|
2012-03-08 23:21:18 +00:00
|
|
|
* @param {Number} remove Number of elements to remove at the offset. May be zero
|
|
|
|
* @param {Array} data Array of items to insert at the offset
|
2011-11-02 21:00:55 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.batchSplice = function ( arr, offset, remove, data ) {
|
2011-12-05 18:31:39 +00:00
|
|
|
// We need to splice insertion in in batches, because of parameter list length limits which vary
|
|
|
|
// cross-browser - 1024 seems to be a safe batch size on all browsers
|
2012-03-08 23:21:18 +00:00
|
|
|
var index = 0, batchSize = 1024, toRemove = remove;
|
|
|
|
|
2012-04-02 22:28:26 +00:00
|
|
|
if ( data.length === 0 ) {
|
2012-03-08 23:21:18 +00:00
|
|
|
// Special case: data is empty, so we're just doing a removal
|
|
|
|
// The code below won't handle that properly, so we do it here
|
|
|
|
arr.splice( offset, remove );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( index < data.length ) {
|
|
|
|
// Call arr.splice( offset, remove, i0, i1, i2, ..., i1023 );
|
|
|
|
// Only set remove on the first call, and set it to zero on subsequent calls
|
|
|
|
arr.splice.apply(
|
|
|
|
arr, [index + offset, toRemove].concat( data.slice( index, index + batchSize ) )
|
2011-11-02 21:00:55 +00:00
|
|
|
);
|
|
|
|
index += batchSize;
|
2012-03-08 23:21:18 +00:00
|
|
|
toRemove = 0;
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
|
|
|
};
|
2011-11-02 23:26:43 +00:00
|
|
|
|
2012-03-08 23:21:18 +00:00
|
|
|
/**
|
2012-06-20 01:20:28 +00:00
|
|
|
* Insert one array into another. This just calls ve.batchSplice( dst, offset, 0, src )
|
|
|
|
*
|
2012-03-08 23:21:18 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
2012-06-20 01:20:28 +00:00
|
|
|
* @see ve.batchSplice
|
2012-03-08 23:21:18 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.insertIntoArray = function ( dst, offset, src ) {
|
2012-06-20 01:20:28 +00:00
|
|
|
ve.batchSplice( dst, offset, 0, src );
|
2012-03-08 23:21:18 +00:00
|
|
|
};
|
|
|
|
|
2011-11-02 23:26:43 +00:00
|
|
|
/**
|
2012-06-20 01:20:28 +00:00
|
|
|
* Logs data to the console.
|
|
|
|
*
|
|
|
|
* This implementation does nothing, to add a real implmementation ve.debug needs to be loaded.
|
|
|
|
*
|
2011-11-02 23:26:43 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
2012-06-20 01:20:28 +00:00
|
|
|
* @param {Mixed} [...] Data to log
|
2011-11-02 23:26:43 +00:00
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.log = function () {
|
2012-06-20 01:20:28 +00:00
|
|
|
// don't do anything, this is just a stub
|
2012-02-06 23:50:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2012-06-20 01:20:28 +00:00
|
|
|
* Logs an object to the console.
|
|
|
|
*
|
|
|
|
* This implementation does nothing, to add a real implmementation ve.debug needs to be loaded.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Object} obj Object to log
|
2012-02-06 23:50:56 +00:00
|
|
|
*/
|
Make use of new jshint options
* Restricting "camelcase":
No changes, we were passing all of these already
* Explicitly unrestricting "forin" and "plusplus"
These are off by default in node-jshint, but some distro of jshint
and editors that use their own wrapper around jshint instead of
node-jshint (Eclipse?) may have different defaults. Therefor
setting them to false explicitly. This also serves as a reminder
for the future so we'll always know we don't pass that, in case
we would want to change that.
* Fix order ("quotemark" before "regexp")
* Restricting "unused"
We're not passing all of this, which is why I've set it to false
for now. But I did put it in .jshintrc as placeholder.
I've fixed most of them, there's some left where there is no clean
solution.
* While at it fix a few issues:
- Unused variables ($target, $window)
- Bad practices (using jQuery context for find instead of creation)
- Redundant /*global */ comments
- Parameters that are not used and don't have documentation either
- Lines longer than 100 chars @ 4 spaces/tab
* Note:
- ve.ce.Surface.prototype.onChange takes two arguments but never
uses the former. And even the second one can be null/undefined.
Aside from that, the .change() function emits
another event for the transaction already. Looks like this
should be refactored a bit, two more separated events probably
or one that is actually used better.
- Also cleaned up a lot of comments, some of which were missing,
others were incorrect
- Reworked the contentChange event so we are no longer using the
word new as an object key; expanded a complex object into multiple
arguments being passed through the event to make it easier to work
with and document
Change-Id: I8490815a508c6c379d5f9a743bb4aefd14576aa6
2012-08-07 06:02:18 +00:00
|
|
|
ve.dir = function () {
|
2012-06-20 01:20:28 +00:00
|
|
|
// don't do anything, this is just a stub
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ported from: http://underscorejs.org/underscore.js
|
|
|
|
*
|
|
|
|
* Returns a function, that, as long as it continues to be invoked, will not
|
|
|
|
* be triggered. The function will be called after it stops being called for
|
|
|
|
* N milliseconds. If `immediate` is passed, trigger the function on the
|
|
|
|
* leading edge, instead of the trailing.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.debounce = function ( func, wait, immediate ) {
|
2012-06-20 01:20:28 +00:00
|
|
|
var timeout;
|
2012-08-07 01:50:44 +00:00
|
|
|
return function () {
|
2012-08-02 18:46:13 +00:00
|
|
|
var context = this,
|
|
|
|
args = arguments,
|
2012-08-07 01:50:44 +00:00
|
|
|
later = function () {
|
2012-08-02 18:46:13 +00:00
|
|
|
timeout = null;
|
|
|
|
if ( !immediate ) {
|
|
|
|
func.apply( context, args );
|
|
|
|
}
|
|
|
|
};
|
2012-06-20 01:20:28 +00:00
|
|
|
if ( immediate && !timeout ) {
|
|
|
|
func.apply( context, args );
|
2012-02-06 23:50:56 +00:00
|
|
|
}
|
2012-06-20 01:20:28 +00:00
|
|
|
clearTimeout( timeout );
|
|
|
|
timeout = setTimeout( later, wait );
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a localized message.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {String} key Message key
|
|
|
|
* @param {Mixed} [...] Message parameters
|
|
|
|
*/
|
2012-08-07 01:50:44 +00:00
|
|
|
ve.msg = function () {
|
2012-07-20 23:59:59 +00:00
|
|
|
return ve.init.platform.getMessage.apply( ve.init.platform, arguments );
|
2011-11-02 23:26:43 +00:00
|
|
|
};
|
2012-08-23 19:19:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Escapes non-word characters so they can be safely used as HTML attribute values.
|
|
|
|
*
|
|
|
|
* This method is basically a copy of mw.html.escape.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {String} value Attribute value to escape
|
|
|
|
* @returns {String} Escaped attribute value
|
|
|
|
*/
|
|
|
|
ve.escapeHtml = function( value ) {
|
|
|
|
return value.replace( /['"<>&]/g, ve.escapeHtml.escapeHtmlCharacter );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper function for ve.escapeHtml which escapes a character for use in HTML.
|
|
|
|
*
|
|
|
|
* This is a callback passed into String.prototype.replace.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {String} key Property name of value being replaced
|
|
|
|
* @returns {String} Escaped charcater
|
|
|
|
*/
|
|
|
|
ve.escapeHtml.escapeHtmlCharacter = function ( value ) {
|
|
|
|
switch ( value ) {
|
2012-08-12 18:27:31 +00:00
|
|
|
case '\'':
|
2012-08-23 19:19:32 +00:00
|
|
|
return ''';
|
|
|
|
case '"':
|
|
|
|
return '"';
|
|
|
|
case '<':
|
|
|
|
return '<';
|
|
|
|
case '>':
|
|
|
|
return '>';
|
|
|
|
case '&':
|
|
|
|
return '&';
|
|
|
|
default:
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
};
|