From 9787166bab48f9e2b26ffe48b72d331983a86744 Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Fri, 16 Nov 2012 14:57:20 -0800 Subject: [PATCH] Fixing Pre-Annotations AnnotationAction and SurfaceFragment now use insertAnnotations. ve.dm.Surface.test * Removed test for annotate method (not needed anymore) ve.dm.SurfaceFragment * Now using getInsertionAnnotations method * Added support for modifying insertion annotations when annotating a zero-length selection ve.dm.Surface * Moved in insertion annotations state from document model * Added insertion annotation interface (enable, disable, areEnabled, get, set, add, and remove) * Simplified handling of annotations on change * Removed annotate method (not used anymore) ve.dm.Document * Removed insertion annotations (moved it to surface model) ve.ce.Surface * Cleaned up handleInsertion and changed it to use the insertion annotations interface on the surface model ve.AnnotationAction * Moved insertion annotation handling out of here since it's now included in the surface fragment Change-Id: I047d656acf7fa1c63f726ca2b0801e1476f84f96 --- modules/ve/ce/ve.ce.Surface.js | 70 ++++++------ modules/ve/dm/ve.dm.Document.js | 1 - modules/ve/dm/ve.dm.Surface.js | 131 +++++++++++++++-------- modules/ve/dm/ve.dm.SurfaceFragment.js | 10 +- modules/ve/test/dm/ve.dm.Surface.test.js | 55 ---------- 5 files changed, 133 insertions(+), 134 deletions(-) diff --git a/modules/ve/ce/ve.ce.Surface.js b/modules/ve/ce/ve.ce.Surface.js index 705d0c1bfa..f280083715 100644 --- a/modules/ve/ce/ve.ce.Surface.js +++ b/modules/ve/ce/ve.ce.Surface.js @@ -83,34 +83,38 @@ ve.ce.Surface.static.$phantomTemplate = $( '
0 && - !ve.compareObjects ( - this.model.getDocument().getAnnotationsFromOffset( selection.start - 1 ), - this.model.documentModel.insertAnnotations - ) ) ) { - this.model.insertingAnnotations = true; + // Is this a slug or are the annotations to the left different than the insertion + // annotations? + if ( + slug || ( + selection.start > 0 && + !ve.compareObjects ( + this.model.getDocument().getAnnotationsFromOffset( selection.start - 1 ), + insertionAnnotations + ) + ) + ) { + this.model.enableInsertionAnnotations(); // is this a slug and if so, is this a block slug? if ( slug && ve.dm.Document.isStructuralOffset( this.documentView.model.data, selection.start @@ -118,13 +122,13 @@ ve.ce.Surface.prototype.handleInsertion = function () { range = new ve.Range( selection.start + 1, selection.start + 2 ); data = [ { 'type' : 'paragraph' }, - ['\u2659', this.model.documentModel.insertAnnotations], + ['\u2659', insertionAnnotations], { 'type' : '/paragraph' } ]; } else { range = new ve.Range( selection.start, selection.start + 1 ); data = [ - ['\u2659', this.model.documentModel.insertAnnotations] + ['\u2659', insertionAnnotations] ]; } this.model.change( @@ -184,8 +188,11 @@ ve.ce.Surface.prototype.onContentChange = function ( node, previous, next ) { previous.range.start - nodeOffset - 1, next.range.start - nodeOffset - 1 ).split( '' ); - // Apply insertAnnotations - ve.dm.Document.addAnnotationsToData( data, this.model.getDocument().insertAnnotations ); + // Apply insertion annotations + annotations = this.model.getInsertionAnnotations(); + if ( annotations instanceof ve.AnnotationSet ) { + ve.dm.Document.addAnnotationsToData( data, this.model.getInsertionAnnotations() ); + } this.lock(); this.model.change( ve.dm.Transaction.newFromInsertion( @@ -223,12 +230,12 @@ ve.ce.Surface.prototype.onContentChange = function ( node, previous, next ) { data = next.text.substring( fromLeft, next.text.length - fromRight ).split( '' ); // Get annotations to the left of new content and apply - annotations = this.model.getDocument().getAnnotationsFromOffset( nodeOffset + 1 + fromLeft ); - if ( annotations.getLength() > 0 ) { + annotations = + this.model.getDocument().getAnnotationsFromOffset( nodeOffset + 1 + fromLeft ); + if ( annotations.getLength() ) { ve.dm.Document.addAnnotationsToData( data, annotations ); } - if ( data.length > 0) - { + if ( data.length > 0 ) { this.model.change( ve.dm.Transaction.newFromInsertion( this.documentView.model, nodeOffset + 1 + fromLeft, data @@ -313,7 +320,7 @@ ve.ce.Surface.prototype.onCompositionStart = function () { ve.ce.Surface.prototype.onCompositionEnd = function () { this.inIme = false; - this.model.insertingAnnotations = false; + this.model.disableInsertionAnnotations(); this.surfaceObserver.start(); }; @@ -645,14 +652,11 @@ ve.ce.Surface.prototype.onKeyPress = function ( e ) { if ( ve.ce.Surface.isShortcutKey( e ) || e.which === 13 || e.which === 8 || e.which === 0 ) { return; } - this.handleInsertion(); - - var view = this; - setTimeout( function () { - view.model.insertingAnnotations = false; - view.surfaceObserver.start(); - }, 0 ); + setTimeout( ve.bind( function () { + this.surfaceObserver.start(); + this.model.disableInsertionAnnotations(); + }, this ), 0 ); }; /** diff --git a/modules/ve/dm/ve.dm.Document.js b/modules/ve/dm/ve.dm.Document.js index 26f5923aeb..7b992fd7eb 100644 --- a/modules/ve/dm/ve.dm.Document.js +++ b/modules/ve/dm/ve.dm.Document.js @@ -48,7 +48,6 @@ ve.dm.Document = function VeDmDocument( data, parentDocument ) { currentStack = stack[1], parentStack = stack[0], currentNode = this.documentNode; - this.insertAnnotations = new ve.AnnotationSet(); this.documentNode.setDocument( doc ); this.documentNode.setRoot( root ); for ( i = 0; i < this.data.length; i++ ) { diff --git a/modules/ve/dm/ve.dm.Surface.js b/modules/ve/dm/ve.dm.Surface.js index ba2c2108f9..f7f58397d4 100644 --- a/modules/ve/dm/ve.dm.Surface.js +++ b/modules/ve/dm/ve.dm.Surface.js @@ -24,6 +24,8 @@ ve.dm.Surface = function VeDmSurface( doc ) { this.bigStack = []; this.undoIndex = 0; this.historyTrackingInterval = null; + this.insertionAnnotations = new ve.AnnotationSet(); + this.useInsertionAnnotations = true; }; /* Inheritance */ @@ -76,6 +78,80 @@ ve.dm.Surface.prototype.getHistory = function () { } }; +/** + * Enables insertion annotations. + * + * @method + */ +ve.dm.Surface.prototype.enableInsertionAnnotations = function () { + this.useInsertionAnnotations = true; +}; + +/** + * Disables insertion annotations. + * + * @method + */ +ve.dm.Surface.prototype.disableInsertionAnnotations = function () { + this.useInsertionAnnotations = false; +}; + +/** + * Checks if insertion annotations are enabled. + * + * @method + * @returns {Boolean} Insertion annotations are enabled + */ +ve.dm.Surface.prototype.areInsertionAnnotationsEnabled = function () { + return this.useInsertionAnnotations; +}; + +/** + * Gets annotations that will be used upon insertion. + * + * @method + * @returns {ve.AnnotationSet|null} Insertion anotations or null if not being used + */ +ve.dm.Surface.prototype.getInsertionAnnotations = function () { + return this.insertionAnnotations.clone(); +}; + +/** + * Sets annotations that will be used upon insertion. + * + * @method + * @param {ve.AnnotationSet|null} Insertion anotations to use or null to disable them + * @emits 'annotationChange' + */ +ve.dm.Surface.prototype.setInsertionAnnotations = function ( annotations ) { + this.insertionAnnotations = annotations.clone(); + this.emit( 'annotationChange' ); +}; + +/** + * Adds an annotation to the insertion annotations. + * + * @method + * @param {ve.AnnotationSet} Insertion anotation to add + * @emits 'annotationChange' + */ +ve.dm.Surface.prototype.addInsertionAnnotation = function ( annotation ) { + this.insertionAnnotations.push( annotation ); + this.emit( 'annotationChange' ); +}; + +/** + * Removes an annotation from the insertion annotations. + * + * @method + * @param {ve.AnnotationSet} Insertion anotation to remove + * @emits 'annotationChange' + */ +ve.dm.Surface.prototype.removeInsertionAnnotation = function ( annotation ) { + this.insertionAnnotations.remove( annotation ); + this.emit( 'annotationChange' ); +}; + /** * Checks if there is a state to redo. * @@ -136,7 +212,7 @@ ve.dm.Surface.prototype.getFragment = function ( range, noAutoSelect ) { * @param {ve.Range|undefined} selection */ ve.dm.Surface.prototype.change = function ( transactions, selection ) { - var i, leftOffset, contentOffset, annotations; + var i, offset; if ( transactions ) { if ( transactions instanceof ve.dm.Transaction ) { transactions = [transactions]; @@ -160,56 +236,23 @@ ve.dm.Surface.prototype.change = function ( transactions, selection ) { this.emit( 'transact', transactions ); } - // Clear and add annotations to stack if insertingAnnotations isn't happening - if ( !this.insertingAnnotations ) { - leftOffset = this.getSelection().start - 1; - if ( leftOffset === -1 ) { - leftOffset = 0; + // Clear and add annotations to stack if insertion annotations aren't being used + if ( this.useInsertionAnnotations ) { + offset = this.documentModel.getNearestContentOffset( + Math.max( 0, this.getSelection().start - 1 ), -1 + ); + if ( offset === -1 ) { + // Document is empty, use empty set + this.insertionAnnotations = new ve.AnnotationSet(); + } else { + this.insertionAnnotations = this.documentModel.getAnnotationsFromOffset( offset ); } - contentOffset = this.documentModel.getNearestContentOffset( leftOffset, -1 ); - // contentOffset may be -1 if the document is empty - annotations = contentOffset > - 1 ? - this.documentModel.getAnnotationsFromOffset( contentOffset ) : - new ve.AnnotationSet(); - - // Reset insertAnnotations - this.documentModel.insertAnnotations = new ve.AnnotationSet(); - this.documentModel.insertAnnotations.addSet( annotations ); - this.emit( 'annotationChange' ); } this.emit( 'change', transactions, selection ); }; -/** - * Applies an annotation to the current selection - * - * @method - * @param {String} annotation action: toggle, clear, set - * @param {Object} annotation object to apply. - */ -ve.dm.Surface.prototype.annotate = function ( method, annotation ) { - var tx, - selection = this.getSelection(); - if ( selection.getLength() ) { - // Apply annotation immediately to selection - selection = this.getDocument().trimOuterSpaceFromRange( selection ); - tx = ve.dm.Transaction.newFromAnnotation( - this.getDocument(), selection, method, annotation - ); - this.change( tx, selection ); - } else { - // Apply annotation to stack - if ( method === 'set' ) { - this.documentModel.insertAnnotations.push( annotation ); - } else if ( method === 'clear' ) { - this.documentModel.insertAnnotations.remove( annotation ); - } - } - this.emit( 'annotationChange' ); -}; - /** * Sets a history state breakpoint. * diff --git a/modules/ve/dm/ve.dm.SurfaceFragment.js b/modules/ve/dm/ve.dm.SurfaceFragment.js index c085db99f1..9d647ed6c0 100644 --- a/modules/ve/dm/ve.dm.SurfaceFragment.js +++ b/modules/ve/dm/ve.dm.SurfaceFragment.js @@ -310,7 +310,7 @@ ve.dm.SurfaceFragment.prototype.getAnnotations = function ( all ) { if ( this.range.getLength() ) { return this.document.getAnnotationsFromRange( this.range, all ); } else { - return this.document.getAnnotationsFromOffset( this.range.from ); + return this.surface.getInsertionAnnotations(); } }; @@ -427,8 +427,16 @@ ve.dm.SurfaceFragment.prototype.annotateContent = function ( method, name, data annotation.data = data; } if ( this.range.getLength() ) { + // Apply to selection tx = ve.dm.Transaction.newFromAnnotation( this.document, this.range, method, annotation ); this.surface.change( tx, !this.noAutoSelect && tx.translateRange( this.range ) ); + } else { + // Apply annotation to stack + if ( method === 'set' ) { + this.surface.addInsertionAnnotation( annotation ); + } else if ( method === 'clear' ) { + this.surface.removeInsertionAnnotation( annotation ); + } } return this; }; diff --git a/modules/ve/test/dm/ve.dm.Surface.test.js b/modules/ve/test/dm/ve.dm.Surface.test.js index fa56cfd8a5..fe09ca0356 100644 --- a/modules/ve/test/dm/ve.dm.Surface.test.js +++ b/modules/ve/test/dm/ve.dm.Surface.test.js @@ -57,58 +57,3 @@ QUnit.test( 'change', 3, function ( assert ) { surface.change( tx, new ve.Range( 2, 2 ) ); assert.deepEqual( events, { 'transact': 2, 'select': 2, 'change': 3 } ); } ); - -QUnit.test( 'annotate', 1, function ( assert ) { - var i, - surface, - cases = [ - { - 'msg': 'Set Bold', - 'data': [ - 'b', 'o', 'l', 'd' - ], - 'expected': - [ - [ - 'b', - [ - ve.dm.example.bold - ] - ], - [ - 'o', - [ - ve.dm.example.bold - ] - ], - [ - 'l', - [ - ve.dm.example.bold - ] - ], - [ - 'd', - [ - ve.dm.example.bold - ] - ] - ], - 'annotate': { - 'method': 'set', - 'annotation': ve.dm.example.bold - } - } - ]; - - QUnit.expect( cases.length ); - for ( i = 0; i < cases.length; i++ ) { - ve.dm.example.preprocessAnnotations( cases[i].data ); - ve.dm.example.preprocessAnnotations( cases[i].expected ); - surface = new ve.dm.SurfaceStub( cases[i].data ); - surface.change( null, new ve.Range( 0, surface.getDocument().getData().length ) ); - surface.annotate( cases[i].annotate.method, - ve.dm.example.createAnnotation( cases[i].annotate.annotation ) ); - assert.deepEqual( surface.getDocument().getData(), cases[i].expected, cases[i].msg ); - } -} );