mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-24 06:24:08 +00:00
* Moved getContent and getText from leaf nodes to document model nodes
* Renamed getContent to getContentData * Renamed getText to getContentText * Added getElementData
This commit is contained in:
parent
4bcc31846b
commit
07af0cab63
|
@ -34,50 +34,10 @@ es.DocumentModelLeafNode.prototype.getPlainObject = function() {
|
|||
if ( this.element && this.element.attributes ) {
|
||||
obj.attributes = es.copyObject( this.element.attributes );
|
||||
}
|
||||
obj.content = es.DocumentModel.getExpandedContentData( this.getContent() );
|
||||
obj.content = es.DocumentModel.getExpandedContentData( this.getContentData() );
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the content length.
|
||||
*
|
||||
* FIXME: This method makes assumptions that a node with a data property is a DocumentModel, which
|
||||
* may be an issue if sub-classes of DocumentModelLeafNode other than DocumentModel have a data property
|
||||
* as well. A safer way of determining this would be helpful in preventing future bugs.
|
||||
*
|
||||
* @method
|
||||
* @param {es.Range} [range] Range of content to get
|
||||
* @returns {Integer} Length of content
|
||||
*/
|
||||
es.DocumentModelLeafNode.prototype.getContent = function( range ) {
|
||||
// Find root
|
||||
var root = this.data ? this : ( this.root && this.root.data ? this.root : null );
|
||||
if ( root ) {
|
||||
return root.getContentFromNode( this, range );
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets plain text version of the content within a specific range.
|
||||
*
|
||||
* @method
|
||||
* @param {es.Range} [range] Range of text to get
|
||||
* @returns {String} Text within given range
|
||||
*/
|
||||
es.DocumentModelLeafNode.prototype.getText = function( range ) {
|
||||
var content = this.getContent( range );
|
||||
// Copy characters
|
||||
var text = '';
|
||||
for ( var i = 0, length = content.length; i < length; i++ ) {
|
||||
// If not using in IE6 or IE7 (which do not support array access for strings) use this..
|
||||
// text += this.data[i][0];
|
||||
// Otherwise use this...
|
||||
text += typeof content[i] === 'string' ? content[i] : content[i][0];
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
es.extendClass( es.DocumentModelLeafNode, es.DocumentLeafNode );
|
||||
|
|
|
@ -218,6 +218,71 @@ es.DocumentModelNode.prototype.getElementAttribute = function( key ) {
|
|||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets all element data, including the element opening, closing and it's contents.
|
||||
*
|
||||
* @method
|
||||
* @returns {Array} Element data
|
||||
*/
|
||||
es.DocumentModelNode.prototype.getElementData = function() {
|
||||
// Get reference to the document, which might be this node but otherwise should be this.root
|
||||
var root = this.type === 'document' ?
|
||||
this : ( this.root && this.root.type === 'document' ? this.root : null );
|
||||
if ( root ) {
|
||||
return root.getElementDataFromNode( this );
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets content data within a given range.
|
||||
*
|
||||
* @method
|
||||
* @param {es.Range} [range] Range of content to get
|
||||
* @returns {Array} Content data
|
||||
*/
|
||||
es.DocumentModelNode.prototype.getContentData = function( range ) {
|
||||
// Get reference to the document, which might be this node but otherwise should be this.root
|
||||
var root = this.type === 'document' ?
|
||||
this : ( this.root && this.root.type === 'document' ? this.root : null );
|
||||
if ( root ) {
|
||||
return root.getContentDataFromNode( this, range );
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets plain text version of the content within a specific range.
|
||||
*
|
||||
* Two newlines are inserted between leaf nodes.
|
||||
*
|
||||
* TODO: Maybe do something more adaptive with newlines
|
||||
*
|
||||
* @method
|
||||
* @param {es.Range} [range] Range of text to get
|
||||
* @returns {String} Text within given range
|
||||
*/
|
||||
es.DocumentModelNode.prototype.getContentText = function( range ) {
|
||||
var content = this.getContentData( range );
|
||||
// Copy characters
|
||||
var text = '',
|
||||
element = false;
|
||||
for ( var i = 0, length = content.length; i < length; i++ ) {
|
||||
if ( typeof content[i] === 'object' ) {
|
||||
if ( i ) {
|
||||
element = true;
|
||||
}
|
||||
} else {
|
||||
if ( element ) {
|
||||
text += '\n\n';
|
||||
element = false;
|
||||
}
|
||||
text += typeof content[i] === 'string' ? content[i] : content[i][0];
|
||||
}
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
/* Inheritance */
|
||||
|
||||
es.extendClass( es.DocumentModelNode, es.DocumentNode );
|
||||
|
|
|
@ -612,6 +612,21 @@ es.DocumentModel.prototype.getElementFromNode = function( node ) {
|
|||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the element data of a node.
|
||||
*
|
||||
* @method
|
||||
* @param {es.DocumentModelNode} node Node to get element data for
|
||||
*/
|
||||
es.DocumentModel.prototype.getContentDataFromNode = function( node ) {
|
||||
var length = node.getElementLength();
|
||||
var offset = this.getOffsetFromNode( node );
|
||||
if ( offset !== -1 ) {
|
||||
return this.data.slice( offset, offset + length );
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the content data of a node.
|
||||
*
|
||||
|
@ -619,7 +634,7 @@ es.DocumentModel.prototype.getElementFromNode = function( node ) {
|
|||
* @param {es.DocumentModelNode} node Node to get content data for
|
||||
* @returns {Array|null} List of content and elements inside node or null if node is not found
|
||||
*/
|
||||
es.DocumentModel.prototype.getContentFromNode = function( node, range ) {
|
||||
es.DocumentModel.prototype.getContentDataFromNode = function( node, range ) {
|
||||
var length = node.getContentLength();
|
||||
if ( range ) {
|
||||
range.normalize();
|
||||
|
@ -1201,7 +1216,7 @@ es.DocumentModel.prototype.prepareLeafConversion = function( range, type, attrib
|
|||
txs.push( this.prepareInsertion(
|
||||
nodeOffset,
|
||||
[ { 'type': type, 'attributes': attributes } ]
|
||||
.concat( nodes[i].getContent() )
|
||||
.concat( nodes[i].getContentData() )
|
||||
.concat( [ { 'type': '/' + type } ] )
|
||||
) );
|
||||
}
|
||||
|
|
|
@ -500,7 +500,7 @@ es.ContentView.prototype.scanBoundaries = function() {
|
|||
* the words.
|
||||
*/
|
||||
// Get and cache a copy of all content, the make a plain-text version of the cached content
|
||||
var data = this.contentCache = this.model.getContent(),
|
||||
var data = this.contentCache = this.model.getContentData(),
|
||||
text = '';
|
||||
for ( var i = 0, length = data.length; i < length; i++ ) {
|
||||
text += typeof data[i] === 'string' ? data[i] : data[i][0];
|
||||
|
@ -712,7 +712,7 @@ es.ContentView.prototype.appendLine = function( range, wordOffset, fractional )
|
|||
$line[0].innerHTML = this.getHtml( range );
|
||||
// Overwrite/append line information
|
||||
this.lines[rs.line] = {
|
||||
'text': this.model.getText( range ),
|
||||
'text': this.model.getContentText( range ),
|
||||
'range': range,
|
||||
'width': $line.outerWidth(),
|
||||
'height': $line.outerHeight(),
|
||||
|
|
|
@ -589,7 +589,7 @@ es.SurfaceView.prototype.handleDelete = function( backspace ) {
|
|||
this.model.transact( tx, true );
|
||||
} else {
|
||||
tx = this.model.getDocument().prepareInsertion(
|
||||
targetOffset, sourceNode.model.getContent()
|
||||
targetOffset, sourceNode.model.getContentData()
|
||||
);
|
||||
this.model.transact( tx, true );
|
||||
|
||||
|
|
|
@ -85,50 +85,50 @@ test( 'es.DocumentModel.getRelativeContentOffset', 7, function() {
|
|||
);
|
||||
} );
|
||||
|
||||
test( 'es.DocumentModel.getContent', 6, function() {
|
||||
test( 'es.DocumentModel.getContentData', 6, function() {
|
||||
var documentModel = es.DocumentModel.newFromPlainObject( esTest.obj ),
|
||||
childNodes = documentModel.getChildren();
|
||||
|
||||
// Test 1
|
||||
deepEqual(
|
||||
childNodes[0].getContent( new es.Range( 1, 3 ) ),
|
||||
childNodes[0].getContentData( new es.Range( 1, 3 ) ),
|
||||
[
|
||||
['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }],
|
||||
['c', { 'type': 'textStyle/italic', 'hash': '{"type":"textStyle/italic"}' }]
|
||||
],
|
||||
'getContent can return an ending portion of the content'
|
||||
'getContentData can return an ending portion of the content'
|
||||
);
|
||||
|
||||
// Test 2
|
||||
deepEqual(
|
||||
childNodes[0].getContent( new es.Range( 0, 2 ) ),
|
||||
childNodes[0].getContentData( new es.Range( 0, 2 ) ),
|
||||
['a', ['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }]],
|
||||
'getContent can return a beginning portion of the content'
|
||||
'getContentData can return a beginning portion of the content'
|
||||
);
|
||||
|
||||
// Test 3
|
||||
deepEqual(
|
||||
childNodes[0].getContent( new es.Range( 1, 2 ) ),
|
||||
childNodes[0].getContentData( new es.Range( 1, 2 ) ),
|
||||
[['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }]],
|
||||
'getContent can return a middle portion of the content'
|
||||
'getContentData can return a middle portion of the content'
|
||||
);
|
||||
|
||||
// Test 4
|
||||
try {
|
||||
childNodes[0].getContent( new es.Range( -1, 3 ) );
|
||||
childNodes[0].getContentData( new es.Range( -1, 3 ) );
|
||||
} catch ( negativeIndexError ) {
|
||||
ok( true, 'getContent throws exceptions when given a range with start < 0' );
|
||||
ok( true, 'getContentData throws exceptions when given a range with start < 0' );
|
||||
}
|
||||
|
||||
// Test 5
|
||||
try {
|
||||
childNodes[0].getContent( new es.Range( 0, 4 ) );
|
||||
childNodes[0].getContentData( new es.Range( 0, 4 ) );
|
||||
} catch ( outOfRangeError ) {
|
||||
ok( true, 'getContent throws exceptions when given a range with end > length' );
|
||||
ok( true, 'getContentData throws exceptions when given a range with end > length' );
|
||||
}
|
||||
|
||||
// Test 6
|
||||
deepEqual( childNodes[2].getContent(), ['h'], 'Content can be extracted from nodes' );
|
||||
deepEqual( childNodes[2].getContentData(), ['h'], 'Content can be extracted from nodes' );
|
||||
} );
|
||||
|
||||
test( 'es.DocumentModel.getIndexOfAnnotation', 3, function() {
|
||||
|
|
|
@ -94,7 +94,7 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 6
|
||||
deepEqual(
|
||||
documentModel.getChildren()[0].getContent(),
|
||||
documentModel.getChildren()[0].getContentData(),
|
||||
[
|
||||
'a',
|
||||
['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }],
|
||||
|
@ -120,7 +120,7 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 8
|
||||
deepEqual(
|
||||
documentModel.getChildren()[0].getContent(),
|
||||
documentModel.getChildren()[0].getContentData(),
|
||||
[
|
||||
'a',
|
||||
['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }],
|
||||
|
@ -145,7 +145,7 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 10
|
||||
deepEqual(
|
||||
documentModel.getChildren()[0].getContent(),
|
||||
documentModel.getChildren()[0].getContentData(),
|
||||
['a'],
|
||||
'commit keeps model tree up to date with removals'
|
||||
);
|
||||
|
@ -166,7 +166,7 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 12
|
||||
deepEqual(
|
||||
documentModel.getChildren()[0].getContent(),
|
||||
documentModel.getChildren()[0].getContentData(),
|
||||
[
|
||||
'a',
|
||||
['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }],
|
||||
|
@ -197,14 +197,14 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 14
|
||||
deepEqual(
|
||||
documentModel.getChildren()[0].getContent(),
|
||||
documentModel.getChildren()[0].getContentData(),
|
||||
['a'],
|
||||
'commit keeps model tree up to date with paragraph split (paragraph 1)'
|
||||
);
|
||||
|
||||
// Test 15
|
||||
deepEqual(
|
||||
documentModel.getChildren()[1].getContent(),
|
||||
documentModel.getChildren()[1].getContentData(),
|
||||
[
|
||||
['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }],
|
||||
['c', { 'type': 'textStyle/italic', 'hash': '{"type":"textStyle/italic"}' }]
|
||||
|
@ -228,7 +228,7 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 17
|
||||
deepEqual(
|
||||
documentModel.getChildren()[0].getContent(),
|
||||
documentModel.getChildren()[0].getContentData(),
|
||||
[
|
||||
'a',
|
||||
['b', { 'type': 'textStyle/bold', 'hash': '{"type":"textStyle/bold"}' }],
|
||||
|
@ -272,21 +272,21 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 21
|
||||
deepEqual(
|
||||
documentModel.children[1].children[0].children[0].children[1].children[0].children[0].getContent(),
|
||||
documentModel.children[1].children[0].children[0].children[1].children[0].children[0].getContentData(),
|
||||
[ 'f' ],
|
||||
'removal keeps model tree up to date with list item merge (first list item)'
|
||||
);
|
||||
|
||||
// Test 22
|
||||
deepEqual(
|
||||
documentModel.children[1].children[0].children[0].children[1].children[1].children[0].getContent(),
|
||||
documentModel.children[1].children[0].children[0].children[1].children[1].children[0].getContentData(),
|
||||
[ 'g' ],
|
||||
'removal keeps model tree up to date with list item merge (second list item)'
|
||||
);
|
||||
|
||||
// Test 23
|
||||
deepEqual(
|
||||
documentModel.children[2].getContent(),
|
||||
documentModel.children[2].getContentData(),
|
||||
[ 'h' ],
|
||||
'rollback keeps model tree up to date with list item split (final paragraph)'
|
||||
);
|
||||
|
@ -322,28 +322,28 @@ test( 'es.TransactionProcessor', 29, function() {
|
|||
|
||||
// Test 26
|
||||
deepEqual(
|
||||
documentModel.children[1].children[0].children[0].children[1].children[0].children[0].getContent(),
|
||||
documentModel.children[1].children[0].children[0].children[1].children[0].children[0].getContentData(),
|
||||
[ 'e' ],
|
||||
'rollback keeps model tree up to date with list item split (first list item)'
|
||||
);
|
||||
|
||||
// Test 27
|
||||
deepEqual(
|
||||
documentModel.children[1].children[0].children[0].children[1].children[1].children[0].getContent(),
|
||||
documentModel.children[1].children[0].children[0].children[1].children[1].children[0].getContentData(),
|
||||
[ 'f' ],
|
||||
'rollback keeps model tree up to date with list item split (second list item)'
|
||||
);
|
||||
|
||||
// Test 28
|
||||
deepEqual(
|
||||
documentModel.children[1].children[0].children[0].children[1].children[2].children[0].getContent(),
|
||||
documentModel.children[1].children[0].children[0].children[1].children[2].children[0].getContentData(),
|
||||
[ 'g' ],
|
||||
'rollback keeps model tree up to date with list item split (third list item)'
|
||||
);
|
||||
|
||||
// Test 29
|
||||
deepEqual(
|
||||
documentModel.children[2].getContent(),
|
||||
documentModel.children[2].getContentData(),
|
||||
[ 'h' ],
|
||||
'rollback keeps model tree up to date with list item split (final paragraph)'
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue