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
|
|
|
|
*/
|
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
( function () {
|
|
|
|
var ve, hasOwn;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Namespace for all VisualEditor classes, static methods and static properties.
|
|
|
|
*/
|
|
|
|
ve = {
|
|
|
|
// List of instances of ve.Surface
|
|
|
|
'instances': []
|
|
|
|
};
|
2011-11-02 21:00:55 +00:00
|
|
|
|
2012-09-17 23:53:03 +00:00
|
|
|
/* Utility Functions */
|
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
hasOwn = Object.prototype.hasOwnProperty;
|
|
|
|
|
2012-09-17 23:53:03 +00:00
|
|
|
/* Static Methods */
|
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* Create an object that inherits from another object.
|
2012-09-04 23:21:18 +00:00
|
|
|
*
|
2012-09-17 13:30:50 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* @until ES5: Object.create.
|
|
|
|
* @source https://github.com/Krinkle/K-js.
|
|
|
|
* @param {Object} origin Object to inherit from.
|
|
|
|
* @return {Object} Empty object that inherits from origin.
|
|
|
|
*/
|
2012-10-08 04:12:50 +00:00
|
|
|
ve.createObject = Object.create || function ( origin ) {
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
function O() {}
|
|
|
|
O.prototype = origin;
|
|
|
|
var r = new O();
|
|
|
|
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility for common usage of ve.createObject for inheriting from one
|
|
|
|
* prototype to another.
|
|
|
|
*
|
|
|
|
* Beware: This redefines the prototype, call before setting your prototypes.
|
|
|
|
* Beware: This redefines the prototype, can only be called once on a function.
|
|
|
|
* If called multiple times on the same function, the previous prototype is lost.
|
|
|
|
* 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 ve.mixinClass).
|
2012-09-04 23:21:18 +00:00
|
|
|
*
|
|
|
|
* @example
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* <code>
|
|
|
|
* function Foo() {}
|
2012-10-07 07:14:45 +00:00
|
|
|
*
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* Foo.prototype.jump = function () {};
|
2012-09-04 23:21:18 +00:00
|
|
|
*
|
2012-10-07 07:14:45 +00:00
|
|
|
* -------
|
|
|
|
*
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* function FooBar() {}
|
|
|
|
* ve.inheritClass( FooBar, Foo );
|
2012-10-07 07:14:45 +00:00
|
|
|
*
|
|
|
|
* FooBar.prop.feet = 2;
|
|
|
|
*
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* FooBar.prototype.walk = function () {};
|
|
|
|
*
|
2012-10-07 07:14:45 +00:00
|
|
|
* -------
|
|
|
|
*
|
|
|
|
* function FooBarQuux() {}
|
|
|
|
* ve.inheritClass( FooBarQuux, FooBar );
|
|
|
|
*
|
|
|
|
* FooBarQuux.prototype.jump = function () {};
|
|
|
|
*
|
|
|
|
* -------
|
|
|
|
*
|
|
|
|
* FooBarQuux.prop.feet === 2;
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* var fb = new FooBar();
|
|
|
|
* fb.jump();
|
|
|
|
* fb.walk();
|
2012-10-07 07:14:45 +00:00
|
|
|
* fb instanceof Foo && fb instanceof FooBar && fb instanceof FooBarQuux;
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* </code>
|
|
|
|
*
|
2012-09-17 13:30:50 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* @source https://github.com/Krinkle/K-js.
|
|
|
|
* @param {Function} targetFn
|
|
|
|
* @param {Function} originFn
|
|
|
|
*/
|
|
|
|
ve.inheritClass = function ( targetFn, originFn ) {
|
2012-10-07 07:14:45 +00:00
|
|
|
// Doesn't really require ES5 (jshint/jshint#74@github)
|
|
|
|
/*jshint es5: true */
|
|
|
|
var targetConstructor = targetFn.prototype.constructor;
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
|
|
|
|
targetFn.prototype = ve.createObject( originFn.prototype );
|
|
|
|
|
2012-10-07 07:14:45 +00:00
|
|
|
// Restore constructor property of targetFn
|
|
|
|
targetFn.prototype.constructor = targetConstructor;
|
|
|
|
|
|
|
|
// Messing with static properties can be harmful, but we've agreed on one
|
|
|
|
// common property that will be inherited, and that one only. Use this for
|
|
|
|
// for making static values visible in child classes
|
|
|
|
originFn.static = originFn.static || {}; // Lazy-init
|
|
|
|
targetFn.static = ve.createObject( originFn.static );
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility to copy over *own* prototype properties of a mixin.
|
|
|
|
* The 'constructor' (whether implicit or explicit) is not copied over.
|
|
|
|
*
|
|
|
|
* This does not create inheritance to the origin. If inheritance is needed
|
|
|
|
* use ve.inheritClass instead.
|
|
|
|
*
|
|
|
|
* Beware: This can redefine a prototype property, call before setting your prototypes.
|
|
|
|
* Beware: Don't call before ve.inheritClass.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* <code>
|
|
|
|
* function Foo() {}
|
|
|
|
* function Context() {}
|
|
|
|
*
|
|
|
|
* // Avoid repeating this code
|
|
|
|
* function ContextLazyLoad() {}
|
|
|
|
* ContextLazyLoad.prototype.getContext = function () {
|
|
|
|
* if ( !this.context ) {
|
|
|
|
* this.context = new Context();
|
|
|
|
* }
|
|
|
|
* return this.context;
|
|
|
|
* };
|
|
|
|
*
|
|
|
|
* function FooBar() {}
|
|
|
|
* ve.inheritClass( FooBar, Foo );
|
|
|
|
* ve.mixinClass( FooBar, ContextLazyLoad );
|
|
|
|
* </code>
|
|
|
|
*
|
2012-09-17 13:30:50 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* @source https://github.com/Krinkle/K-js.
|
|
|
|
* @param {Function} targetFn
|
|
|
|
* @param {Function} originFn
|
|
|
|
*/
|
|
|
|
ve.mixinClass = function ( targetFn, originFn ) {
|
|
|
|
for ( var key in originFn.prototype ) {
|
|
|
|
if ( key !== 'constructor' && hasOwn.call( originFn.prototype, key ) ) {
|
|
|
|
targetFn.prototype[key] = originFn.prototype[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new object that is an instance of the same
|
|
|
|
* constructor as the input, inherits from the same object
|
|
|
|
* and contains the same own properties.
|
|
|
|
*
|
|
|
|
* This makes a shallow non-recursive copy of own properties.
|
|
|
|
* To create a recursive copy of plain objects, use ve.copyObject.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* <code>
|
|
|
|
* var foo = new Person( mom, dad );
|
|
|
|
* foo.setAge( 21 );
|
|
|
|
* var foo2 = ve.cloneObject( foo );
|
|
|
|
* foo.setAge( 22 );
|
|
|
|
* // Then
|
|
|
|
* foo2 !== foo; // true
|
|
|
|
* foo2 instanceof Person; // true
|
|
|
|
* foo2.getAge(); // 21
|
|
|
|
* foo.getAge(); // 22
|
|
|
|
* </code>
|
|
|
|
*
|
2012-09-17 13:30:50 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* @source https://github.com/Krinkle/K-js.
|
|
|
|
* @param {Object} origin
|
|
|
|
* @return {Object} Clone of origin.
|
2012-09-04 23:21:18 +00:00
|
|
|
*/
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
ve.cloneObject = function ( origin ) {
|
|
|
|
var key, r;
|
|
|
|
|
|
|
|
r = ve.createObject( origin.constructor.prototype );
|
|
|
|
|
|
|
|
for ( key in origin ) {
|
|
|
|
if ( hasOwn.call( origin, key ) ) {
|
|
|
|
r[key] = origin[key];
|
2012-06-22 17:50:41 +00:00
|
|
|
}
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
|
|
|
|
return r;
|
2012-09-04 23:21:18 +00:00
|
|
|
};
|
2012-08-11 08:14:56 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
ve.isPlainObject = $.isPlainObject;
|
|
|
|
|
|
|
|
ve.isEmptyObject = $.isEmptyObject;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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}
|
|
|
|
*/
|
|
|
|
ve.isArray = $.isArray;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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-09-17 13:30:50 +00:00
|
|
|
* Wrapper for Array.prototype.indexOf.
|
|
|
|
*
|
2012-09-04 23:21:18 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @until ES5
|
|
|
|
* @param {Mixed} value Element to search for.
|
|
|
|
* @param {Array} array Array to search in.
|
Object management: Object create/inherit/clone utilities
* For the most common case:
- replace ve.extendClass with ve.inheritClass (chose slightly
different names to detect usage of the old/new one, and I
like 'inherit' better).
- move it up to below the constructor, see doc block for why.
* Cases where more than 2 arguments were passed to
ve.extendClass are handled differently depending on the case.
In case of a longer inheritance tree, the other arguments
could be omitted (like in "ve.ce.FooBar, ve.FooBar,
ve.Bar". ve.ce.FooBar only needs to inherit from ve.FooBar,
because ve.ce.FooBar inherits from ve.Bar).
In the case of where it previously had two mixins with
ve.extendClass(), either one becomes inheritClass and one
a mixin, both to mixinClass().
No visible changes should come from this commit as the
instances still all have the same visible properties in the
end. No more or less than before.
* Misc.:
- Be consistent in calling parent constructors in the
same order as the inheritance.
- Add missing @extends and @param documentation.
- Replace invalid {Integer} type hint with {Number}.
- Consistent doc comments order:
@class, @abstract, @constructor, @extends, @params.
- Fix indentation errors
A fairly common mistake was a superfluous space before the
identifier on the assignment line directly below the
documentation comment.
$ ack "^ [^*]" --js modules/ve
- Typo "Inhertiance" -> "Inheritance".
- Replacing the other confusing comment "Inheritance" (inside
the constructor) with "Parent constructor".
- Add missing @abstract for ve.ui.Tool.
- Corrected ve.FormatDropdownTool to ve.ui.FormatDropdownTool.js
- Add function names to all @constructor functions. Now that we
have inheritance it is important and useful to have these
functions not be anonymous.
Example of debug shot: http://cl.ly/image/1j3c160w3D45
Makes the difference between
< documentNode;
> ve_dm_DocumentNode
...
: ve_dm_BranchNode
...
: ve_dm_Node
...
: ve_dm_Node
...
: Object
...
without names (current situation):
< documentNode;
> Object
...
: Object
...
: Object
...
: Object
...
: Object
...
though before this commit, it really looks like this
(flattened since ve.extendClass really did a mixin):
< documentNode;
> Object
...
...
...
Pattern in Sublime (case-sensitive) to find nameless
constructor functions:
"^ve\..*\.([A-Z])([^\.]+) = function \("
Change-Id: Iab763954fb8cf375900d7a9a92dec1c755d5407e
2012-09-05 06:07:47 +00:00
|
|
|
* @param {Number} [fromIndex=0] Index to being searching from.
|
2012-09-04 23:21:18 +00:00
|
|
|
* @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-09-17 13:30:50 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
2012-09-04 23:21:18 +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.
|
|
|
|
*/
|
|
|
|
ve.extendObject = $.extend;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates 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
|
|
|
|
* not be the fastest way to do this; we should investigate this further.
|
|
|
|
*
|
2012-10-04 00:51:10 +00:00
|
|
|
* Objects an arrays are hashed recursively. When hashing an object that has a .getHash()
|
|
|
|
* function, we call that function and use its return value rather than hashing the object
|
|
|
|
* ourselves. This allows classes to define custom hashing.
|
|
|
|
*
|
2012-09-04 23:21:18 +00:00
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Object} val Object to generate hash for
|
|
|
|
* @returns {String} Hash of object
|
|
|
|
*/
|
|
|
|
ve.getHash = function ( val ) {
|
|
|
|
return JSON.stringify( val, ve.getHash.keySortReplacer );
|
|
|
|
};
|
2011-11-15 12:54:18 +00:00
|
|
|
|
2012-09-04 23:21:18 +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
|
|
|
|
* @param {Mixed} val Property value to replace
|
|
|
|
* @returns {Mixed} Replacement value
|
|
|
|
*/
|
|
|
|
ve.getHash.keySortReplacer = function ( key, val ) {
|
|
|
|
var normalized, keys, i, len;
|
2012-10-04 00:51:10 +00:00
|
|
|
if ( val && typeof val.getHash === 'function' ) {
|
|
|
|
// This object has its own custom hash function, use it
|
|
|
|
return val.getHash();
|
|
|
|
}
|
2012-09-04 23:21:18 +00:00
|
|
|
if ( !ve.isArray( val ) && Object( val ) === val ) {
|
2012-10-04 00:51:10 +00:00
|
|
|
// Only normalize objects when the key-order is ambiguous
|
|
|
|
// (e.g. any object not an array).
|
2012-09-04 23:21:18 +00:00
|
|
|
normalized = {};
|
|
|
|
keys = ve.getObjectKeys( val ).sort();
|
|
|
|
i = 0;
|
|
|
|
len = keys.length;
|
|
|
|
for ( ; i < len; i += 1 ) {
|
|
|
|
normalized[keys[i]] = val[keys[i]];
|
|
|
|
}
|
|
|
|
return normalized;
|
2012-08-15 18:14:44 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
// Primitive values and arrays get stable hashes
|
|
|
|
// by default. Lets those be stringified as-is.
|
|
|
|
} else {
|
|
|
|
return val;
|
2012-08-15 18:14:44 +00:00
|
|
|
}
|
2012-09-04 23:21:18 +00:00
|
|
|
};
|
2012-08-12 18:27:31 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Gets an array of all property names in an object.
|
|
|
|
*
|
|
|
|
* This falls back to the native impelentation of Object.keys if available.
|
|
|
|
* Performance optimization: http://jsperf.com/object-keys-shim-perf#/fnHasown_fnForIfcallLength
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @until ES5
|
|
|
|
* @param {Object} Object to get properties from
|
|
|
|
* @returns {String[]} List of object keys
|
|
|
|
*/
|
2012-10-08 04:12:50 +00:00
|
|
|
ve.getObjectKeys = Object.keys || function ( obj ) {
|
2012-08-12 18:27:31 +00:00
|
|
|
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
|
|
|
|
2012-09-04 23:21:18 +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
|
|
|
|
*/
|
|
|
|
ve.getObjectValues = function ( obj ) {
|
2012-08-12 18:27:31 +00:00
|
|
|
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
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Recursively compares string and number property between two objects.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
ve.compareObjects = function ( a, b, asymmetrical ) {
|
|
|
|
var aValue, bValue, aType, bType, k;
|
|
|
|
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 ) ||
|
|
|
|
( ve.isPlainObject( aValue ) && !ve.compareObjects( aValue, bValue ) ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
2012-09-04 23:21:18 +00:00
|
|
|
// If the check is not asymmetrical, recursing with the arguments swapped will verify our result
|
|
|
|
return asymmetrical ? true : ve.compareObjects( b, a, true );
|
|
|
|
};
|
2011-11-02 21:00:55 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Recursively compare two arrays.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Array} a First array to compare
|
|
|
|
* @param {Array} b Second array to compare
|
|
|
|
* @param {Boolean} [objectsByValue] Use ve.compareObjects() to compare objects instead of ===
|
|
|
|
*/
|
|
|
|
ve.compareArrays = function ( a, b, objectsByValue ) {
|
|
|
|
var i,
|
|
|
|
aValue,
|
|
|
|
bValue,
|
|
|
|
aType,
|
|
|
|
bType;
|
|
|
|
if ( a.length !== b.length ) {
|
2011-11-15 11:10:21 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-09-04 23:21:18 +00:00
|
|
|
for ( i = 0; i < a.length; i++ ) {
|
|
|
|
aValue = a[i];
|
|
|
|
bValue = b[i];
|
|
|
|
aType = typeof aValue;
|
|
|
|
bType = typeof bValue;
|
|
|
|
if (
|
|
|
|
aType !== bType ||
|
|
|
|
!(
|
|
|
|
(
|
|
|
|
ve.isArray( aValue ) &&
|
|
|
|
ve.isArray( bValue ) &&
|
|
|
|
ve.compareArrays( aValue, bValue )
|
|
|
|
) ||
|
|
|
|
(
|
|
|
|
objectsByValue &&
|
|
|
|
ve.isPlainObject( aValue ) &&
|
|
|
|
ve.compareObjects( aValue, bValue )
|
|
|
|
) ||
|
|
|
|
aValue === bValue
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
2011-11-15 11:10:21 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Gets a deep copy of an array's string, number, array, plain-object and cloneable object contents.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Array} source Array to copy
|
|
|
|
* @returns {Array} Copy of source array
|
|
|
|
*/
|
|
|
|
ve.copyArray = function ( source ) {
|
|
|
|
var i, sourceValue, sourceType,
|
|
|
|
destination = [];
|
|
|
|
for ( i = 0; i < source.length; i++ ) {
|
|
|
|
sourceValue = source[i];
|
|
|
|
sourceType = typeof sourceValue;
|
|
|
|
if ( sourceType === 'string' || sourceType === 'number' || sourceType === 'undefined' ) {
|
|
|
|
destination.push( sourceValue );
|
|
|
|
} else if ( ve.isPlainObject( sourceValue ) ) {
|
|
|
|
destination.push( ve.copyObject( sourceValue ) );
|
|
|
|
} else if ( ve.isArray( sourceValue ) ) {
|
|
|
|
destination.push( ve.copyArray( sourceValue ) );
|
|
|
|
} else if ( sourceValue && typeof sourceValue.clone === 'function' ) {
|
|
|
|
destination.push( sourceValue.clone() );
|
|
|
|
}
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
2012-09-04 23:21:18 +00:00
|
|
|
return destination;
|
|
|
|
};
|
2011-11-02 21:00:55 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Gets a deep copy of an object's string, number, array and plain-object properties.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Object} source Object to copy
|
|
|
|
* @returns {Object} Copy of source object
|
|
|
|
*/
|
|
|
|
ve.copyObject = function ( source ) {
|
|
|
|
var key, sourceValue, sourceType,
|
|
|
|
destination = {};
|
|
|
|
if ( typeof source.clone === 'function' ) {
|
|
|
|
return source.clone();
|
2011-11-02 21:00:55 +00:00
|
|
|
}
|
2012-09-04 23:21:18 +00:00
|
|
|
for ( key in source ) {
|
|
|
|
sourceValue = source[key];
|
|
|
|
sourceType = typeof sourceValue;
|
|
|
|
if ( sourceType === 'string' || sourceType === 'number' || sourceType === 'undefined' ) {
|
|
|
|
destination[key] = sourceValue;
|
|
|
|
} else if ( ve.isPlainObject( sourceValue ) ) {
|
|
|
|
destination[key] = ve.copyObject( sourceValue );
|
|
|
|
} else if ( ve.isArray( sourceValue ) ) {
|
|
|
|
destination[key] = ve.copyArray( sourceValue );
|
|
|
|
} else if ( sourceValue && typeof sourceValue.clone === 'function' ) {
|
|
|
|
destination[key] = sourceValue.clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return destination;
|
|
|
|
};
|
2011-11-02 21:00:55 +00:00
|
|
|
|
2012-09-04 23:21:18 +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.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @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'
|
|
|
|
* parameter for Array.prototype.splice()
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
ve.batchSplice = function ( arr, offset, remove, data ) {
|
|
|
|
// 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
|
|
|
|
var index = 0, batchSize = 1024, toRemove = remove;
|
|
|
|
if ( data.length === 0 ) {
|
|
|
|
// 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 ) )
|
|
|
|
);
|
|
|
|
index += batchSize;
|
|
|
|
toRemove = 0;
|
|
|
|
}
|
|
|
|
};
|
2011-11-02 23:26:43 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Insert one array into another. This just calls ve.batchSplice( dst, offset, 0, src )
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @see ve.batchSplice
|
|
|
|
*/
|
|
|
|
ve.insertIntoArray = function ( dst, offset, src ) {
|
|
|
|
ve.batchSplice( dst, offset, 0, src );
|
|
|
|
};
|
2012-03-08 23:21:18 +00:00
|
|
|
|
2012-10-11 00:13:01 +00:00
|
|
|
/**
|
|
|
|
* Get a deeply nested property of an object using variadic arguments, protecting against
|
|
|
|
* undefined property errors.
|
|
|
|
*
|
|
|
|
* quux = getProp( obj, 'foo', 'bar', 'baz' ); is equivalent to quux = obj.foo.bar.baz;
|
|
|
|
* except that the former protects against JS errors if one of the intermediate properties
|
|
|
|
* is undefined. Instead of throwing an error, this function will return undefined in
|
|
|
|
* that case.
|
|
|
|
*
|
|
|
|
* @param {Object} obj
|
|
|
|
* @returns obj[arguments[1]][arguments[2]].... or undefined
|
|
|
|
*/
|
|
|
|
ve.getProp = function ( obj /*, keys ... */ ) {
|
|
|
|
var retval = obj;
|
|
|
|
for ( i = 1; i < arguments.length; i++ ) {
|
|
|
|
if ( retval === undefined || retval === null ) {
|
|
|
|
// Trying to access a property of undefined or null causes an error
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
retval = retval[arguments[i]];
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Logs data to the console.
|
|
|
|
*
|
|
|
|
* This implementation does nothing, to add a real implmementation ve.debug needs to be loaded.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {Mixed} [...] Data to log
|
|
|
|
*/
|
|
|
|
ve.log = function () {
|
|
|
|
// don't do anything, this is just a stub
|
|
|
|
};
|
2012-02-06 23:50:56 +00:00
|
|
|
|
2012-09-04 23:21:18 +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
|
|
|
|
*/
|
|
|
|
ve.dir = function () {
|
|
|
|
// don't do anything, this is just a stub
|
|
|
|
};
|
2012-06-20 01:20:28 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* 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-09-17 13:30:50 +00:00
|
|
|
* @param func
|
|
|
|
* @param wait
|
|
|
|
* @param immediate
|
2012-09-04 23:21:18 +00:00
|
|
|
*/
|
|
|
|
ve.debounce = function ( func, wait, immediate ) {
|
|
|
|
var timeout;
|
|
|
|
return function () {
|
|
|
|
var context = this,
|
|
|
|
args = arguments,
|
|
|
|
later = function () {
|
|
|
|
timeout = null;
|
|
|
|
if ( !immediate ) {
|
|
|
|
func.apply( context, args );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if ( immediate && !timeout ) {
|
|
|
|
func.apply( context, args );
|
|
|
|
}
|
|
|
|
clearTimeout( timeout );
|
|
|
|
timeout = setTimeout( later, wait );
|
|
|
|
};
|
2012-06-20 01:20:28 +00:00
|
|
|
};
|
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* Gets a localized message.
|
|
|
|
*
|
|
|
|
* @static
|
|
|
|
* @method
|
|
|
|
* @param {String} key Message key
|
|
|
|
* @param {Mixed} [...] Message parameters
|
|
|
|
*/
|
|
|
|
ve.msg = function () {
|
|
|
|
return ve.init.platform.getMessage.apply( ve.init.platform, arguments );
|
|
|
|
};
|
2012-08-23 19:19:32 +00:00
|
|
|
|
2012-09-04 23:21:18 +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 );
|
|
|
|
};
|
2012-08-23 19:19:32 +00:00
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
/**
|
|
|
|
* 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 ) {
|
|
|
|
case '\'':
|
|
|
|
return ''';
|
|
|
|
case '"':
|
|
|
|
return '"';
|
|
|
|
case '<':
|
|
|
|
return '<';
|
|
|
|
case '>':
|
|
|
|
return '>';
|
|
|
|
case '&':
|
|
|
|
return '&';
|
|
|
|
default:
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-10-06 00:23:43 +00:00
|
|
|
/**
|
|
|
|
* Generate an opening HTML tag.
|
|
|
|
*
|
|
|
|
* This method copies part of mw.html.element() in MediaWiki.
|
|
|
|
*
|
|
|
|
* NOTE: While the values of attributes are escaped, the tag name and the names of
|
|
|
|
* attributes (i.e. the keys in the attributes objects) are NOT ESCAPED. The caller is
|
|
|
|
* responsible for making sure these are sane tag/attribute names and do not contain
|
|
|
|
* unsanitized content from an external source (e.g. from the user or from the web).
|
|
|
|
*
|
|
|
|
* @param {String} tag HTML tag name
|
|
|
|
* @param {Object} attributes Key-value map of attributes for the tag
|
|
|
|
* @return {String} Opening HTML tag
|
|
|
|
*/
|
|
|
|
ve.getOpeningHtmlTag = function ( tagName, attributes ) {
|
|
|
|
var html, attrName, attrValue;
|
|
|
|
html = '<' + tagName;
|
|
|
|
for ( attrName in attributes ) {
|
|
|
|
attrValue = attributes[attrName];
|
|
|
|
if ( attrValue === true ) {
|
|
|
|
// Convert name=true to name=name
|
|
|
|
attrValue = attrName;
|
|
|
|
} else if ( attrValue === false ) {
|
|
|
|
// Skip name=false
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
html += ' ' + attrName + '="' + ve.escapeHtml( String( attrValue ) ) + '"';
|
|
|
|
}
|
|
|
|
html += '>';
|
|
|
|
return html;
|
|
|
|
};
|
|
|
|
|
2012-10-01 21:14:52 +00:00
|
|
|
/**
|
|
|
|
* Get the attributes of a DOM element as an object with key/value pairs
|
|
|
|
* @param {HTMLElement} element
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
ve.getDOMAttributes = function ( element ) {
|
|
|
|
var result = {}, i;
|
|
|
|
for ( i = 0; i < element.attributes.length; i++ ) {
|
|
|
|
result[element.attributes[i].name] = element.attributes[i].value;
|
|
|
|
}
|
2012-10-05 22:16:45 +00:00
|
|
|
return result;
|
2012-10-01 21:14:52 +00:00
|
|
|
};
|
|
|
|
|
2012-10-04 00:48:06 +00:00
|
|
|
/**
|
|
|
|
* Set the attributes of a DOM element as an object with key/value pairs
|
|
|
|
* @param {HTMLElement} element
|
|
|
|
* @param {Object} attributes
|
|
|
|
*/
|
|
|
|
ve.setDOMAttributes = function ( element, attributes ) {
|
|
|
|
var key;
|
|
|
|
for ( key in attributes ) {
|
|
|
|
if ( attributes[key] === undefined || attributes[key] === null ) {
|
|
|
|
element.removeAttribute( key );
|
|
|
|
} else {
|
|
|
|
element.setAttribute( key, attributes[key] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-09-04 23:21:18 +00:00
|
|
|
// Expose
|
|
|
|
window.ve = ve;
|
|
|
|
}() );
|