Jforrester has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/350965 )
Change subject: [WIP] Allow document subscribers to be informed to changes to
nodes
......................................................................
[WIP] Allow document subscribers to be informed to changes to nodes
Bug: T162761
Change-Id: I6b397e792bddc002e78fd7d2b06d509f3da2569d
---
M src/dm/ve.dm.Document.js
M tests/dm/ve.dm.Document.test.js
2 files changed, 163 insertions(+), 0 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor
refs/changes/65/350965/1
diff --git a/src/dm/ve.dm.Document.js b/src/dm/ve.dm.Document.js
index 196ba05..de6151a 100644
--- a/src/dm/ve.dm.Document.js
+++ b/src/dm/ve.dm.Document.js
@@ -52,6 +52,10 @@
this.completeHistory = [];
this.storeLengthAtHistoryLength = [ 0 ];
this.nodesByType = {};
+ this.changeListeners = {};
+
+ // FIXME: DEBUG CODE
+ this.registerListener( 'heading', function() { window.alert( arguments[
0 ] + ': ' + arguments[ 1 ] ); } );
if ( data instanceof ve.dm.ElementLinearData ) {
// Pre-split ElementLinearData
@@ -384,10 +388,12 @@
if ( transaction.hasBeenApplied() ) {
throw new Error( 'Cannot commit a transaction that has already
been committed' );
}
+ this.alertListenersOnRemoves( transaction );
this.emit( 'precommit', transaction );
new ve.dm.TransactionProcessor( this, transaction, isStaging
).process();
this.completeHistory.push( transaction );
this.storeLengthAtHistoryLength[ this.completeHistory.length ] =
this.store.getLength();
+ this.alertListenersOnInserts( transaction );
this.emit( 'transact', transaction );
};
@@ -1664,3 +1670,150 @@
ve.dm.Document.prototype.getDir = function () {
return this.dir;
};
+
+/**
+ * Register a function to be executed on changes to this document of nodes of
the given type.
+ *
+ * @param {string} nodeType Node type
+ * @param {Function} listener Node type
+ */
+ve.dm.Document.prototype.registerListener = function ( nodeType, listener ) {
+ if ( !this.changeListeners.hasOwnProperty( nodeType ) ) {
+ this.changeListeners[ nodeType ] = [];
+ }
+ this.changeListeners[ nodeType ].push( listener );
+};
+
+/**
+ * De-register a function from execution on changes to this document of nodes
of the given type.
+ *
+ * @param {string} nodeType Node type
+ * @param {Function} listener Node type
+ */
+ve.dm.Document.prototype.deregisterListener = function ( nodeType, listener ) {
+ this.changeListeners[ nodeType ].splice( this.changeListeners[ nodeType
].indexOf( listener ) );
+};
+
+/**
+ * Execute listener functions on changes to this document of nodes of the
given type.
+ *
+ * @param {ve.dm.Transaction} tx Transaction that was applied to the document
+ */
+ve.dm.Document.prototype.alertListenersOnRemoves = function ( tx ) {
+ var operations, operation, i, ilen, j, jlen, type, k, klen,
+ listeners = [];
+
+ if ( !Object.keys( this.changeListeners ).length ) {
+ return;
+ }
+
+ operations = tx.getOperations();
+ for ( i = 0, ilen = operations.length; i < ilen; i++ ) {
+ operation = operations[ i ];
+ switch ( operation.type ) {
+ case 'retain':
+ case 'retainMetadata':
+ // No-op
+ continue;
+ case 'annotate':
+ // FIXME: Implement this.
+ continue;
+ case 'attribute':
+ // We only care about this in the
after-transact case.
+ continue;
+ case 'replace':
+ for ( j = 0, jlen = operation.remove.length; j
< jlen; j++ ) {
+ type = operation.remove[ j ].type;
+ if ( !type ||
!this.changeListeners.hasOwnProperty( type ) ) {
+ // Do nothing for text node
changes, or if no-one's registered for this type
+ continue;
+ }
+ for ( k = 0, klen =
this.changeListeners[ type ].length; k < klen; k++ ) {
+ listeners.push( [
this.changeListeners[ type ][ k ], 'remove', operation.remove[ j ] ] );
+ }
+ }
+ break;
+ case 'replaceMetadata':
+ // FIXME: Implement this.
+ continue;
+ default:
+ throw new Error( 'Unrecognised operation type:
' + operation );
+
+ }
+
+ }
+
+ if ( !listeners.length ) {
+ return;
+ }
+
+ for ( i = 0, ilen = listeners.length; i < ilen; i++ ) {
+ listeners[ i ][ 0 ]( listeners[ i ][ 1 ], listeners[ i ][ 2 ] );
+ }
+};
+
+/**
+ * Execute listener functions on changes to this document of nodes of the
given type.
+ *
+ * @param {ve.dm.Transaction} tx Transaction that was applied to the document
+ */
+ve.dm.Document.prototype.alertListenersOnInserts = function ( tx ) {
+ var operations, operation, i, ilen, j, jlen, type, k, klen,
+ listeners = [];
+
+ if ( !Object.keys( this.changeListeners ).length ) {
+ return;
+ }
+
+ operations = tx.getOperations();
+ for ( i = 0, ilen = operations.length; i < ilen; i++ ) {
+ operation = operations[ i ];
+ switch ( operation.type ) {
+ case 'retain':
+ case 'retainMetadata':
+ // No-op
+ continue;
+ case 'annotate':
+ // FIXME: Implement this.
+ continue;
+ case 'attribute':
+ // FIXME: We don't have a reference to the
object to pass on to listeners
+ type = 'heading';
+ if ( !type ||
!this.changeListeners.hasOwnProperty( type ) ) {
+ // Do nothing for text node changes, or
if no-one's registered for this type
+ continue;
+ }
+ for ( k = 0, klen = this.changeListeners[ type
].length; k < klen; k++ ) {
+ listeners.push( [ this.changeListeners[
type ][ k ], operation.type, { from: operation.from, to: operation.to } ] );
+ }
+ break;
+ case 'replace':
+ for ( j = 0, jlen = operation.insert.length; j
< jlen; j++ ) {
+ type = operation.insert[ j ].type;
+ if ( !type ||
!this.changeListeners.hasOwnProperty( type ) ) {
+ // Do nothing for text node
changes, or if no-one's registered for this type
+ continue;
+ }
+ for ( k = 0, klen =
this.changeListeners[ type ].length; k < klen; k++ ) {
+ listeners.push( [
this.changeListeners[ type ][ k ], 'insert', operation.insert[ j ] ] );
+ }
+ }
+ break;
+ case 'replaceMetadata':
+ // FIXME: Implement this.
+ continue;
+ default:
+ throw new Error( 'Unrecognised operation type:
' + operation );
+
+ }
+
+ }
+
+ if ( !listeners.length ) {
+ return;
+ }
+
+ for ( i = 0, ilen = listeners.length; i < ilen; i++ ) {
+ listeners[ i ][ 0 ]( listeners[ i ][ 1 ], listeners[ i ][ 2 ] );
+ }
+};
diff --git a/tests/dm/ve.dm.Document.test.js b/tests/dm/ve.dm.Document.test.js
index e7153a2..cf57d44 100644
--- a/tests/dm/ve.dm.Document.test.js
+++ b/tests/dm/ve.dm.Document.test.js
@@ -1269,3 +1269,13 @@
}
}
} );
+
+QUnit.test( 'listening to transactions', function () {
+ var testDocument = ve.dm.example.createExampleDocument(),
+ txBuilder = new ve.dm.TransactionBuilder();
+ txBuilder.pushRetain( 1 );
+ txBuilder.pushReplace( testDocument, 1, 0, [ 'H', 'e', 'l', 'l', 'o' ]
);
+ // FIXME: WRITEME
+ testDocument.commit( txBuilder.getTransaction() );
+ // FIXME: WRITEME
+} );
--
To view, visit https://gerrit.wikimedia.org/r/350965
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6b397e792bddc002e78fd7d2b06d509f3da2569d
Gerrit-PatchSet: 1
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Jforrester <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits