Divec has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/405827 )

Change subject: Create ve.EventEmitter with emitCatch, and use it throughout 
ve.dm
......................................................................

Create ve.EventEmitter with emitCatch, and use it throughout ve.dm

Bug: T185546
Change-Id: I3175a9e985d4ecffa282d9078352523bfbdf4982
---
M .jsduck/categories.json
M build/modules.json
M demos/ve/desktop.html
M demos/ve/mobile.html
M src/dm/nodes/ve.dm.TableNode.js
M src/dm/nodes/ve.dm.TableRowNode.js
M src/dm/nodes/ve.dm.TableSectionNode.js
M src/dm/ve.dm.APIResultsProvider.js
M src/dm/ve.dm.APIResultsQueue.js
M src/dm/ve.dm.Document.js
M src/dm/ve.dm.InternalList.js
M src/dm/ve.dm.MetaItem.js
M src/dm/ve.dm.MetaList.js
M src/dm/ve.dm.Node.js
M src/dm/ve.dm.Scalable.js
M src/dm/ve.dm.Surface.js
M src/dm/ve.dm.SurfaceSynchronizer.js
M src/dm/ve.dm.TableMatrix.js
M src/ve.Document.js
A src/ve.EventEmitter.js
M tests/index.html
21 files changed, 126 insertions(+), 81 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor 
refs/changes/27/405827/1

diff --git a/.jsduck/categories.json b/.jsduck/categories.json
index a7b1fbe..bafa206 100644
--- a/.jsduck/categories.json
+++ b/.jsduck/categories.json
@@ -9,6 +9,7 @@
                                        "ve.Range",
                                        "ve.PositionStep",
                                        "ve.SelectionState",
+                                       "ve.EventEmitter",
                                        "ve.EventSequencer",
                                        "ve.Filibuster",
                                        "ve.TriggerListener",
diff --git a/build/modules.json b/build/modules.json
index d808fa1..7ce11c2 100644
--- a/build/modules.json
+++ b/build/modules.json
@@ -249,6 +249,7 @@
        },
        "visualEditor.core.build": {
                "scripts": [
+                       "src/ve.EventEmitter.js",
                        "src/ve.Range.js",
                        "src/ve.SelectionState.js",
                        "src/ve.Node.js",
diff --git a/demos/ve/desktop.html b/demos/ve/desktop.html
index f8dc64e..94cbd41 100644
--- a/demos/ve/desktop.html
+++ b/demos/ve/desktop.html
@@ -190,6 +190,7 @@
                <script src="../../lib/oojs-ui/oojs-ui-apex.js"></script>
 
                <!-- visualEditor.core.build -->
+               <script src="../../src/ve.EventEmitter.js"></script>
                <script src="../../src/ve.Range.js"></script>
                <script src="../../src/ve.SelectionState.js"></script>
                <script src="../../src/ve.Node.js"></script>
diff --git a/demos/ve/mobile.html b/demos/ve/mobile.html
index b5e6346..88aa00d 100644
--- a/demos/ve/mobile.html
+++ b/demos/ve/mobile.html
@@ -190,6 +190,7 @@
                <script src="../../lib/oojs-ui/oojs-ui-wikimediaui.js"></script>
 
                <!-- visualEditor.core.build -->
+               <script src="../../src/ve.EventEmitter.js"></script>
                <script src="../../src/ve.Range.js"></script>
                <script src="../../src/ve.SelectionState.js"></script>
                <script src="../../src/ve.Node.js"></script>
diff --git a/src/dm/nodes/ve.dm.TableNode.js b/src/dm/nodes/ve.dm.TableNode.js
index 64caa96..8a7ce63 100644
--- a/src/dm/nodes/ve.dm.TableNode.js
+++ b/src/dm/nodes/ve.dm.TableNode.js
@@ -65,7 +65,7 @@
  * @fires cellAttributeChange
  */
 ve.dm.TableNode.prototype.onCellAttributeChange = function ( cell ) {
-       this.emit( 'cellAttributeChange', cell );
+       this.emitCatch( 'cellAttributeChange', cell );
 };
 
 /**
@@ -113,14 +113,14 @@
  * e.g., providing consecutive row indexes.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {ve.dm.TableNode} tableNode Table node to iterate through
  */
 ve.dm.TableNodeCellIterator = function VeDmTableNodeCellIterator( tableNode ) {
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        this.table = tableNode;
 
@@ -141,7 +141,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.dm.TableNodeCellIterator, OO.EventEmitter );
+OO.mixinClass( ve.dm.TableNodeCellIterator, ve.EventEmitter );
 
 /* Events */
 
@@ -200,7 +200,7 @@
        if ( sectionNode instanceof ve.dm.TableSectionNode ) {
                this.sectionNode = sectionNode;
                this.rowCount = this.sectionNode.children.length;
-               this.emit( 'newSection', this.sectionNode );
+               this.emitCatch( 'newSection', this.sectionNode );
        } else {
                this.nextSection();
                return;
@@ -229,7 +229,7 @@
        if ( rowNode instanceof ve.dm.TableRowNode ) {
                this.rowNode = rowNode;
                this.cellCount = this.rowNode.children.length;
-               this.emit( 'newRow', this.rowNode );
+               this.emitCatch( 'newRow', this.rowNode );
        } else {
                this.nextRow();
                return;
diff --git a/src/dm/nodes/ve.dm.TableRowNode.js 
b/src/dm/nodes/ve.dm.TableRowNode.js
index 6245b3a..758f582 100644
--- a/src/dm/nodes/ve.dm.TableRowNode.js
+++ b/src/dm/nodes/ve.dm.TableRowNode.js
@@ -92,7 +92,7 @@
  * @fires cellAttributeChange
  */
 ve.dm.TableRowNode.prototype.onCellAttributeChange = function ( cell ) {
-       this.emit( 'cellAttributeChange', cell );
+       this.emitCatch( 'cellAttributeChange', cell );
 };
 
 /* Registration */
diff --git a/src/dm/nodes/ve.dm.TableSectionNode.js 
b/src/dm/nodes/ve.dm.TableSectionNode.js
index bedc0ee..88ce039 100644
--- a/src/dm/nodes/ve.dm.TableSectionNode.js
+++ b/src/dm/nodes/ve.dm.TableSectionNode.js
@@ -90,7 +90,7 @@
  * @fires cellAttributeChange
  */
 ve.dm.TableSectionNode.prototype.onCellAttributeChange = function ( cell ) {
-       this.emit( 'cellAttributeChange', cell );
+       this.emitCatch( 'cellAttributeChange', cell );
 };
 
 /* Registration */
diff --git a/src/dm/ve.dm.APIResultsProvider.js 
b/src/dm/ve.dm.APIResultsProvider.js
index aa882a4..95864c6 100644
--- a/src/dm/ve.dm.APIResultsProvider.js
+++ b/src/dm/ve.dm.APIResultsProvider.js
@@ -8,7 +8,7 @@
  * API Results Provider object.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {string} apiurl The URL to the api
@@ -38,11 +38,11 @@
        this.toggleDepleted( false );
 
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 };
 
 /* Setup */
-OO.mixinClass( ve.dm.APIResultsProvider, OO.EventEmitter );
+OO.mixinClass( ve.dm.APIResultsProvider, ve.EventEmitter );
 
 /* Methods */
 
diff --git a/src/dm/ve.dm.APIResultsQueue.js b/src/dm/ve.dm.APIResultsQueue.js
index c3650e8..8b5684b 100644
--- a/src/dm/ve.dm.APIResultsQueue.js
+++ b/src/dm/ve.dm.APIResultsQueue.js
@@ -8,7 +8,7 @@
  * API Results Queue object.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {Object} [config] Configuration options
@@ -31,11 +31,11 @@
        this.setThreshold( config.threshold || 10 );
 
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 };
 
 /* Setup */
-OO.mixinClass( ve.dm.APIResultsQueue, OO.EventEmitter );
+OO.mixinClass( ve.dm.APIResultsQueue, ve.EventEmitter );
 
 /* Methods */
 
diff --git a/src/dm/ve.dm.Document.js b/src/dm/ve.dm.Document.js
index d571bf9..8b16e41 100644
--- a/src/dm/ve.dm.Document.js
+++ b/src/dm/ve.dm.Document.js
@@ -311,11 +311,11 @@
        if ( transaction.hasBeenApplied() ) {
                throw new Error( 'Cannot commit a transaction that has already 
been committed' );
        }
-       this.emit( 'precommit', transaction );
+       this.emitCatch( 'precommit', transaction );
        new ve.dm.TransactionProcessor( this, transaction, isStaging 
).process();
        this.completeHistory.push( transaction );
        this.storeLengthAtHistoryLength[ this.completeHistory.length ] = 
this.store.getLength();
-       this.emit( 'transact', transaction );
+       this.emitCatch( 'transact', transaction );
 };
 
 /**
diff --git a/src/dm/ve.dm.InternalList.js b/src/dm/ve.dm.InternalList.js
index 5534203..bce7e24 100644
--- a/src/dm/ve.dm.InternalList.js
+++ b/src/dm/ve.dm.InternalList.js
@@ -8,14 +8,14 @@
  * DataModel meta item.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {ve.dm.Document} doc Document model
  */
 ve.dm.InternalList = function VeDmInternalList( doc ) {
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        // Properties
        this.document = doc;
@@ -35,7 +35,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.dm.InternalList, OO.EventEmitter );
+OO.mixinClass( ve.dm.InternalList, ve.EventEmitter );
 
 /* Events */
 
@@ -376,7 +376,7 @@
                for ( i = 0; i < this.groupsChanged.length; i++ ) {
                        this.sortGroupIndexes( this.nodes[ this.groupsChanged[ 
i ] ] );
                }
-               this.emit( 'update', this.groupsChanged );
+               this.emitCatch( 'update', this.groupsChanged );
                this.groupsChanged = [];
        }
 };
diff --git a/src/dm/ve.dm.MetaItem.js b/src/dm/ve.dm.MetaItem.js
index 1df631c..1be156c 100644
--- a/src/dm/ve.dm.MetaItem.js
+++ b/src/dm/ve.dm.MetaItem.js
@@ -11,7 +11,7 @@
  * @class
  * @abstract
  * @extends ve.dm.LeafNode
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {Object} element Reference to element in meta-linmod
@@ -20,7 +20,7 @@
        // Parent constructor
        ve.dm.MetaItem.super.apply( this, arguments );
        // Mixin
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
        // Properties
        this.list = null;
 };
@@ -29,7 +29,7 @@
 
 OO.inheritClass( ve.dm.MetaItem, ve.dm.LeafNode );
 
-OO.mixinClass( ve.dm.MetaItem, OO.EventEmitter );
+OO.mixinClass( ve.dm.MetaItem, ve.EventEmitter );
 
 /* Static members */
 
diff --git a/src/dm/ve.dm.MetaList.js b/src/dm/ve.dm.MetaList.js
index d183c1e..98ca9d2 100644
--- a/src/dm/ve.dm.MetaList.js
+++ b/src/dm/ve.dm.MetaList.js
@@ -8,7 +8,7 @@
  * DataModel meta item.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {ve.dm.Surface} surface Surface model
@@ -18,7 +18,7 @@
                metaList = this;
 
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        this.surface = surface;
        this.document = surface.getDocument();
@@ -42,7 +42,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.dm.MetaList, OO.EventEmitter );
+OO.mixinClass( ve.dm.MetaList, ve.EventEmitter );
 
 /* Events */
 
@@ -72,7 +72,7 @@
                }, true );
                this.items.splice( i, 0, node );
                node.attachToMetaList( this );
-               this.emit( 'insert', node );
+               this.emitCatch( 'insert', node );
        }
 };
 
@@ -88,7 +88,7 @@
                if ( i !== -1 ) {
                        node.detachFromMetaList( this );
                        this.items.splice( i, 1 );
-                       this.emit( 'remove', node );
+                       this.emitCatch( 'remove', node );
                }
        }
 };
diff --git a/src/dm/ve.dm.Node.js b/src/dm/ve.dm.Node.js
index 85d4fd5..bc1e45b 100644
--- a/src/dm/ve.dm.Node.js
+++ b/src/dm/ve.dm.Node.js
@@ -9,7 +9,7 @@
  *
  * @abstract
  * @extends ve.dm.Model
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  * @mixins ve.Node
  *
  * @constructor
@@ -21,7 +21,7 @@
 
        // Mixin constructors
        ve.Node.call( this );
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        // Properties
        this.length = 0;
@@ -44,7 +44,7 @@
 
 OO.mixinClass( ve.dm.Node, ve.Node );
 
-OO.mixinClass( ve.dm.Node, OO.EventEmitter );
+OO.mixinClass( ve.dm.Node, ve.EventEmitter );
 
 /* Static Properties */
 
@@ -616,8 +616,8 @@
                this.parent.adjustLength( diff );
        }
        // Emit events
-       this.emit( 'lengthChange', diff );
-       this.emit( 'update' );
+       this.emitCatch( 'lengthChange', diff );
+       this.emitCatch( 'update' );
 };
 
 /**
diff --git a/src/dm/ve.dm.Scalable.js b/src/dm/ve.dm.Scalable.js
index 2a2ddde..ffbb243 100644
--- a/src/dm/ve.dm.Scalable.js
+++ b/src/dm/ve.dm.Scalable.js
@@ -8,7 +8,7 @@
  * Scalable object.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {Object} [config] Configuration options
@@ -30,7 +30,7 @@
        }, config );
 
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        // Computed properties
        this.ratio = null;
@@ -71,7 +71,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.dm.Scalable, OO.EventEmitter );
+OO.mixinClass( ve.dm.Scalable, ve.EventEmitter );
 
 /* Events */
 
@@ -238,7 +238,7 @@
                        this.setRatioFromDimensions( 
this.getCurrentDimensions() );
                }
                this.valid = null;
-               this.emit( 'currentSizeChange', this.getCurrentDimensions() );
+               this.emitCatch( 'currentSizeChange', 
this.getCurrentDimensions() );
        }
 };
 
@@ -261,7 +261,7 @@
                        this.setRatioFromDimensions( 
this.getOriginalDimensions() );
                }
                this.valid = null;
-               this.emit( 'originalSizeChange', this.getOriginalDimensions() );
+               this.emitCatch( 'originalSizeChange', 
this.getOriginalDimensions() );
        }
 };
 
@@ -278,7 +278,7 @@
        ) {
                this.defaultDimensions = ve.copy( dimensions );
                this.valid = null;
-               this.emit( 'defaultSizeChange', this.isDefault() );
+               this.emitCatch( 'defaultSizeChange', this.isDefault() );
        }
 };
 
@@ -291,7 +291,7 @@
        if ( this.defaultDimensions !== null ) {
                this.defaultDimensions = null;
                this.valid = null;
-               this.emit( 'defaultSizeChange', this.isDefault() );
+               this.emitCatch( 'defaultSizeChange', this.isDefault() );
        }
 };
 
@@ -304,7 +304,7 @@
        if ( this.originalDimensions !== null ) {
                this.originalDimensions = null;
                this.valid = null;
-               this.emit( 'originalSizeChange', this.isDefault() );
+               this.emitCatch( 'originalSizeChange', this.isDefault() );
        }
 };
 
@@ -325,7 +325,7 @@
                                this.getDefaultDimensions()
                        );
                }
-               this.emit( 'defaultSizeChange', this.isDefault() );
+               this.emitCatch( 'defaultSizeChange', this.isDefault() );
        }
 };
 
@@ -342,7 +342,7 @@
        ) {
                this.minDimensions = ve.copy( dimensions );
                this.valid = null;
-               this.emit( 'minSizeChange', dimensions );
+               this.emitCatch( 'minSizeChange', dimensions );
        }
 };
 
@@ -358,7 +358,7 @@
                !ve.compare( dimensions, this.getMaxDimensions() )
        ) {
                this.maxDimensions = ve.copy( dimensions );
-               this.emit( 'maxSizeChange', dimensions );
+               this.emitCatch( 'maxSizeChange', dimensions );
                this.valid = null;
        }
 };
@@ -372,7 +372,7 @@
        if ( this.minDimensions !== null ) {
                this.minDimensions = null;
                this.valid = null;
-               this.emit( 'minSizeChange', this.minDimensions );
+               this.emitCatch( 'minSizeChange', this.minDimensions );
        }
 };
 
@@ -385,7 +385,7 @@
        if ( this.maxDimensions !== null ) {
                this.maxDimensions = null;
                this.valid = null;
-               this.emit( 'maxSizeChange', this.maxDimensions );
+               this.emitCatch( 'maxSizeChange', this.maxDimensions );
        }
 };
 
diff --git a/src/dm/ve.dm.Surface.js b/src/dm/ve.dm.Surface.js
index 1c2fad1..b0d46bc 100644
--- a/src/dm/ve.dm.Surface.js
+++ b/src/dm/ve.dm.Surface.js
@@ -8,7 +8,7 @@
  * DataModel surface.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  *
  * @constructor
  * @param {ve.dm.Document} doc Document model to create surface for
@@ -19,7 +19,7 @@
        config = config || {};
 
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        // Properties
        this.documentModel = doc;
@@ -53,7 +53,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.dm.Surface, OO.EventEmitter );
+OO.mixinClass( ve.dm.Surface, ve.EventEmitter );
 
 /* Events */
 
@@ -107,7 +107,7 @@
 ve.dm.Surface.prototype.disable = function () {
        this.stopHistoryTracking();
        this.enabled = false;
-       this.emit( 'history' );
+       this.emitCatch( 'history' );
 };
 
 /**
@@ -118,7 +118,7 @@
 ve.dm.Surface.prototype.enable = function () {
        this.enabled = true;
        this.startHistoryTracking();
-       this.emit( 'history' );
+       this.emitCatch( 'history' );
 };
 
 /**
@@ -128,7 +128,7 @@
  */
 ve.dm.Surface.prototype.initialize = function () {
        this.startHistoryTracking();
-       this.emit( 'contextChange' );
+       this.emitCatch( 'contextChange' );
 };
 
 /**
@@ -231,7 +231,7 @@
                // Set a breakpoint to make sure newTransactions is clear
                this.breakpoint();
                this.stopHistoryTracking();
-               this.emit( 'history' );
+               this.emitCatch( 'history' );
        }
        this.stagingStack.push( {
                transactions: [],
@@ -266,7 +266,7 @@
 
        if ( !this.isStaging() ) {
                this.startHistoryTracking();
-               this.emit( 'history' );
+               this.emitCatch( 'history' );
        }
 
        return transactions;
@@ -302,7 +302,8 @@
 
        if ( !this.isStaging() ) {
                this.startHistoryTracking();
-               this.emit( 'history' );
+               this.emitCatch( 'history' );
+
        }
 };
 
@@ -357,8 +358,8 @@
                annotations.clone() :
                new ve.dm.AnnotationSet( this.getDocument().getStore() );
 
-       this.emit( 'insertionAnnotationsChange', this.insertionAnnotations );
-       this.emit( 'contextChange' );
+       this.emitCatch( 'insertionAnnotationsChange', this.insertionAnnotations 
);
+       this.emitCatch( 'contextChange' );
 };
 
 /**
@@ -380,8 +381,8 @@
                throw new Error( 'Invalid annotations' );
        }
 
-       this.emit( 'insertionAnnotationsChange', this.insertionAnnotations );
-       this.emit( 'contextChange' );
+       this.emitCatch( 'insertionAnnotationsChange', this.insertionAnnotations 
);
+       this.emitCatch( 'contextChange' );
 };
 
 /**
@@ -403,8 +404,8 @@
                throw new Error( 'Invalid annotations' );
        }
 
-       this.emit( 'insertionAnnotationsChange', this.insertionAnnotations );
-       this.emit( 'contextChange' );
+       this.emitCatch( 'insertionAnnotationsChange', this.insertionAnnotations 
);
+       this.emitCatch( 'contextChange' );
 };
 
 /**
@@ -543,7 +544,7 @@
        if ( this.queueingContextChanges ) {
                this.contextChangeQueued = true;
        } else {
-               this.emit( 'contextChange' );
+               this.emitCatch( 'contextChange' );
        }
 };
 
@@ -560,7 +561,7 @@
                this.queueingContextChanges = false;
                if ( this.contextChangeQueued ) {
                        this.contextChangeQueued = false;
-                       this.emit( 'contextChange' );
+                       this.emitCatch( 'contextChange' );
                }
        }
 };
@@ -741,12 +742,13 @@
 
        // If selection changed emit a select
        if ( selectionChange ) {
-               this.emit( 'select', this.selection.clone() );
+               this.emitCatch( 'select', this.selection.clone() );
                if ( oldSelection.isNull() ) {
-                       this.emit( 'focus' );
+                       this.emitCatch( 'focus' );
+
                }
                if ( selection.isNull() ) {
-                       this.emit( 'blur' );
+                       this.emitCatch( 'blur' );
                }
        }
 
@@ -859,7 +861,7 @@
                        }
                }
                this.transacting = false;
-               this.emit( 'history' );
+               this.emitCatch( 'history' );
        }
        selectionAfter = this.selection;
 
@@ -878,7 +880,7 @@
                !selectionBefore.equals( selectionAfter ) &&
                selectionAfter.equals( this.selection )
        ) {
-               this.emit( 'select', this.selection.clone() );
+               this.emitCatch( 'select', this.selection.clone() );
        }
 
        if ( contextChange ) {
@@ -967,7 +969,7 @@
  */
 ve.dm.Surface.prototype.onDocumentTransact = function ( tx ) {
        this.setSelection( 
this.getSelection().translateByTransactionWithAuthor( tx, this.authorId ) );
-       this.emit( 'documentUpdate', tx );
+       this.emitCatch( 'documentUpdate', tx );
 };
 
 /**
diff --git a/src/dm/ve.dm.SurfaceSynchronizer.js 
b/src/dm/ve.dm.SurfaceSynchronizer.js
index 651f952..44edc38 100644
--- a/src/dm/ve.dm.SurfaceSynchronizer.js
+++ b/src/dm/ve.dm.SurfaceSynchronizer.js
@@ -9,7 +9,7 @@
  * DataModel surface synchronizer.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  * @mixins ve.dm.RebaseClient
  *
  * @constructor
@@ -22,7 +22,7 @@
        config = config || {};
 
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
        ve.dm.RebaseClient.call( this );
 
        // Properties
@@ -61,7 +61,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.dm.SurfaceSynchronizer, OO.EventEmitter );
+OO.mixinClass( ve.dm.SurfaceSynchronizer, ve.EventEmitter );
 OO.mixinClass( ve.dm.SurfaceSynchronizer, ve.dm.RebaseClient );
 
 /* Events */
@@ -242,14 +242,14 @@
                }
                if ( !translatedSelection.equals( this.authorSelections[ 
authorId ] ) ) {
                        this.authorSelections[ authorId ] = translatedSelection;
-                       this.emit( 'authorSelect', authorId );
+                       this.emitCatch( 'authorSelect', authorId );
                }
        }
 };
 
 ve.dm.SurfaceSynchronizer.prototype.onNameChange = function ( data ) {
        this.authorNames[ data.authorId ] = data.authorName;
-       this.emit( 'authorNameChange', data.authorId );
+       this.emitCatch( 'authorNameChange', data.authorId );
 };
 
 ve.dm.SurfaceSynchronizer.prototype.changeName = function ( newName ) {
@@ -258,7 +258,7 @@
 
 ve.dm.SurfaceSynchronizer.prototype.onAuthorDisconnect = function ( authorId ) 
{
        delete this.authorSelections[ authorId ];
-       this.emit( 'authorDisconnect', authorId );
+       this.emitCatch( 'authorDisconnect', authorId );
 };
 
 /**
diff --git a/src/dm/ve.dm.TableMatrix.js b/src/dm/ve.dm.TableMatrix.js
index 7474442..f8ec560 100644
--- a/src/dm/ve.dm.TableMatrix.js
+++ b/src/dm/ve.dm.TableMatrix.js
@@ -29,13 +29,13 @@
  * and P[1] a PlaceHolder instance owned by that cell.
  *
  * @class
- * @mixins OO.EventEmitter
+ * @mixins ve.EventEmitter
  * @constructor
  * @param {ve.dm.TableNode} tableNode Reference to a table instance
  */
 ve.dm.TableMatrix = function VeDmTableMatrix( tableNode ) {
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        this.tableNode = tableNode;
        // Do not access these directly as they get invalidated on structural 
changes
@@ -46,7 +46,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.dm.TableMatrix, OO.EventEmitter );
+OO.mixinClass( ve.dm.TableMatrix, ve.EventEmitter );
 
 /**
  * @event structureChange
@@ -62,7 +62,7 @@
 ve.dm.TableMatrix.prototype.invalidate = function () {
        this.matrix = null;
        this.rowNodes = null;
-       this.emit( 'structureChange' );
+       this.emitCatch( 'structureChange' );
 };
 
 /**
diff --git a/src/ve.Document.js b/src/ve.Document.js
index 5e47b5f..ef2fcae 100644
--- a/src/ve.Document.js
+++ b/src/ve.Document.js
@@ -15,7 +15,7 @@
  */
 ve.Document = function VeDocument( documentNode ) {
        // Mixin constructors
-       OO.EventEmitter.call( this );
+       ve.EventEmitter.call( this );
 
        // Properties
        this.documentNode = documentNode;
@@ -24,7 +24,7 @@
 
 /* Inheritance */
 
-OO.mixinClass( ve.Document, OO.EventEmitter );
+OO.mixinClass( ve.Document, ve.EventEmitter );
 
 /* Events */
 
diff --git a/src/ve.EventEmitter.js b/src/ve.EventEmitter.js
new file mode 100644
index 0000000..de592d3
--- /dev/null
+++ b/src/ve.EventEmitter.js
@@ -0,0 +1,38 @@
+/*!
+ * VisualEditor EventEmitter class.
+ *
+ * @copyright 2011-2018 VisualEditor Team and others; see 
http://ve.mit-license.org
+ */
+
+/**
+ * EventEmitter class.
+ *
+ * @class
+ * @abstract
+ * @mixins OO.EventEmitter
+ * @constructor
+ */
+ve.EventEmitter = function VeEventEmitter() {
+       // Mix-in constructor
+       OO.EventEmitter.apply( this, arguments );
+};
+
+OO.mixinClass( ve.EventEmitter, OO.EventEmitter );
+
+/* Methods */
+
+/**
+ * Emit an event, catching (and ignoring) errors in handlers
+ *
+ * @param {string} event Type of event
+ * @param {...Mixed} args First in a list of variadic arguments passed to 
event handler (optional)
+ * @return {boolean} Whether the event was handled by at least one listener
+ */
+ve.EventEmitter.prototype.emitCatch = function () {
+       // TODO: Consider wrapping each handler call in a separate try/catch
+       try {
+               return this.emit.apply( this, arguments );
+       } catch ( ex ) {
+               return true;
+       }
+};
diff --git a/tests/index.html b/tests/index.html
index a9f781b..c7c4bf2 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -100,6 +100,7 @@
                <script src="../lib/oojs-ui/oojs-ui-apex.js"></script>
 
                <!-- visualEditor.core.build -->
+               <script src="../src/ve.EventEmitter.js"></script>
                <script src="../src/ve.Range.js"></script>
                <script src="../src/ve.SelectionState.js"></script>
                <script src="../src/ve.Node.js"></script>

-- 
To view, visit https://gerrit.wikimedia.org/r/405827
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3175a9e985d4ecffa282d9078352523bfbdf4982
Gerrit-PatchSet: 1
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Divec <da...@troi.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to