mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-30 17:14:42 +00:00
Implement ve.NodeFactory and add tests
Change-Id: I34fdf24c0099072fe5f7178400abbc323be975d4
This commit is contained in:
parent
a239b73746
commit
69df3eefbc
|
@ -1,15 +1,44 @@
|
||||||
/**
|
/**
|
||||||
* Data model node factory.
|
* Generic node factory.
|
||||||
*
|
*
|
||||||
* @class
|
* @class
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
ve.NodeFactory = function() {
|
ve.NodeFactory = function() {
|
||||||
//
|
this.registry = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Methods */
|
/* Methods */
|
||||||
|
|
||||||
ve.NodeFactory.prototype.register = function( name, constructor ) {
|
/**
|
||||||
//
|
* Register a node type with the factory.
|
||||||
|
*
|
||||||
|
* The constructor will be called as constructor( contents, attributes ), see createNode().
|
||||||
|
*
|
||||||
|
* @param {String} type Node type
|
||||||
|
* @param {Function} constructor Node constructor subclassing ve.Node
|
||||||
|
*/
|
||||||
|
ve.NodeFactory.prototype.register = function( type, constructor ) {
|
||||||
|
if ( typeof constructor !== 'function' ) {
|
||||||
|
throw 'Constructor must be a function, cannot be a ' + typeof constructor;
|
||||||
|
}
|
||||||
|
this.registry[type] = constructor;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a node based on a type. type is used to look up the constructor to use, contents and
|
||||||
|
* attributes are passed to the constructor.
|
||||||
|
*
|
||||||
|
* @param {String} type Node type
|
||||||
|
* @param {Array|Number} contents Either an array of child nodes (for non-leaf nodes)
|
||||||
|
* or the length (for leaf nodes)
|
||||||
|
* @param {Object} [attributes] Attribute key/value pairs
|
||||||
|
* @returns {ve.Node|null} The node object, or null if type is not a registered node type.
|
||||||
|
*/
|
||||||
|
ve.NodeFactory.prototype.createNode = function( type, contents, attributes ) {
|
||||||
|
if ( type in this.registry ) {
|
||||||
|
return new this.registry[type]( contents, attributes );
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
<script src="../../modules/ve2/ve.BranchNode.js"></script>
|
<script src="../../modules/ve2/ve.BranchNode.js"></script>
|
||||||
<script src="../../modules/ve2/ve.TwigNode.js"></script>
|
<script src="../../modules/ve2/ve.TwigNode.js"></script>
|
||||||
<script src="../../modules/ve2/ve.LeafNode.js"></script>
|
<script src="../../modules/ve2/ve.LeafNode.js"></script>
|
||||||
|
<script src="../../modules/ve2/ve.NodeFactory.js"></script>
|
||||||
|
|
||||||
<!-- VisualEditor DataModel -->
|
<!-- VisualEditor DataModel -->
|
||||||
<script src="../../modules/ve2/dm/ve.dm.js"></script>
|
<script src="../../modules/ve2/dm/ve.dm.js"></script>
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
<script src="ve.BranchNode.test.js"></script>
|
<script src="ve.BranchNode.test.js"></script>
|
||||||
<script src="ve.TwigNode.test.js"></script>
|
<script src="ve.TwigNode.test.js"></script>
|
||||||
<script src="ve.LeafNode.test.js"></script>
|
<script src="ve.LeafNode.test.js"></script>
|
||||||
|
<script src="ve.NodeFactory.test.js"></script>
|
||||||
<script src="dm/ve.dm.Node.test.js"></script>
|
<script src="dm/ve.dm.Node.test.js"></script>
|
||||||
<script src="dm/ve.dm.BranchNode.test.js"></script>
|
<script src="dm/ve.dm.BranchNode.test.js"></script>
|
||||||
<script src="dm/ve.dm.TwigNode.test.js"></script>
|
<script src="dm/ve.dm.TwigNode.test.js"></script>
|
||||||
|
|
40
tests/ve2/ve.NodeFactory.test.js
Normal file
40
tests/ve2/ve.NodeFactory.test.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
module( 've.NodeFactory' );
|
||||||
|
|
||||||
|
/* Stubs */
|
||||||
|
|
||||||
|
ve.NodeStub1 = function( content, attributes ) {
|
||||||
|
this.content = content;
|
||||||
|
this.attributes = attributes;
|
||||||
|
this.type = 'nodestub1';
|
||||||
|
};
|
||||||
|
|
||||||
|
ve.NodeStub2 = function( content, attributes ) {
|
||||||
|
this.content = content;
|
||||||
|
this.attributes = attributes;
|
||||||
|
this.type = 'nodestub2';
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Tests */
|
||||||
|
|
||||||
|
test( 've.NodeFactory', function() {
|
||||||
|
var factory = new ve.NodeFactory();
|
||||||
|
|
||||||
|
factory.register( 'nodestub1', ve.NodeStub1 );
|
||||||
|
var ns1 = factory.createNode( 'nodestub1', 42, { 'foo': 'bar' } );
|
||||||
|
deepEqual( ns1, new ve.NodeStub1( 42, { 'foo': 'bar' } ), 'createNode creates a node ' +
|
||||||
|
'using the registered constructor and passes through arguments' );
|
||||||
|
|
||||||
|
deepEqual( factory.createNode( 'nodestub2', 23, { 'bar': 'baz' } ), null, 'createNode ' +
|
||||||
|
'returns null for unregistered node types' );
|
||||||
|
factory.register( 'nodestub2', ve.NodeStub2 );
|
||||||
|
var ns2 = factory.createNode( 'nodestub2', 16, { 'baz': 'quux' } );
|
||||||
|
deepEqual( ns2, new ve.NodeStub2( 16, { 'baz': 'quux' } ), 'createNode creates a node ' +
|
||||||
|
'with a previously unregistered type' );
|
||||||
|
|
||||||
|
raises( function() {
|
||||||
|
factory.register( 'nodestub3', 'nodestub3' );
|
||||||
|
},
|
||||||
|
/^Constructor must be a function, cannot be a string$/,
|
||||||
|
'register throws an exception when trying to register a string as a constructor'
|
||||||
|
);
|
||||||
|
} );
|
Loading…
Reference in a new issue