mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-24 06:24:08 +00:00
Added basic ve.ce nodes
* Also removed beforeSplice and afterSplice in favor of just plain splice which is the same as afterSplice used to be - beforeSplice was never used and it was making things more complex looking than needed Change-Id: Icbbc57eac73a2a206ba35409ab57b3d1a49ab1a5
This commit is contained in:
parent
aaa322642b
commit
c2d4a2d928
99
modules/ve2/ce/ve.ce.BranchNode.js
Normal file
99
modules/ve2/ce/ve.ce.BranchNode.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* ContentEditable node that can have branch or leaf children.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
* @constructor
|
||||
* @extends {ve.BranchNode}
|
||||
* @extends {ve.ce.Node}
|
||||
* @param model {ve.dm.BranchNode} Model to observe
|
||||
* @param {jQuery} [$element] Element to use as a container
|
||||
*/
|
||||
ve.ce.BranchNode = function( model, $element ) {
|
||||
// Inheritance
|
||||
ve.BranchNode.call( this );
|
||||
ve.ce.Node.call( this, model, $element );
|
||||
|
||||
// Properties
|
||||
this.$ = $element || $( '<div></div>' );
|
||||
|
||||
// Events
|
||||
this.model.addListenerMethod( 'splice', this, 'onSplice' );
|
||||
|
||||
// Initialization
|
||||
this.onAfterSplice.apply( this, [0].concat( model.getChildren() ) );
|
||||
};
|
||||
|
||||
/* Methods */
|
||||
|
||||
ve.ce.BranchNode.prototype.convertDomElement = function( type ) {
|
||||
// Create new element
|
||||
var $new = $( '<' + type + '></' + type + '>' );
|
||||
// Copy classes
|
||||
$new.attr( 'class', this.$.attr( 'class' ) );
|
||||
// Move contents
|
||||
$new.append( this.$.contents() );
|
||||
// Swap elements
|
||||
this.$.replaceWith( $new );
|
||||
// Use new element from now on
|
||||
this.$ = $new;
|
||||
};
|
||||
|
||||
ve.ce.BranchNode.prototype.onSplice = function( index, howmany ) {
|
||||
var i,
|
||||
length,
|
||||
args = Array.prototype.slice.call( arguments, 0 );
|
||||
// Convert models to views and attach them to this node
|
||||
if ( args.length >= 3 ) {
|
||||
for ( i = 2, length = args.length; i < length; i++ ) {
|
||||
args[i] = args[i].createView();
|
||||
}
|
||||
}
|
||||
this.emit.apply( this, ['beforeSplice'].concat( args ) );
|
||||
var removals = this.children.splice.apply( this.children, args );
|
||||
for ( i = 0, length = removals.length; i < length; i++ ) {
|
||||
removals[i].detach();
|
||||
removals[i].removeListener( 'update', this.emitUpdate );
|
||||
// Update DOM
|
||||
removals[i].$.detach();
|
||||
}
|
||||
if ( args.length >= 3 ) {
|
||||
var $target;
|
||||
if ( index ) {
|
||||
// Get the element before the insertion point
|
||||
$anchor = this.$.children().eq( index - 1 );
|
||||
}
|
||||
for ( i = args.length - 1; i >= 2; i-- ) {
|
||||
args[i].attach( this );
|
||||
args[i].on( 'update', this.emitUpdate );
|
||||
if ( index ) {
|
||||
$anchor.after( args[i].$ );
|
||||
} else {
|
||||
this.$.prepend( args[i].$ );
|
||||
}
|
||||
}
|
||||
}
|
||||
this.emit.apply( this, ['afterSplice'].concat( args ) );
|
||||
if ( args.length >= 3 ) {
|
||||
for ( i = 2, length = args.length; i < length; i++ ) {
|
||||
args[i].render();
|
||||
}
|
||||
}
|
||||
this.emit( 'update' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Render content.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
ve.ce.BranchNode.prototype.render = function() {
|
||||
for ( var i = 0; i < this.children.length; i++ ) {
|
||||
this.children[i].render();
|
||||
}
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
ve.extendClass( ve.ce.BranchNode, ve.BranchNode );
|
||||
ve.extendClass( ve.ce.BranchNode, ve.ce.Node );
|
31
modules/ve2/ce/ve.ce.LeafNode.js
Normal file
31
modules/ve2/ce/ve.ce.LeafNode.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* ContentEditable node that can not have any children.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
* @constructor
|
||||
* @extends {ve.LeafNode}
|
||||
* @extends {ve.ce.Node}
|
||||
* @param model {ve.dm.LeafNode} Model to observe
|
||||
*/
|
||||
ve.ce.LeafNode = function( model ) {
|
||||
// Inheritance
|
||||
ve.LeafNode.call( this );
|
||||
ve.ce.Node.call( this, model );
|
||||
};
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Render content.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
ve.ce.LeafNode.prototype.render = function() {
|
||||
//
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
ve.extendClass( ve.ce.LeafNode, ve.LeafNode );
|
||||
ve.extendClass( ve.ce.LeafNode, ve.ce.Node );
|
67
modules/ve2/ce/ve.ce.Node.js
Normal file
67
modules/ve2/ce/ve.ce.Node.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Generic ContentEditable node.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
* @constructor
|
||||
* @extends {ve.Node}
|
||||
* @param {ve.dm.Node} model Model to observe
|
||||
*/
|
||||
ve.ce.Node = function( model ) {
|
||||
// Inheritance
|
||||
ve.Node.call( this );
|
||||
|
||||
// Properties
|
||||
this.model = model;
|
||||
this.parent = null;
|
||||
};
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
* Gets a reference to the model this node observes.
|
||||
*
|
||||
* @method
|
||||
* @returns {ve.dm.Node} Reference to the model this node observes
|
||||
*/
|
||||
ve.ce.Node.prototype.getModel = function() {
|
||||
return this.model;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a reference to this node's parent.
|
||||
*
|
||||
* @method
|
||||
* @returns {ve.ce.Node} Reference to this node's parent
|
||||
*/
|
||||
ve.ce.Node.prototype.getParent = function() {
|
||||
return this.parent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches node as a child to another node.
|
||||
*
|
||||
* @method
|
||||
* @param {ve.ce.Node} parent Node to attach to
|
||||
* @emits attach (parent)
|
||||
*/
|
||||
ve.ce.Node.prototype.attach = function( parent ) {
|
||||
this.parent = parent;
|
||||
this.emit( 'attach', parent );
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches node from it's parent.
|
||||
*
|
||||
* @method
|
||||
* @emits detach (parent)
|
||||
*/
|
||||
ve.ce.Node.prototype.detach = function() {
|
||||
var parent = this.parent;
|
||||
this.parent = null;
|
||||
this.emit( 'detach', parent );
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
ve.extendClass( ve.ce.Node, ve.Node );
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* VisualEditor ContentEditable namespace.
|
||||
* ContentEditable namespace.
|
||||
*
|
||||
* All classes and functions will be attached to this object to keep the global namespace clean.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Data model node that can have branch or twig children.
|
||||
* DataModel node that can have branch or leaf children.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
|
@ -48,8 +48,7 @@ ve.dm.BranchNode.prototype.setRoot = function( root ) {
|
|||
* @method
|
||||
* @param {ve.dm.BranchNode} childModel Item to add
|
||||
* @returns {Integer} New number of children
|
||||
* @emits beforeSplice (index, 0, [childModel])
|
||||
* @emits afterSplice (index, 0, [childModel])
|
||||
* @emits splice (index, 0, [childModel])
|
||||
* @emits update
|
||||
*/
|
||||
ve.dm.BranchNode.prototype.push = function( childModel ) {
|
||||
|
@ -62,8 +61,7 @@ ve.dm.BranchNode.prototype.push = function( childModel ) {
|
|||
*
|
||||
* @method
|
||||
* @returns {ve.dm.BranchNode} Removed childModel
|
||||
* @emits beforeSplice (index, 1, [])
|
||||
* @emits afterSplice (index, 1, [])
|
||||
* @emits splice (index, 1, [])
|
||||
* @emits update
|
||||
*/
|
||||
ve.dm.BranchNode.prototype.pop = function() {
|
||||
|
@ -80,8 +78,7 @@ ve.dm.BranchNode.prototype.pop = function() {
|
|||
* @method
|
||||
* @param {ve.dm.BranchNode} childModel Item to add
|
||||
* @returns {Integer} New number of children
|
||||
* @emits beforeSplice (0, 0, [childModel])
|
||||
* @emits afterSplice (0, 0, [childModel])
|
||||
* @emits splice (0, 0, [childModel])
|
||||
* @emits update
|
||||
*/
|
||||
ve.dm.BranchNode.prototype.unshift = function( childModel ) {
|
||||
|
@ -94,8 +91,7 @@ ve.dm.BranchNode.prototype.unshift = function( childModel ) {
|
|||
*
|
||||
* @method
|
||||
* @returns {ve.dm.BranchNode} Removed childModel
|
||||
* @emits beforeSplice (0, 1, [])
|
||||
* @emits afterSplice (0, 1, [])
|
||||
* @emits splice (0, 1, [])
|
||||
* @emits update
|
||||
*/
|
||||
ve.dm.BranchNode.prototype.shift = function() {
|
||||
|
@ -114,8 +110,7 @@ ve.dm.BranchNode.prototype.shift = function() {
|
|||
* @param {Integer} howmany Number of nodes to remove
|
||||
* @param {ve.dm.BranchNode} [...] Variadic list of nodes to insert
|
||||
* @returns {ve.dm.BranchNode[]} Removed nodes
|
||||
* @emits beforeSplice (index, howmany, [...])
|
||||
* @emits afterSplice (index, howmany, [...])
|
||||
* @emits splice (index, howmany, [...])
|
||||
* @emits update
|
||||
*/
|
||||
ve.dm.BranchNode.prototype.splice = function( index, howmany ) {
|
||||
|
@ -123,7 +118,6 @@ ve.dm.BranchNode.prototype.splice = function( index, howmany ) {
|
|||
length,
|
||||
args = Array.prototype.slice.call( arguments, 0 ),
|
||||
diff = 0;
|
||||
this.emit.apply( this, ['beforeSplice'].concat( args ) );
|
||||
if ( args.length >= 3 ) {
|
||||
length = args.length;
|
||||
for ( i = 2; i < length; i++ ) {
|
||||
|
@ -139,7 +133,7 @@ ve.dm.BranchNode.prototype.splice = function( index, howmany ) {
|
|||
diff -= removals[i].getOuterLength();
|
||||
}
|
||||
this.adjustLength( diff, true );
|
||||
this.emit.apply( this, ['afterSplice'].concat( args ) );
|
||||
this.emit.apply( this, ['splice'].concat( args ) );
|
||||
this.emit( 'update' );
|
||||
return removals;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Document object.
|
||||
* DataModel document.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Document fragment.
|
||||
* DataModel document fragment.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Data model node that can not have children.
|
||||
* DataModel node that can not have children.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Creates an ve.dm.Node object.
|
||||
* Generic DataModel node.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Creates an ve.dm.Transaction object.
|
||||
* DataModel transaction.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Class that processes a transaction.
|
||||
* DataModel transaction processor.
|
||||
*
|
||||
* This class reads operations from a transaction and applies them one by one. It's not intended
|
||||
* to be used directly; use the static functions ve.dm.TransactionProcessor.commit() and .rollback()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* VisualEditor DataModel namespace.
|
||||
* DataModel namespace.
|
||||
*
|
||||
* All classes and functions will be attached to this object to keep the global namespace clean.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Mixin for branch node functionality
|
||||
* Mixin for branch nodes.
|
||||
*
|
||||
* Branch nodes are immutable, which is why there are no methods for adding or removing children.
|
||||
* DataModel classes will add this functionality, and other subclasses will implement behavior that
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Mixin for leaf nodes
|
||||
* Mixin for leaf nodes.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Creates an ve.Node object.
|
||||
* Generic node.
|
||||
*
|
||||
* @class
|
||||
* @abstract
|
||||
|
|
|
@ -22,82 +22,62 @@ test( 'setRoot', 3, function() {
|
|||
strictEqual( node1.getRoot(), node4 );
|
||||
} );
|
||||
|
||||
test( 'push', 4, function() {
|
||||
test( 'push', 3, function() {
|
||||
var node1 = new ve.dm.BranchNodeStub(),
|
||||
node2 = new ve.dm.BranchNodeStub(),
|
||||
node3 = new ve.dm.BranchNodeStub( [node1] );
|
||||
node3.on( 'beforeSplice', function() {
|
||||
node3.on( 'splice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'beforeSplice was emitted' );
|
||||
} );
|
||||
node3.on( 'afterSplice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'afterSplice was emitted' );
|
||||
ok( true, 'splice was emitted' );
|
||||
} );
|
||||
strictEqual( node3.push( node2 ), 2 );
|
||||
deepEqual( node3.getChildren(), [node1, node2] );
|
||||
} );
|
||||
|
||||
test( 'pop', 4, function() {
|
||||
test( 'pop', 3, function() {
|
||||
var node1 = new ve.dm.BranchNodeStub(),
|
||||
node2 = new ve.dm.BranchNodeStub(),
|
||||
node3 = new ve.dm.BranchNodeStub( [node1, node2] );
|
||||
node3.on( 'beforeSplice', function() {
|
||||
node3.on( 'splice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'beforeSplice was emitted' );
|
||||
} );
|
||||
node3.on( 'afterSplice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'afterSplice was emitted' );
|
||||
ok( true, 'splice was emitted' );
|
||||
} );
|
||||
strictEqual( node3.pop(), node2 );
|
||||
deepEqual( node3.getChildren(), [node1] );
|
||||
} );
|
||||
|
||||
test( 'unshift', 4, function() {
|
||||
test( 'unshift', 3, function() {
|
||||
var node1 = new ve.dm.BranchNodeStub(),
|
||||
node2 = new ve.dm.BranchNodeStub(),
|
||||
node3 = new ve.dm.BranchNodeStub( [node1] );
|
||||
node3.on( 'beforeSplice', function() {
|
||||
node3.on( 'splice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'beforeSplice was emitted' );
|
||||
} );
|
||||
node3.on( 'afterSplice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'afterSplice was emitted' );
|
||||
ok( true, 'splice was emitted' );
|
||||
} );
|
||||
strictEqual( node3.unshift( node2 ), 2 );
|
||||
deepEqual( node3.getChildren(), [node2, node1] );
|
||||
} );
|
||||
|
||||
test( 'shift', 4, function() {
|
||||
test( 'shift', 3, function() {
|
||||
var node1 = new ve.dm.BranchNodeStub(),
|
||||
node2 = new ve.dm.BranchNodeStub(),
|
||||
node3 = new ve.dm.BranchNodeStub( [node1, node2] );
|
||||
node3.on( 'beforeSplice', function() {
|
||||
node3.on( 'splice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'beforeSplice was emitted' );
|
||||
} );
|
||||
node3.on( 'afterSplice', function() {
|
||||
// Will be called 1 time
|
||||
ok( true, 'afterSplice was emitted' );
|
||||
ok( true, 'splice was emitted' );
|
||||
} );
|
||||
strictEqual( node3.shift(), node1 );
|
||||
deepEqual( node3.getChildren(), [node2] );
|
||||
} );
|
||||
|
||||
test( 'splice', 12, function() {
|
||||
test( 'splice', 9, function() {
|
||||
var node1 = new ve.dm.BranchNodeStub(),
|
||||
node2 = new ve.dm.BranchNodeStub(),
|
||||
node3 = new ve.dm.BranchNodeStub(),
|
||||
node4 = new ve.dm.BranchNodeStub( [node1, node2] );
|
||||
node4.on( 'beforeSplice', function() {
|
||||
node4.on( 'splice', function() {
|
||||
// Will be called 3 times
|
||||
ok( true, 'beforeSplice was emitted' );
|
||||
} );
|
||||
node4.on( 'afterSplice', function() {
|
||||
// Will be called 3 times
|
||||
ok( true, 'afterSplice was emitted' );
|
||||
ok( true, 'splice was emitted' );
|
||||
} );
|
||||
// Insert branch
|
||||
deepEqual( node4.splice( 1, 0, node3 ), [] );
|
||||
|
|
Loading…
Reference in a new issue