Cleaned up toolbar annotation updates

Change-Id: I8cefd6c871ed6d1ad71f64eb66236de1b8b719b5
This commit is contained in:
Trevor Parscal 2012-06-13 14:31:33 -07:00
parent 26e0f6ed5f
commit 169b7e754d
8 changed files with 259 additions and 220 deletions

View file

@ -11,24 +11,24 @@ ve.ce.Surface = function( $container, model ) {
// Properties // Properties
this.model = model; this.model = model;
this.documentView = new ve.ce.Document( model.getDocument() );
this.contextView = new ve.ui.Context( this ); // Properties
this.documentView = null; // See initialization below
this.contextView = null; // See initialization below
this.$ = $container; this.$ = $container;
this.clipboard = {}; this.clipboard = {};
// Driven by mousedown and mouseup events
this.isMouseDown = false;
this.range = { this.range = {
anchorNode: null, 'anchorNode': null,
anchorOffset: null, 'anchorOffset': null,
focusNode: null, 'focusNode': null,
focusOffset: null 'focusOffset': null
}; };
// Tracked using mouse events
// init rangy in case of Toshiba... this.isMouseDown = false;
rangy.init();
// Events // Events
this.model.on( 'select', ve.proxy( this.onSelect, this ) );
this.model.on( 'transact', ve.proxy( this.onTransact, this ) );
this.$.on( { this.$.on( {
'keypress': ve.proxy( this.onKeyPress, this ), 'keypress': ve.proxy( this.onKeyPress, this ),
'keydown': ve.proxy( this.onKeyDown, this ), 'keydown': ve.proxy( this.onKeyDown, this ),
@ -43,31 +43,38 @@ ve.ce.Surface = function( $container, model ) {
return false; return false;
} }
} ); } );
if ($.browser.msie) { if ( $.browser.msie ) {
this.$.on('beforepaste', ve.proxy( this.onPaste, this ) ); this.$.on( 'beforepaste', ve.proxy( this.onPaste, this ) );
} }
this.model.on( 'select', ve.proxy( this.onSelect, this ) );
// Initialization // Initialization
this.$.append( this.documentView.documentNode.$ );
try { try {
document.execCommand( "enableObjectResizing", false, false ); document.execCommand( 'enableObjectResizing', false, false );
document.execCommand( "enableInlineTableEditing", false, false ); document.execCommand( 'enableInlineTableEditing', false, false );
} catch (e) { } } catch ( e ) {
// Silently ignore
}
// Initialize rangy in case of Toshiba...
rangy.init();
// Must be initialized after select and transact listeners are added to model so respond first
this.documentView = new ve.ce.Document( model.getDocument() );
this.contextView = new ve.ui.Context( this );
this.$.append( this.documentView.documentNode.$ );
}; };
/* Methods */ /* Methods */
ve.ce.Surface.prototype.onSelect = function( e ) { ve.ce.Surface.prototype.onSelect = function( range ) {
console.log("onSelect", e); //console.log( 'onSelect', range );
};
ve.ce.Surface.prototype.onTransact = function( tx ) {
//console.log( 'onTransact', tx );
this.showSelection( this.model.getSelection() );
}; };
ve.ce.Surface.prototype.onKeyPress = function( e ) { ve.ce.Surface.prototype.onKeyPress = function( e ) {
console.log('onKeyPress'); //console.log( 'onKeyPress' );
switch ( e.which ) { switch ( e.which ) {
// Enter // Enter
case 13: case 13:
@ -78,13 +85,12 @@ ve.ce.Surface.prototype.onKeyPress = function( e ) {
}; };
ve.ce.Surface.prototype.onKeyDown = function( e ) { ve.ce.Surface.prototype.onKeyDown = function( e ) {
console.log('onKeyDown'); //console.log( 'onKeyDown' );
// Prevent all interactions coming from keyboard when mouse is down (possibly selecting) // Prevent all interactions coming from keyboard when mouse is down (possibly selecting)
if ( this.isMouseDown === true ) { if ( this.isMouseDown === true ) {
e.preventDefault(); e.preventDefault();
return false; return false;
} }
switch ( e.keyCode ) { switch ( e.keyCode ) {
// Left arrow // Left arrow
case 37: case 37:
@ -94,12 +100,9 @@ ve.ce.Surface.prototype.onKeyDown = function( e ) {
break; break;
// Backspace // Backspace
case 8: case 8:
tx = ve.dm.Transaction.newFromRemoval( this.documentView.model, this.model.getSelection() ); tx = ve.dm.Transaction.newFromRemoval( this.documentView.model, this.model.getSelection() );
ve.dm.TransactionProcessor.commit( this.documentView.model, tx ); ve.dm.TransactionProcessor.commit( this.documentView.model, tx );
this.showCursor(this.model.getSelection().start); this.showCursor(this.model.getSelection().start);
e.preventDefault(); e.preventDefault();
break; break;
// Delete // Delete
@ -111,7 +114,6 @@ ve.ce.Surface.prototype.onKeyDown = function( e ) {
ve.ce.Surface.prototype.onMouseDown = function( e ) { ve.ce.Surface.prototype.onMouseDown = function( e ) {
this.isMouseDown = true; this.isMouseDown = true;
// TODO: Add special handling for clicking on images and alien nodes // TODO: Add special handling for clicking on images and alien nodes
var $leaf = $( e.target ).closest( '.ve-ce-leafNode' ); var $leaf = $( e.target ).closest( '.ve-ce-leafNode' );
}; };

View file

@ -494,7 +494,7 @@ ve.dm.Document.prototype.getDataFromNode = function( node ) {
* *
* @method * @method
* @param {Integer} offset Offset to get annotations for * @param {Integer} offset Offset to get annotations for
* @returns {Object[]} A copy of all annotation objects offset is covered by * @returns {Object} A copy of all annotation objects offset is covered by
*/ */
ve.dm.Document.prototype.getAnnotationsFromOffset = function( offset ) { ve.dm.Document.prototype.getAnnotationsFromOffset = function( offset ) {
var annotations; var annotations;
@ -516,7 +516,7 @@ ve.dm.Document.prototype.getAnnotationsFromOffset = function( offset ) {
if ( ve.isPlainObject( annotations ) ) { if ( ve.isPlainObject( annotations ) ) {
//return ve.getObjectValues( annotations ); //return ve.getObjectValues( annotations );
return annotations; return ve.extendObject( {}, annotations );
} }
return {}; return {};
}; };
@ -642,99 +642,59 @@ ve.dm.Document.getMatchingAnnotations = function( annotations, pattern ) {
return matches; return matches;
}; };
/**
* Returns an annotation from annotations that match a regular expression.
*
* @static
* @method
* @param {Array} annotations Annotations to search through
* @param {RegExp} pattern Regular expression pattern to match with
* @returns {Object} Annotation object
*/
ve.dm.Document.getMatchingAnnotation = function( annotations, pattern ) {
if ( !( pattern instanceof RegExp ) ) {
throw 'Invalid Pattern. Pattern not instance of RegExp';
}
if ( ve.isPlainObject( annotations ) ) {
for ( var hash in annotations ) {
if ( pattern.test( annotations[hash].type ) ){
return annotations[hash];
}
}
}
return;
};
/**
* Quick check for annotation inside annotations object
*
* @static
* @method
* @param {Object} annotations Annotations to search through
* @param {Object} pattern Regular expression pattern to match with
* @returns {Boolean} if annotation in annotations object
*/
ve.dm.Document.annotationsContainAnnotation = function( annotations, annotation ) {
var contains = false;
$.each(annotations, function(i, val){
if ( ve.compareObjects(val, annotation) ) {
contains = true;
}
});
return contains;
};
/** /**
* Gets an array of common annnotations across a range. * Gets an array of common annnotations across a range.
* *
* @method * @method
* @param {Integer} offset Offset to get annotations for * @param {Integer} offset Offset to get annotations for
* @returns {Object[]} A copy of all annotation objects offset is covered by * @param {Boolean} [all] Get all annotations found within the range, not just those that cover it
* @returns {Object} A copy of all annotation objects offset is covered by
*/ */
ve.dm.Document.prototype.getAnnotationsFromRange = function( range ) { ve.dm.Document.prototype.getAnnotationsFromRange = function( range, all ) {
var currentChar = {},
annotations = {},
charCount = 0,
map = {};
range.normalize(); range.normalize();
var annotations = {},
count = 0,
left,
right,
hash;
// Shorcut for zero-length ranges
if ( range.getLength() === 0 ) { if ( range.getLength() === 0 ) {
return this.getAnnotationsFromOffset( range.to ); return {};
} }
// There's at least one character, get it's annotations
for ( var i = range.start; i < range.end; i++ ) { left = this.getAnnotationsFromOffset( range.start );
// skip non characters // Shorcut for single character ranges
if ( range.getLength() === 1 ) {
return left;
}
// Iterator over the range, looking for annotations, starting at the 2nd character
for ( var i = range.start + 1; i < range.end; i++ ) {
// Skip non character data
if ( ve.dm.Document.isElementData( this.data, i ) ) { if ( ve.dm.Document.isElementData( this.data, i ) ) {
continue; continue;
} }
//current character annotations // Current character annotations
currentChar = this.data[i][1]; right = this.getAnnotationsFromOffset( i );
// if a non annotated character, no commonality. if ( all && right !== undefined ) {
if ( currentChar === undefined ) { ve.extendObject( left, right );
return annotations; } else if ( !all ) {
} // A non annotated character indicates there's no full coverage
charCount++; if ( right === undefined ) {
// if current char annotations are not the same as previous char. return {};
if ( ve.compareObjects( map, currentChar ) === false) { }
//retain common annotations // Exclude annotations that are in left but not right
if ( charCount > 1 ) { for ( hash in left ) {
// look for annotation in map if ( right[hash] === undefined ) {
for ( var a in currentChar ) { delete left[hash];
if( map[a] === undefined ) {
delete currentChar[a];
}
} }
} }
// If we've reduced left down to nothing, just stop looking
if ( ve.isEmptyObject( left ) ) {
break;
}
} }
//save map
map = currentChar;
} }
// build array of annotations return left;
for ( var key in map ) {
annotations[key] = map[key];
}
return annotations;
}; };
/** /**

View file

@ -103,15 +103,6 @@ ve.dm.Surface.prototype.transact = function( transaction ) {
*/ */
ve.dm.Surface.prototype.annotate = function( method, annotation ) { ve.dm.Surface.prototype.annotate = function( method, annotation ) {
var selection = this.getSelection(); var selection = this.getSelection();
if ( method === 'toggle' ) {
var annotations = this.getDocument().getAnnotationsFromRange( selection );
if ( annotation in annotations ) {
method = 'clear';
} else {
method = 'set';
}
}
if ( this.selection.getLength() ) { if ( this.selection.getLength() ) {
var tx = ve.dm.Transaction.newFromAnnotation( var tx = ve.dm.Transaction.newFromAnnotation(
this.getDocument(), selection, method, annotation this.getDocument(), selection, method, annotation

View file

@ -23,11 +23,11 @@ ve.ui.LinkInspector = function( toolbar, context ) {
return; return;
} }
var surfaceModel = _this.context.getSurfaceView().getModel(), var surfaceModel = _this.context.getSurfaceView().getModel(),
annotation = _this.getSelectedLinkAnnotation(); annotations = _this.getSelectedLinkAnnotations();
// If link annotation exists, clear it. // If link annotation exists, clear it.
if ( annotation !== undefined ) { for ( var hash in annotations ) {
surfaceModel.annotate( 'clear', annotation ); surfaceModel.annotate( 'clear', annotations[hash] );
} }
_this.$locationInput.val( '' ); _this.$locationInput.val( '' );
@ -46,7 +46,7 @@ ve.ui.LinkInspector = function( toolbar, context ) {
/* Methods */ /* Methods */
ve.ui.LinkInspector.prototype.getSelectedLinkAnnotation = function(){ ve.ui.LinkInspector.prototype.getSelectedLinkAnnotations = function(){
var surfaceView = this.context.getSurfaceView(), var surfaceView = this.context.getSurfaceView(),
surfaceModel = surfaceView.getModel(), surfaceModel = surfaceView.getModel(),
documentModel = surfaceModel.getDocument(), documentModel = surfaceModel.getDocument(),
@ -54,9 +54,9 @@ ve.ui.LinkInspector.prototype.getSelectedLinkAnnotation = function(){
if ( data.length ) { if ( data.length ) {
if ( ve.isPlainObject( data[0][1] ) ) { if ( ve.isPlainObject( data[0][1] ) ) {
var annotation = ve.dm.Document.getMatchingAnnotation( data[0][1], /link\/.*/ ); var annotations = ve.dm.Document.getMatchingAnnotations( data[0][1], /link\/.*/ );
if ( ve.isPlainObject(annotation) ) { for ( var hash in annotations ) {
return annotation; return annotations[hash];
} }
} }
} }
@ -64,10 +64,12 @@ ve.ui.LinkInspector.prototype.getSelectedLinkAnnotation = function(){
}; };
ve.ui.LinkInspector.prototype.getTitleFromSelection = function() { ve.ui.LinkInspector.prototype.getTitleFromSelection = function() {
var annotation = this.getSelectedLinkAnnotation(); var annotations = this.getSelectedLinkAnnotations();
for ( var hash in annotations ) {
if ( annotation && annotation.data && annotation.data.title ) { // Use the first one that has a title (there should only be one, but this is just in case)
return annotation.data.title; if ( annotations[hash].data && annotations[hash].data.title ) {
return annotations[hash].data.title;
}
} }
return null; return null;
}; };
@ -96,11 +98,11 @@ ve.ui.LinkInspector.prototype.onClose = function( accept ) {
return; return;
} }
var surfaceModel = this.context.getSurfaceView().getModel(), var surfaceModel = this.context.getSurfaceView().getModel(),
annotation = this.getSelectedLinkAnnotation(); annotations = this.getSelectedLinkAnnotations();
// Clear link annotation if it exists // Clear link annotation if it exists
if ( annotation !== undefined ) { for ( var hash in annotations ) {
surfaceModel.annotate( 'clear', annotation ); surfaceModel.annotate( 'clear', annotations[hash] );
} }
surfaceModel.annotate( 'set', { 'type': 'link/wikiLink', 'data': { 'title': title } } ); surfaceModel.annotate( 'set', { 'type': 'link/wikiLink', 'data': { 'title': title } } );
} }

View file

@ -46,13 +46,16 @@ ve.ui.AnnotationButtonTool.prototype.onClick = function() {
}; };
ve.ui.AnnotationButtonTool.prototype.updateState = function( annotations, nodes ) { ve.ui.AnnotationButtonTool.prototype.updateState = function( annotations, nodes ) {
if ( ve.dm.Document.annotationsContainAnnotation(annotations, this.annotation) ) { var matches = ve.dm.Document.getMatchingAnnotations(
this.$.addClass( 'es-toolbarButtonTool-down' ); annotations, new RegExp( '^' + this.annotation.type + '$' )
this.active = true; );
return; if ( ve.isEmptyObject( matches ) ) {
this.$.removeClass( 'es-toolbarButtonTool-down' );
this.active = false;
} else {
this.$.addClass( 'es-toolbarButtonTool-down' );
this.active = true;
} }
this.$.removeClass( 'es-toolbarButtonTool-down' );
this.active = false;
}; };
/* Registration */ /* Registration */

View file

@ -18,7 +18,7 @@ ve.ui.ClearButtonTool = function( toolbar, name, title ) {
/* Methods */ /* Methods */
ve.ui.ClearButtonTool.prototype.getAnnotation = function(){ ve.ui.ClearButtonTool.prototype.getAnnotations = function(){
var surfaceView = this.toolbar.getSurfaceView(), var surfaceView = this.toolbar.getSurfaceView(),
surfaceModel = surfaceView.getModel(), surfaceModel = surfaceView.getModel(),
documentModel = surfaceModel.getDocument(), documentModel = surfaceModel.getDocument(),
@ -26,10 +26,7 @@ ve.ui.ClearButtonTool.prototype.getAnnotation = function(){
if ( data.length ) { if ( data.length ) {
if ( ve.isPlainObject( data[0][1] ) ) { if ( ve.isPlainObject( data[0][1] ) ) {
var annotation = ve.dm.Document.getMatchingAnnotation( data[0][1], this.pattern ); return ve.dm.Document.getMatchingAnnotations( data[0][1], this.pattern );
if ( ve.isPlainObject( annotation ) ) {
return annotation;
}
} }
} }
return ; return ;
@ -37,9 +34,11 @@ ve.ui.ClearButtonTool.prototype.getAnnotation = function(){
ve.ui.ClearButtonTool.prototype.onClick = function() { ve.ui.ClearButtonTool.prototype.onClick = function() {
var surfaceView = this.toolbar.getSurfaceView(), var surfaceView = this.toolbar.getSurfaceView(),
model = surfaceView.getModel(); model = surfaceView.getModel(),
annotations = this.getAnnotations();
model.annotate( 'clear', this.getAnnotation() ); for ( var hash in annotations ) {
model.annotate( 'clear', annotations[hash] );
}
surfaceView.showSelection( model.getSelection() ); surfaceView.showSelection( model.getSelection() );
surfaceView.contextView.closeInspector(); surfaceView.contextView.closeInspector();
}; };

View file

@ -32,27 +32,26 @@ ve.ui.Toolbar = function( $container, surfaceView, config ) {
/* Methods */ /* Methods */
ve.ui.Toolbar.prototype.updateTools = function( e ) { /**
var _this = this, * Triggers update events on all tools.
model = _this.surfaceView.getModel(), *
* @method
*/
ve.ui.Toolbar.prototype.updateTools = function() {
var model = this.surfaceView.getModel(),
doc = model.getDocument(), doc = model.getDocument(),
annotations, annotations,
nodes = [], nodes = [],
range = model.getSelection(),
startNode, startNode,
endNode; endNode;
// On transact: set e, and redraw selection if ( range !== null ) {
if ( e.from === undefined ) { if ( range.from === range.to ){
e = model.getSelection(); nodes.push( doc.getNodeFromOffset( range.from ) );
this.surfaceView.showSelection( e );
}
if( e !== null ) {
if ( e.from === e.to ){
nodes.push( doc.getNodeFromOffset( e.from ) );
} else { } else {
startNode = doc.getNodeFromOffset( e.from ); startNode = doc.getNodeFromOffset( range.from );
endNode = doc.getNodeFromOffset ( e.end ); endNode = doc.getNodeFromOffset ( range.end );
// These should be different, alas just in case. // These should be different, alas just in case.
if ( startNode === endNode ) { if ( startNode === endNode ) {
nodes.push( startNode ); nodes.push( startNode );
@ -67,22 +66,24 @@ ve.ui.Toolbar.prototype.updateTools = function( e ) {
} }
} }
// Update Context // Update Context
if ( e.getLength() > 0 ) { if ( range.getLength() > 0 ) {
_this.surfaceView.contextView.set(); this.surfaceView.contextView.set();
annotations = doc.getAnnotationsFromRange( range );
} else { } else {
_this.surfaceView.contextView.clear(); this.surfaceView.contextView.clear();
annotations = doc.getAnnotationsFromOffset(
doc.getNearestContentOffset( range.start - 1 )
);
} }
annotations = doc.getAnnotationsFromRange( e );
// Update state // Update state
for ( i = 0; i < _this.tools.length; i++ ) { for ( i = 0; i < this.tools.length; i++ ) {
_this.tools[i].updateState( annotations, nodes ); this.tools[i].updateState( annotations, nodes );
} }
} else { } else {
// Clear state // Clear state
_this.surfaceView.contextView.clear(); this.surfaceView.contextView.clear();
for ( i = 0; i < _this.tools.length; i++ ) { for ( i = 0; i < this.tools.length; i++ ) {
_this.tools[i].clearState(); this.tools[i].clearState();
} }
} }
}; };

View file

@ -205,12 +205,9 @@ test( 'getAnnotationsFromOffset', 1, function() {
} ); } );
test( 'getAnnotationsFromRange', 1, function() { test( 'getAnnotationsFromRange', 1, function() {
var doc, var cases = [
range,
annotations,
cases = [
{ {
'msg': 'all bold', 'msg': 'single annotations',
'data': [ 'data': [
['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ], ['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ],
['b', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ] ['b', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ]
@ -218,38 +215,41 @@ test( 'getAnnotationsFromRange', 1, function() {
'expected': { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } 'expected': { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } }
}, },
{ {
'msg': 'bold and italic', 'msg': 'mutliple annotations',
'data': [ 'data': [
['a', [
'a',
{ {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'} '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
} }
], ],
['b', [
'b',
{ {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'} '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
} }
] ]
], ],
'expected': 'expected': {
{ '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'} }
}
}, },
{ {
'msg': 'bold and italic', 'msg': 'lowest common coverage',
'data': [ 'data': [
['a', [
'a',
{ {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'} '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
} }
], ],
['b', [
'b',
{ {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}, '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'},
@ -257,22 +257,67 @@ test( 'getAnnotationsFromRange', 1, function() {
} }
] ]
], ],
'expected': 'expected': {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
}
},
{
'msg': 'no common coverage due to plain character at the start',
'data': [
['a'],
[
'b',
{
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'},
'{"type":"textStyle/underline"}': { 'type': 'textStyle/underline'}
}
],
[
'c',
{ {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'} '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
} }
]
],
'expected': {}
}, },
{ {
'msg': 'none common, non annotated character at end', 'msg': 'no common coverage due to plain character in the middle',
'data': [ 'data': [
['a', [
'a',
{
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'},
'{"type":"textStyle/underline"}': { 'type': 'textStyle/underline'}
}
],
['b'],
[
'c',
{
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
}
]
],
'expected': {}
},
{
'msg': 'no common coverage due to plain character at the end',
'data': [
[
'a',
{ {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'} '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
} }
], ],
['b', [
'b',
{ {
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' }, '{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}, '{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'},
@ -284,27 +329,7 @@ test( 'getAnnotationsFromRange', 1, function() {
'expected': {} 'expected': {}
}, },
{ {
'msg': 'none common, reverse of previous', 'msg': 'no common coverage due to mismatched annotations',
'data': [
['a'],
['b',
{
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'},
'{"type":"textStyle/underline"}': { 'type': 'textStyle/underline'}
}
],
['c',
{
'{"type":"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type":"textStyle/italic"}': { 'type': 'textStyle/italic'}
}
]
],
'expected': {}
},
{
'msg': 'all different',
'data': [ 'data': [
['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ], ['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ],
['b', { '{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' } } ] ['b', { '{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' } } ]
@ -312,22 +337,78 @@ test( 'getAnnotationsFromRange', 1, function() {
'expected': {} 'expected': {}
}, },
{ {
'msg': 'no annotations', 'msg': 'annotations are collected using all with mismatched annotations',
'data': [
['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ],
['b', { '{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' } } ]
],
'all': true,
'expected': {
'{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' }
}
},
{
'msg': 'annotations are collected using all, even with a plain character at the start',
'data': [
['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ],
['b', { '{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' } } ],
['c']
],
'all': true,
'expected': {
'{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' }
}
},
{
'msg': 'annotations are collected using all, even with a plain character at the middle',
'data': [
['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ],
['b', { '{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' } } ],
['c']
],
'all': true,
'expected': {
'{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' }
}
},
{
'msg': 'annotations are collected using all, even with a plain character at the end',
'data': [
['a', { '{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' } } ],
['b', { '{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' } } ],
['c']
],
'all': true,
'expected': {
'{"type:"textStyle/bold"}': { 'type': 'textStyle/bold' },
'{"type:"textStyle/italic"}': { 'type': 'textStyle/italic' }
}
},
{
'msg': 'no common coverage from all plain characters',
'data': ['a', 'b'], 'data': ['a', 'b'],
'expected': {} 'expected': {}
},
{
'msg': 'no common coverage using all from all plain characters',
'data': ['a', 'b'],
'all': true,
'expected': {}
} }
]; ];
expect( cases.length ); expect( cases.length );
for ( var i = 0; i < cases.length; i++ ) { for ( var i = 0; i < cases.length; i++ ) {
doc = new ve.dm.Document ( cases[i].data ); var doc = new ve.dm.Document ( cases[i].data );
range = new ve.Range( 0, doc.getData().length );
annotations = doc.getAnnotationsFromRange( range );
deepEqual( deepEqual(
annotations, cases[i].expected, cases[i].msg doc.getAnnotationsFromRange( new ve.Range( 0, cases[i].data.length ), cases[i].all ),
cases[i].expected,
cases[i].msg
); );
} }
} ); } );