Catrope has uploaded a new change for review.
https://gerrit.wikimedia.org/r/53951
Change subject: Add MetaList
......................................................................
Add MetaList
A MetaList is a collection of MetaItems representing all of the
metadata in a ve.dm.Document, and it updates itself live as the
underlying document changes.
Currently this interface is read-only, I'll add mutators next.
Change-Id: If7bfc9563af37e22dcdca9a682d6decc2f6f1872
---
M .docs/categories.json
M VisualEditor.hooks.php
M VisualEditor.php
M demos/ve/index.php
M modules/ve/dm/ve.dm.MetaItem.js
M modules/ve/dm/ve.dm.MetaItemFactory.js
A modules/ve/dm/ve.dm.MetaList.js
A modules/ve/test/dm/ve.dm.MetaList.test.js
M modules/ve/test/index.php
9 files changed, 533 insertions(+), 2 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor
refs/changes/51/53951/1
diff --git a/.docs/categories.json b/.docs/categories.json
index 96e04d1..3e94f9e 100644
--- a/.docs/categories.json
+++ b/.docs/categories.json
@@ -29,6 +29,7 @@
"classes": [
"ve.dm",
"ve.dm.AnnotationFactory",
+ "ve.dm.MetaItemFactory",
"ve.dm.ModelRegistry",
"ve.dm.Converter",
"ve.dm.DocumentSlice",
@@ -47,7 +48,7 @@
},
{
"name": "Meta items",
- "classes": ["ve.dm.*MetaItem"]
+ "classes": ["ve.dm.*MetaItem", "ve.dm.MetaList"]
},
{
"name": "Nodes",
diff --git a/VisualEditor.hooks.php b/VisualEditor.hooks.php
index ad7ef9d..5b5a3d8 100644
--- a/VisualEditor.hooks.php
+++ b/VisualEditor.hooks.php
@@ -99,6 +99,7 @@
'dm/ve.dm.Surface.test.js',
'dm/ve.dm.SurfaceFragment.test.js',
'dm/ve.dm.ModelRegistry.test.js',
+ 'dm/ve.dm.MetaList.test.js',
// VisualEditor ContentEditable Tests
'ce/ve.ce.test.js',
'ce/ve.ce.Document.test.js',
diff --git a/VisualEditor.php b/VisualEditor.php
index e18bd00..0541a01 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -224,6 +224,7 @@
've/dm/ve.dm.LeafNode.js',
've/dm/ve.dm.Annotation.js',
've/dm/ve.dm.MetaItem.js',
+ 've/dm/ve.dm.MetaList.js',
've/dm/ve.dm.TransactionProcessor.js',
've/dm/ve.dm.Transaction.js',
've/dm/ve.dm.Surface.js',
diff --git a/demos/ve/index.php b/demos/ve/index.php
index e6640c0..3f47c68 100644
--- a/demos/ve/index.php
+++ b/demos/ve/index.php
@@ -120,6 +120,7 @@
<script src="../../modules/ve/dm/ve.dm.LeafNode.js"></script>
<script src="../../modules/ve/dm/ve.dm.Annotation.js"></script>
<script src="../../modules/ve/dm/ve.dm.MetaItem.js"></script>
+ <script src="../../modules/ve/dm/ve.dm.MetaList.js"></script>
<script
src="../../modules/ve/dm/ve.dm.TransactionProcessor.js"></script>
<script src="../../modules/ve/dm/ve.dm.Transaction.js"></script>
<script src="../../modules/ve/dm/ve.dm.Surface.js"></script>
diff --git a/modules/ve/dm/ve.dm.MetaItem.js b/modules/ve/dm/ve.dm.MetaItem.js
index 2d875c0..b5a686e 100644
--- a/modules/ve/dm/ve.dm.MetaItem.js
+++ b/modules/ve/dm/ve.dm.MetaItem.js
@@ -20,6 +20,9 @@
// Properties
this.element = element;
+ this.list = null;
+ this.offset = null;
+ this.index = null;
};
/* Inheritance */
@@ -38,6 +41,15 @@
* @inheritable
*/
ve.dm.MetaItem.static.name = null;
+
+/**
+ * Symbolic name for the group this meta item type will be grouped in in
ve.dm.MetaList.
+ *
+ * @static
+ * @property {String} [static.group='misc']
+ * @inheritable
+ */
+ve.dm.MetaItem.static.group = 'misc';
/**
* Array of HTML tag names that this meta item should be a match candidate for.
@@ -146,4 +158,96 @@
* @property {boolean} static.storeHtmlAttributes
* @inheritable
*/
-ve.dm.MetaItem.static.storeHtmlAttributes = true;
\ No newline at end of file
+ve.dm.MetaItem.static.storeHtmlAttributes = true;
+
+/* Methods */
+
+/**
+ * Get the group this meta item belongs to.
+ * @see ve.dm.MetaItem#static.group
+ * @returns {string} Group
+ */
+ve.dm.MetaItem.prototype.getGroup = function () {
+ return this.constructor.static.group;
+};
+
+/**
+ * Get the metadata element this item represents.
+ * @returns {Object} Metadata element (by reference)
+ */
+ve.dm.MetaItem.prototype.getElement = function () {
+ return this.element;
+};
+
+/**
+ * Get the MetaList this item is attached to.
+ * @returns {ve.dm.MetaList|null} Reference to the parent list, or null if not
attached
+ */
+ve.dm.MetaItem.prototype.getParentList = function () {
+ return this.list;
+};
+
+/**
+ * Get this item's offset in the linear model.
+ *
+ * This is only known if the item is attached to a MetaList.
+ *
+ * @returns {number|null} Offset, or null if not attached
+ */
+ve.dm.MetaItem.prototype.getOffset = function () {
+ return this.offset;
+};
+
+/**
+ * Get this item's index in the metadata array at the offset.
+ *
+ * This is only known if the item is attached to a MetaList.
+ *
+ * @returns {number|null} Index, or null if not attached
+ */
+ve.dm.MetaItem.prototype.getIndex = function () {
+ return this.index;
+};
+
+/**
+ * Set the offset. This is used by the parent list to synchronize the item
with the document state.
+ * @param {number} offset New offset
+ */
+ve.dm.MetaItem.prototype.setOffset = function ( offset ) {
+ this.offset = offset;
+};
+
+/**
+ * Set the index. This is used by the parent list to synchronize the item with
the document state.
+ * @param {number} index New index
+ */
+ve.dm.MetaItem.prototype.setIndex = function ( index ) {
+ this.index = index;
+};
+
+/**
+ * Attach this item to a MetaList.
+ * @param {ve.dm.MetaList} list Parent list to attach to
+ * @param {number} offset Offset of this item in the parent list's document
+ * @param {number} index Index of this item in the metadata array at the offset
+ */
+ve.dm.MetaItem.prototype.attach = function ( list, offset, index ) {
+ this.list = list;
+ this.offset = offset;
+ this.index = index;
+};
+
+/**
+ * Detach this item from its parent list.
+ *
+ * This clears the stored offset and index, unless the item has already been
attached to another list.
+ *
+ * @param {ve.dm.MetaList} list List to detach from
+ */
+ve.dm.MetaItem.prototype.detach = function ( list ) {
+ if ( this.list === list ) {
+ this.list = null;
+ this.offset = null;
+ this.index = null;
+ }
+};
diff --git a/modules/ve/dm/ve.dm.MetaItemFactory.js
b/modules/ve/dm/ve.dm.MetaItemFactory.js
index c77ce35..5604285 100644
--- a/modules/ve/dm/ve.dm.MetaItemFactory.js
+++ b/modules/ve/dm/ve.dm.MetaItemFactory.js
@@ -38,6 +38,20 @@
throw new Error( 'Unknown item type: ' + type );
};
+/**
+ * Get the group a given item type belongs to.
+ *
+ * @method
+ * @param {string} type Meta item type
+ * @returns {string} Group
+ * @throws {Error} Unknown item type
+ */
+ve.dm.MetaItemFactory.prototype.getGroup = function ( type ) {
+ if ( type in this.registry ) {
+ return this.registry[type].static.group;
+ }
+ throw new Error( 'Unknown item type: ' + type );
+};
/* Initialization */
diff --git a/modules/ve/dm/ve.dm.MetaList.js b/modules/ve/dm/ve.dm.MetaList.js
new file mode 100644
index 0000000..84a3b04
--- /dev/null
+++ b/modules/ve/dm/ve.dm.MetaList.js
@@ -0,0 +1,224 @@
+/*!
+ * VisualEditor DataModel MetaList class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel meta item.
+ *
+ * @class
+ * @extends ve.EventEmitter
+ * @constructor
+ * @param {ve.dm.Document} doc Document
+ */
+ve.dm.MetaList = function VeDmMetaList( doc ) {
+ var i, j, metadata, item, group;
+ // Parent constructor
+ ve.EventEmitter.call( this );
+
+ // Properties
+ this.document = doc;
+ this.groups = {};
+ this.items = [];
+
+ // Event handlers
+ this.document.on( 'transact', ve.bind( this.onTransact, this ) );
+
+ // Populate from document
+ metadata = this.document.metadata;
+ for ( i in metadata ) {
+ if ( metadata.hasOwnProperty( i ) && ve.isArray( metadata[i] )
) {
+ for ( j = 0; j < metadata[i].length; j++ ) {
+ item = ve.dm.metaItemFactory.create(
metadata[i][j].type, metadata[i][j] );
+ group = this.groups[item.getGroup()];
+ if ( !group ) {
+ group = this.groups[item.getGroup()] =
[];
+ }
+ item.attach( this, Number( i ), j );
+ group.push( item );
+ this.items.push( item );
+ }
+ }
+ }
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.dm.MetaList, ve.EventEmitter );
+
+/* Methods */
+
+/**
+ * Event handler for transactions on the document.
+ *
+ * When a transaction occurs, update this list to account for it:
+ * - insert items for new metadata that was inserted
+ * - remove items for metadata that was removed
+ * - translate offsets and recompute indices for metadata that has shifted
+ * @param {ve.dm.Transaction} tx Transaction that was applied to the document
+ * @param {boolean} reversed Whether the transaction was applied in reverse
+ */
+ve.dm.MetaList.prototype.onTransact = function ( tx, reversed ) {
+ var i, j, ins, rm, item, offset = 0, index = 0, ops =
tx.getOperations();
+ // Look for replaceMetadata operations in the transaction and
insert/remove items as appropriate
+ // This requires we also inspect retain, replace and replaceMetadata
operations in order to
+ // track the offset and index. We track the pre-transaction offset, we
need to do that in
+ // order to remove items correctly. This also means inserted items are
initially at the wrong
+ // offset, but we translate it later.
+ for ( i = 0; i < ops.length; i++ ) {
+ if ( ops[i].type === 'retain' ) {
+ offset += ops[i].length;
+ index = 0;
+ } else if ( ops[i].type === 'replace' ) {
+ offset += reversed ? ops[i].insert.length :
ops[i].remove.length;
+ index = 0;
+ } else if ( ops[i].type === 'retainMetadata' ) {
+ index += ops[i].length;
+ } else if ( ops[i].type === 'replaceMetadata' ) {
+ ins = reversed ? ops[i].remove : ops[i].insert;
+ rm = reversed ? ops[i].insert : ops[i].remove;
+ for ( j = 0; j < rm.length; j++ ) {
+ this.removeItem( offset, index + j );
+ }
+ for ( j = 0; j < ins.length; j++ ) {
+ item = ve.dm.metaItemFactory.create(
ins[j].type, ins[j] );
+ // offset and index are pre-transaction, but
we'll fix them later
+ this.insertItem( offset, index + j, item );
+ }
+ index += rm.length;
+ }
+ }
+
+ // Translate the offsets of all items, and reindex them too
+ // Reindexing is simple because the above ensures the items are already
in the right order
+ offset = -1;
+ index = 0;
+ for ( i = 0; i < this.items.length; i++ ) {
+ this.items[i].setOffset( tx.translateOffset(
this.items[i].getOffset(), reversed ) );
+ if ( this.items[i].getOffset() === offset ) {
+ index++;
+ } else {
+ index = 0;
+ }
+ this.items[i].setIndex( index );
+ offset = this.items[i].getOffset();
+ }
+};
+
+/**
+ * Find an item by its offset, index and group.
+ *
+ * This function is mostly for internal usage.
+ *
+ * @param {number} offset Offset in the linear model
+ * @param {number} index Index in the metadata array associated with that
offset
+ * @param {string} [group] Group to search in. If not set, search in all
groups.
+ * @param {boolean} [forInsertion] If the item is not found, return the index
where it should have been rather than null
+ * @returns {number|null} Index into this.items or this.groups[group] where
the item was found, or null if not found
+ */
+ve.dm.MetaList.prototype.findItem = function ( offset, index, group,
forInsertion ) {
+ // Binary search for the item
+ var items = typeof group === 'string' ? ( this.groups[group] || [] ) :
this.items,
+ left = 0, right = items.length, mid;
+ while ( left < right ) {
+ mid = Math.floor( ( left + right ) / 2 );
+ if ( items[mid].getOffset() === offset && items[mid].getIndex()
=== index ) {
+ return mid;
+ }
+ if ( items[mid].getOffset() < offset || (
+ items[mid].getOffset() === offset &&
items[mid].getIndex() < index
+ ) ) {
+ left = mid + 1;
+ } else {
+ right = mid;
+ }
+ }
+ return forInsertion ? left : null;
+};
+
+/**
+ * Get the item at a given offset and index, if there is one.
+ * @param {number} offset Offset in the linear model
+ * @param {number} index Index in the metadata array
+ * @returns {ve.dm.MetaItem|null} The item at (offset,index), or null if not
found
+ */
+ve.dm.MetaList.prototype.getItemAt = function ( offset, index ) {
+ var at = this.findItem( offset, index );
+ return at === null ? null : this.items[at];
+};
+
+/**
+ * Get all items in a group.
+ *
+ * This function returns a shallow copy, so the array isn't returned by
reference but the items
+ * themselves are.
+ *
+ * @param {string} group Group
+ * @returns {ve.dm.MetaItem[]} Array of items in the group (shallow copy)
+ */
+ve.dm.MetaList.prototype.getItemsInGroup = function ( group ) {
+ return ( this.groups[group] || [] ).slice( 0 );
+};
+
+/**
+ * Get all items in the list.
+ *
+ * This function returns a shallow copy, so the array isn't returned by
reference but the items
+ * themselves are.
+ *
+ * @returns {ve.dm.MetaItem[]} Array of items in the list
+ */
+ve.dm.MetaList.prototype.getAllItems = function () {
+ return this.items.slice( 0 );
+};
+
+/**
+ * Insert an item at a given offset and index in response to a transaction.
+ *
+ * This function is for internal usage by onTransact(). To actually insert an
item, you need to
+ * process a transaction against the document that inserts metadata, then the
MetaList will
+ * automatically update itself and add the item.
+ *
+ * @param {number} offset Offset in the linear model of the new item
+ * @param {number} index Index of the new item in the metadata array at offset
+ * @param {ve.dm.MetaItem} item Item object
+ */
+ve.dm.MetaList.prototype.insertItem = function ( offset, index, item ) {
+ var group = item.getGroup(), at = this.findItem( offset, index, null,
true );
+ this.items.splice( at, 0, item );
+ if ( this.groups[group] ) {
+ at = this.findItem( offset, index, group, true );
+ this.groups[group].splice( at, 0, item );
+ } else {
+ this.groups[group] = [ item ];
+ }
+ item.attach( this, offset, index );
+};
+
+/**
+ * Remove an item in response to a transaction.
+ *
+ * This function is for internal usage by onTransact(). To actually remove an
item, you need to
+ * process a transaction against the document that removes the associated
metadata, then the
+ * MetaList will automatically update itself and remove the item.
+ *
+ * @param {number} offset Offset in the linear model of the item
+ * @param {number} index Index of the item in the metadata array at offset
+ */
+ve.dm.MetaList.prototype.removeItem = function ( offset, index ) {
+ var at = this.findItem( offset, index ), item, group;
+ if ( at === null ) {
+ return;
+ }
+ item = this.items[at];
+ group = item.getGroup();
+ this.items.splice( at, 1 );
+ at = this.findItem( offset, index, group );
+ if ( at !== null ) {
+ this.groups[group].splice( at, 1 );
+ }
+ item.detach( this );
+};
+
diff --git a/modules/ve/test/dm/ve.dm.MetaList.test.js
b/modules/ve/test/dm/ve.dm.MetaList.test.js
new file mode 100644
index 0000000..c89834b
--- /dev/null
+++ b/modules/ve/test/dm/ve.dm.MetaList.test.js
@@ -0,0 +1,183 @@
+/*!
+ * VisualEditor MetaList tests.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+QUnit.module( 've.dm.MetaList' );
+
+/* Tests */
+
+function assertItemsMatchMetadata( assert, metadata, list, msg, full ) {
+ var i, j, k = 0, items = list.getAllItems();
+ for ( i in metadata ) {
+ if ( ve.isArray( metadata[i] ) ) {
+ for ( j = 0; j < metadata[i].length; j++ ) {
+ assert.strictEqual( items[k].getOffset(),
Number( i ), msg + ' (offset (' + i + ', ' + j + '))' );
+ assert.strictEqual( items[k].getIndex(), j, msg
+ ' (index(' + i + ', ' + j + '))' );
+ if ( full ) {
+ assert.strictEqual(
items[k].getElement(), metadata[i][j], msg + ' (element(' + i + ', ' + j + '))'
);
+ assert.strictEqual(
items[k].getParentList(), list, msg + ' (parentList(' + i + ', ' + j + '))' );
+ }
+ k++;
+ }
+ }
+ }
+ assert.strictEqual( items.length, k, msg + ' (number of items)' );
+}
+
+QUnit.test( 'constructor', function ( assert ) {
+ var i, n = 0,
+ doc = new ve.dm.Document( ve.copyArray( ve.dm.example.withMeta
) ),
+ list = new ve.dm.MetaList( doc ),
+ metadata = doc.metadata;
+ for ( i in metadata ) {
+ if ( ve.isArray( metadata[i] ) ) {
+ n += metadata[i].length;
+ }
+ }
+ QUnit.expect( 4*n + 1 );
+ assertItemsMatchMetadata( assert, metadata, list, 'Constructor', true );
+} );
+
+QUnit.test( 'onTransact', function ( assert ) {
+ var i, j, tx, list, n = 0,
+ doc = new ve.dm.Document( ve.copyArray( ve.dm.example.withMeta
) ),
+ comment = { 'type': 'alienMeta', 'attributes': { 'style':
'comment', 'text': 'onTransact test' } },
+ heading = { 'type': 'heading', 'attributes': { 'level': 2 } },
+ cases = [
+ {
+ // delta: 0
+ 'calls': [
+ [ 'pushRetain', 1 ],
+ [ 'pushReplace', [], [ 'Q', 'u', 'u',
'x' ] ],
+ [ 'pushRetain', 3 ],
+ [ 'pushReplace', [ 'B' ], [] ],
+ [ 'pushRetain', 1 ],
+ [ 'pushReplace', [ 'r', 'B', 'a', 'z'
], [ '!' ] ],
+ [ 'pushRetain', 2 ]
+ ],
+ 'msg': 'Transaction inserting, replacing and
removing text'
+ },
+ {
+ // delta: 0
+ 'calls': [
+ [ 'pushRetainMetadata', 1 ],
+ [ 'pushReplaceMetadata', [], [ comment
] ],
+ [ 'pushRetain', 4 ],
+ [ 'pushReplaceMetadata', [
ve.dm.example.withMetaMetaData[4][0] ], [] ],
+ [ 'pushRetain', 3 ],
+ [ 'pushReplaceMetadata', [
ve.dm.example.withMetaMetaData[7][0] ], [ comment ] ],
+ [ 'pushRetain', 4 ],
+ [ 'pushRetainMetadata', 1 ],
+ [ 'pushReplaceMetadata', [
ve.dm.example.withMetaMetaData[11][1] ], [] ],
+ [ 'pushRetainMetadata', 1 ],
+ [ 'pushReplaceMetadata', [], [ comment
] ]
+ ],
+ 'msg': 'Transaction inserting, replacing and
removing metadata'
+ },
+ {
+ // delta: 0
+ 'calls': [
+ [ 'pushReplace', [
ve.dm.example.withMetaPlainData[0] ], [ heading ] ],
+ [ 'pushRetain', 9 ],
+ [ 'pushReplace', [
ve.dm.example.withMetaPlainData[10] ], [ { 'type': '/heading' } ] ]
+ ],
+ 'msg': 'Transaction converting paragraph to
heading'
+ },
+ {
+ // delta: -9
+ 'calls': [
+ [ 'pushRetain', 1 ],
+ [ 'pushReplace',
ve.dm.example.withMetaPlainData.slice( 1, 10 ), [] ],
+ [ 'pushRetain', 1 ]
+ ],
+ 'msg': 'Transaction blanking paragraph'
+ },
+ {
+ // delta: +11
+ 'calls': [
+ [ 'pushRetain', 11 ],
+ [ 'pushReplace', [],
ve.dm.example.withMetaPlainData ],
+ ],
+ 'msg': 'Transaction adding second paragraph at
the end'
+ },
+ {
+ // delta: -2
+ 'calls': [
+ [ 'pushRetain', 1 ],
+ [ 'pushReplace',
ve.dm.example.withMetaPlainData.slice( 1, 8 ), [] ],
+ [ 'pushRetain', 1 ],
+ [ 'pushReplaceMetadata', [
ve.dm.example.withMetaMetaData[9][0] ], [] ],
+ [ 'pushRetain', 2 ],
+ [ 'pushRetainMetadata', 2 ],
+ // The two operations below have to be
in this order because of bug 46138
+ [ 'pushReplace', [], [ { 'type':
'paragraph' }, 'a', 'b', 'c', { 'type': '/paragraph' } ] ],
+ [ 'pushReplaceMetadata', [], [ comment
] ]
+ ],
+ 'msg': 'Transaction adding and removing text
and metadata'
+ }
+ ];
+ for ( i in doc.metadata ) {
+ if ( ve.isArray( doc.metadata[i] ) ) {
+ n += doc.metadata[i].length;
+ }
+ }
+ // HACK: This works because most transactions above don't change the
document length, and the
+ // ones that do change it cancel out
+ QUnit.expect( cases.length*( 4*n + 2 ) );
+
+ for ( i = 0; i < cases.length; i++ ) {
+ tx = new ve.dm.Transaction();
+ for ( j = 0; j < cases[i].calls.length; j++ ) {
+ tx[cases[i].calls[j][0]].apply( tx,
cases[i].calls[j].slice( 1 ) );
+ }
+ doc = new ve.dm.Document( ve.copyArray( ve.dm.example.withMeta
) );
+ list = new ve.dm.MetaList( doc );
+ ve.dm.TransactionProcessor.commit( doc, tx );
+ assertItemsMatchMetadata( assert, doc.metadata, list,
cases[i].msg, false );
+ ve.dm.TransactionProcessor.rollback( doc, tx );
+ assertItemsMatchMetadata( assert, doc.metadata, list,
cases[i].msg + ' (rollback)', false );
+ }
+} );
+
+QUnit.test( 'findItem', function ( assert ) {
+ var i, j, g, item, element, group, groupDesc,
+ n = 0,
+ groups = [ null ],
+ doc = new ve.dm.Document( ve.copyArray( ve.dm.example.withMeta
) ),
+ metadata = doc.metadata,
+ list = new ve.dm.MetaList( doc );
+
+ for ( i = 0; i < metadata.length; i++ ) {
+ if ( ve.isArray( metadata[i] ) ) {
+ n += metadata[i].length;
+ for ( j = 0; j < metadata[i].length; j++ ) {
+ group = ve.dm.metaItemFactory.getGroup(
metadata[i][j].type );
+ if ( ve.indexOf( group, groups ) === -1 ) {
+ groups.push( group );
+ }
+ }
+ }
+ n++;
+ }
+ QUnit.expect( 2*n*groups.length );
+
+ for ( g = 0; g < groups.length; g++ ) {
+ groupDesc = groups[g] === null ? 'all items' : groups[g];
+ for ( i = 0; i < metadata.length; i++ ) {
+ j = 0;
+ if ( ve.isArray( metadata[i] ) ) {
+ for ( j = 0; j < metadata[i].length; j++ ) {
+ item = list.findItem( i, j, groups[g] );
+ element = item === null ? null :
list.items[item].getElement();
+ assert.strictEqual( element,
metadata[i][j], groupDesc + ' (' + i + ', ' + j + ')' );
+ assert.strictEqual( list.findItem( i,
j, groups[g], true ), item, groupDesc + ' (forInsertion) (' + i + ', ' + j +
')' );
+ }
+ }
+ assert.strictEqual( list.findItem( i, j, groups[g] ),
null, groupDesc + ' (' + i + ', ' + j + ')' );
+ assert.strictEqual( list.findItem( i, j, groups[g],
true ), item + 1, groupDesc + ' (forInsertion) (' + i + ', ' + j + ')' );
+ }
+ }
+} );
\ No newline at end of file
diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php
index 87698b2..a9dc6b8 100644
--- a/modules/ve/test/index.php
+++ b/modules/ve/test/index.php
@@ -65,6 +65,7 @@
<script src="../../ve/dm/ve.dm.LeafNode.js"></script>
<script src="../../ve/dm/ve.dm.Annotation.js"></script>
<script src="../../ve/dm/ve.dm.MetaItem.js"></script>
+ <script src="../../ve/dm/ve.dm.MetaList.js"></script>
<script
src="../../ve/dm/ve.dm.TransactionProcessor.js"></script>
<script src="../../ve/dm/ve.dm.Transaction.js"></script>
<script src="../../ve/dm/ve.dm.Surface.js"></script>
@@ -209,6 +210,7 @@
<script src="dm/ve.dm.Surface.test.js"></script>
<script src="dm/ve.dm.SurfaceFragment.test.js"></script>
<script src="dm/ve.dm.ModelRegistry.test.js"></script>
+ <script src="dm/ve.dm.MetaList.test.js"></script>
<script src="ce/ve.ce.test.js"></script>
<script src="ce/ve.ce.Document.test.js"></script>
<script src="ce/ve.ce.NodeFactory.test.js"></script>
--
To view, visit https://gerrit.wikimedia.org/r/53951
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If7bfc9563af37e22dcdca9a682d6decc2f6f1872
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Catrope <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits