http://www.mediawiki.org/wiki/Special:Code/MediaWiki/100757
Revision: 100757 Author: catrope Date: 2011-10-25 22:28:57 +0000 (Tue, 25 Oct 2011) Log Message: ----------- Various fixes and refactoring in prepareInsertion(). Passes the tests now, but is still incomplete. We'll have to come up with new test cases that break it now Modified Paths: -------------- trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js Modified: trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js =================================================================== --- trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js 2011-10-25 22:18:33 UTC (rev 100756) +++ trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js 2011-10-25 22:28:57 UTC (rev 100757) @@ -580,7 +580,15 @@ * @returns {es.Transaction} */ es.DocumentModel.prototype.prepareInsertion = function( offset, data ) { - function containsStructuralElements( data ) { + /** + * Returns true if data starts with an opening element and ends with a closing element + */ + /*function isStructuralData( data ) { + return data.length >= 2 && + data[0].type !== undefined && data[0].type.charAt( 0 ) != '/' && + data[data.length - 1].type !== undefined && data[data.length - 1].type.charAt( 0 ) == '/'; + }*/ + function isStructuralData( data ) { var i; for ( i = 0; i < data.length; i++ ) { if ( data[i].type !== undefined ) { @@ -596,20 +604,76 @@ // * The end of the document (offset length-1) // * Any location between elements, i.e. the item before is a closing and the item after is an opening return offset <= 0 || offset >= data.length - 1 || ( - data[offset - 1].type !== undefined && data[offset - 1].type.charAt( 0 ) != '/' && - data[offset].type !== undefined && data[offset].type.charAt( 0 ) == '/' + data[offset - 1].type !== undefined && data[offset - 1].type.charAt( 0 ) == '/' && + data[offset].type !== undefined && data[offset].type.charAt( 0 ) != '/' ); } + + /** + * Balances mismatched openings/closings in data + * @return data itself if nothing was changed, or a clone of data with balancing changes made. data itself is never touched + */ + function balance( data ) { + var i, stack = [], element, workingData = null; + + for ( i = 0; i < data.length; i++ ) { + if ( data[i].type === undefined ) { + // Not an opening or a closing, skip + } else if ( data[i].type.charAt( 0 ) != '/' ) { + // Opening + stack.push( data[i].type ); + } else { + // Closing + if ( stack.length == 0 ) { + // The stack is empty, so this is an unopened closing + // Remove it + if ( workingData === null ) { + workingData = data.slice( 0 ); + } + workingData.splice( i, 1 ); + } + + element = stack.pop(); + if ( element != data[i].type.substr( 1 ) ) { + // Closing doesn't match what's expected + // This means the input is malformed and cannot possibly + // have been a fragment taken from well-formed data + throw 'Input is malformed: expected /' + element + ' but got ' + data[i].type + ' at index ' + i; + } + } + } + + // Check whether there are any unclosed tags and close them + if ( stack.length > 0 && workingData === null ) { + workingData = data.slice( 0 ); + } + while ( stack.length > 0 ) { + element = stack.pop(); + workingData.push( { 'type': '/' + element } ); + } + + // TODO + // Check whether there is any raw unenclosed content and deal with that somehow + + return workingData || data; + } - var tx = new es.Transaction(), insertedData = data; + var tx = new es.Transaction(), + insertedData = data, // may be cloned and modified + isStructuralLoc = isStructuralLocation( offset, this.data ); + if ( offset > 0 ) { tx.pushRetain( offset ); } - // TODO check for structural changes - if ( containsStructuralElements( insertedData ) ) { - // TODO + + if ( isStructuralData( insertedData ) ) { + if ( isStructuralLoc ) { + insertedData = balance( insertedData ); + } else { + // TODO close and reopen the element the insertion point is in + } } else { - if ( isStructuralLocation( offset, this.data ) ) { + if ( isStructuralLoc ) { // We're inserting content into a structural location, // so we need to wrap the inserted content in a paragraph. insertedData = [ { 'type': 'paragraph' }, { 'type': '/paragraph' } ]; _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs