r100039 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r100038‎ | r100039 | r100040 >
Date:15:34, 17 October 2011
Author:neilk
Status:deferred (Comments)
Tags:
Comment:
more removal tests pass
Modified paths:
  • /trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js (modified) (history)

Diff [purge]

Index: trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js
@@ -613,53 +613,99 @@
614614 * @returns {es.Transaction}
615615 */
616616 es.DocumentModel.prototype.prepareRemoval = function( range ) {
617 - var tx = new es.Transaction(), removed = [];
 617+ var doc = this;
 618+ debugger;
 619+
 620+ /**
 621+ * Return true if can merge the remaining contents of the elements after a selection is deleted across them.
 622+ * For instance, if a selection is painted across two paragraphs, and then the text is deleted, the two paragraphs can become one paragraph.
 623+ * However, if the selection crosses into a table, those cannot be merged.
 624+ * @param {Number} integer offset
 625+ * @param {Number} integer offset
 626+ * @return {Boolean}
 627+ */
 628+ function canMerge( range ) {
 629+ var node1 = doc.getNodeFromOffset( range.start );
 630+ var node2 = doc.getNodeFromOffset( range.end - 1 );
 631+ // This is the simple rule we are following for now -- same type & same parent = can merge. So you can merge adjacent paragraphs, or listitems.
 632+ // And you can't merge a paragraph into a table row.
 633+ // There may be other rules we will want in here later, for instance, special casing merging a listitem into a paragraph.
 634+
 635+ // wait, some nodes don't have types? Is this the top document node?
 636+ return (
 637+ (
 638+ ( node1.type !== undefined && node2.type !== undefined )
 639+ &&
 640+ ( node1.type === node2.type )
 641+ )
 642+ &&
 643+ ( node1.getParent() === node2.getParent() )
 644+ );
 645+ }
 646+
 647+ function mergeDelete( range, tx ) {
 648+ // yay, content can be removed in one fell swoop
 649+ var removed = doc.data.slice( range.start, range.end );
 650+ tx.pushRemove( removed );
 651+ }
 652+
 653+ // remove string content only, retain structure
 654+ function stripDelete( range, tx ) {
 655+ var lastOperation, operationStart;
 656+
 657+ var ops = [];
 658+ debugger;
 659+
 660+ // get a list of operations, with 0-based indexes
 661+ for (var i = range.start; i < range.end; i++ ) {
 662+ var neededOp = doc.data[i].type === undefined ? 'remove' : 'retain';
 663+ var op = ops[ ops.length - 1 ];
 664+ if ( op === undefined || op.type !== neededOp ) {
 665+ ops.push( { type: neededOp, start: i, end: i } );
 666+ } else {
 667+ op.end = i;
 668+ }
 669+ }
 670+
 671+ debugger;
 672+ // insert operations as transactions (end must be adjusted)
 673+ for (var j = 0; j < ops.length; j++ ) {
 674+ var op = ops[j];
 675+ if ( op.type === 'retain' ) {
 676+ // we add one because retain(3,3) really means retain 1 char at pos 3
 677+ tx.pushRetain( op.end - op.start + 1 );
 678+ } else if ( op.type === 'remove' ) {
 679+ // we add one because to remove(3,5) we need to slice(3,6), the ending is last subscript removed + 1.
 680+ tx.pushRemove( this.data.slice( op.start, op.end + 1 ) );
 681+ } else {
 682+ console.log( "this is impossible" );
 683+ }
 684+ }
 685+
 686+ }
 687+
 688+
 689+ var tx = new es.Transaction();
618690 range.normalize();
619691
620692 // Retain to the start of the range
621693 if ( range.start > 0 ) {
622694 tx.pushRetain( range.start );
623695 }
624 - // TODO check for overlaps with structured elements and compensate
 696+
625697
626 - removed = this.data.slice( range.start, range.end );
627 - tx.pushRemove( removed );
628 -
629 - // Retain up to the end of the document
630 - if ( range.end < this.data.length ) {
631 - tx.pushRetain( this.data.length - range.end );
 698+ // choose a deletion strategy; merging nodes together, or stripping content from existing structure.
 699+ if ( canMerge( range ) ) {
 700+ mergeDelete( range, tx );
 701+ } else {
 702+ stripDelete( range, tx );
632703 }
633 -
634 - /*
635 - * Loop to detect structural changes:
636 - while ( i < range.end ) {
637 - var data = this.data[i];
638 - if ( data.type !== undefined ) {
639 - console.log( "later" );
640 - // TODO structural
641 - } else {
642 - removeData.push( this.data[i] );
643 - }
644 - i++;
645 - }
646 - */
647704
648 - /*
649 - * // Structural changes
650 - * if ( The range spans structural elements ) {
651 - * if ( The range partially overlaps structural elements ) {
652 - * Add insertions to replace removed openings and closing to overlapped elements
653 - * } else {
654 - * Removing entire structural elements is OK, do nothing
655 - * }
656 - * } else {
657 - * Removing only content is OK, do nothing
658 - * }
659 - /
660 - i++;
 705+ // Retain up to the end of the document. Why do we do this?
 706+ if ( range.end < doc.data.length ) {
 707+ tx.pushRetain( doc.data.length - range.end );
661708 }
662 - */
663 -
 709+
664710 return tx;
665711 };
666712

Comments

#Comment by Catrope (talk | contribs)   16:58, 25 October 2011
+		return ( 
+					( 
+						( node1.type !== undefined && node2.type !== undefined ) 
+							&& 
+						( node1.type === node2.type ) 
+					) 
+						&&
+					( node1.getParent() === node2.getParent() )
+				);

The use of parentheses here seems excessive given that && is associative and you're not using any other logical operators.

#Comment by NeilK (talk | contribs)   18:51, 25 October 2011

Agreed. I think the logic is going to get simpler as I continue to work on this. Or at least, I hope.

Status & tagging log