Rewrite data model methods needed for ui tools

getAnnotationRangeFromOffset and offsetContainsAnnotation
which deprecated getAnnotationBoundaries, and getIndexOfAnnotation
write unit tests for proof

Change-Id: I6c0d4e3ca96dd569b1909cd22fce68c3a6fe382c
This commit is contained in:
Rob Moen 2012-05-16 15:55:01 -07:00
parent eefbee2262
commit fbaea888b9
2 changed files with 147 additions and 0 deletions

View file

@ -198,6 +198,54 @@ ve.dm.DocumentFragment.prototype.getAnnotationsFromOffset = function( offset ) {
return [];
};
/**
* Does this offset contain the specified annotation
*
* @method
* @param {Integer} offset Offset to look at
* @param {Object} annotation Object to look for
* @returns {Boolean} Whether an offset contains the specified annotation
*/
ve.dm.DocumentFragment.prototype.offsetContainsAnnotation = function ( offset, annotation ) {
var annotations = this.getAnnotationsFromOffset( offset );
for (var i=0;i<annotations.length;i++){
if (ve.compareObjects(annotations[i], annotation)){
return true;
}
}
return false;
};
/**
* Gets the range of content surrounding a given offset that's covered by a given annotation.
*
* @param {Integer} offset Offset to begin looking forward and backward from
* @param {Object} annotation Annotation to test for coverage with
* @returns {ve.Range|null} Range of content covered by annotation, or null if offset is not covered
*/
ve.dm.DocumentFragment.prototype.getAnnotationRangeFromOffset = function ( offset, annotation ) {
var start = offset,
end = offset;
if ( this.offsetContainsAnnotation(offset, annotation) === false ) {
return null;
}
while ( start > 0 ) {
start--;
if ( this.offsetContainsAnnotation(start, annotation ) === false ) {
start++;
break;
}
}
while ( end < this.data.length ) {
end++;
if ( this.offsetContainsAnnotation(end, annotation ) === false ) {
end--;
break;
}
}
return new ve.Range( start, end );
};
/**
* Gets an array of common annnotations across a range.
*

View file

@ -310,3 +310,102 @@ test( 'getAnnotationsFromRange', 1, function() {
});
test( 'offsetContainsAnnotation', 1, function(){
var cases = [
{
msg: 'contains no annotations',
data: [
['a']
],
lookFor: {'type': 'bold'},
expected: false
},
{
msg: 'contains bold',
data: [
['a', { '{"type:"bold"}': { 'type': 'bold' } } ]
],
lookFor: {'type': 'bold'},
expected: true
},
{
msg: 'contains bold',
data: [
['a', {
'{"type:"bold"}': { 'type': 'bold' },
'{"type":"italic"}': { 'type': 'italic'}
}
]
],
lookFor: {'type': 'bold'},
expected: true
}
],
fragment;
expect( cases.length );
for( var i=0;i<cases.length;i++) {
fragment = new ve.dm.DocumentFragment( cases[i].data );
deepEqual(
fragment.offsetContainsAnnotation(0, cases[i].lookFor),
cases[i].expected,
cases[i].msg
);
}
});
test( 'getAnnotationRangeFromOffset', 1, function(){
var cases = [
{
msg: 'a bold word',
data: [
['a'], //0
['b', { '{"type:"bold"}': { 'type': 'bold' } } ], //1
['o', { '{"type:"bold"}': { 'type': 'bold' } } ], //2
['l', { '{"type:"bold"}': { 'type': 'bold' } } ], //3
['d', { '{"type:"bold"}': { 'type': 'bold' } } ], //4
['w'], //5
['o'], //6
['r'], //7
['d'] //8
],
annotation: { 'type': 'bold' },
offset: 3,
expected: new ve.Range( 1, 4 )
},
{
msg: 'a linked',
data: [
['x'], //0
['x'], //1
['x'], //2
['l', { '{"type:"link/internal"}': { 'type': 'link/internal' } } ], //3
['i', { '{"type:"link/internal"}': { 'type': 'link/internal' } } ], //4
['n', { '{"type:"link/internal"}': { 'type': 'link/internal' } } ], //5
['k', { '{"type:"link/internal"}': { 'type': 'link/internal' } } ], //6
['x'], //7
['x'], //8
['x'] //9
],
annotation: { 'type': 'link/internal' },
offset: 3,
expected: new ve.Range( 3, 6 )
}
],
fragment;
expect( cases.length );
for( var i=0;i<cases.length;i++) {
fragment = new ve.dm.DocumentFragment( cases[i].data );
deepEqual(
fragment.getAnnotationRangeFromOffset(cases[i].offset, cases[i].annotation),
cases[i].expected,
cases[i].msg
);
}
});