r100826 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r100825‎ | r100826 | r100827 >
Date:16:57, 26 October 2011
Author:tparscal
Status:deferred
Tags:
Comment:
Refactored data type checking functionality into static methods of es.DocumentModel
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
@@ -39,37 +39,22 @@
4040 * Each function is called in the context of a state, and takes an operation object as a parameter.
4141 */
4242 es.DocumentModel.operations = ( function() {
43 - function containsElements( op ) {
44 - for ( i = 0; i < op.data.length; i++ ) {
45 - if ( op.data.type !== undefined ) {
46 - return true;
47 - }
48 - }
49 - return false;
 43+ function invalidate( from, to ) {
 44+ this.rebuild.push( { 'from': from, 'to': to } );
5045 }
5146
52 - function isStructural( offset ) {
53 - var edge = offset === 0 || offset === this.data.length - 1,
54 - elementLeft = this.data[offset - 1].type !== undefined,
55 - elementRight = this.data[offset].type !== undefined;
56 - if ( edge || ( elementLeft && elementRight ) ) {
57 - return true;
58 - }
59 - return false;
60 - }
61 -
6247 function retain( op ) {
6348 annotate.call( this, this.cursor + op.length );
6449 this.cursor += op.length;
6550 }
6651
6752 function insert( op ) {
68 - if ( isStructural( this.cursor ) ) {
 53+ if ( es.DocumentModel.isStructuralOffset( this.data, this.cursor ) ) {
6954 // TODO: Support tree updates when inserting between elements
7055 } else {
7156 // Get the node we are about to insert into
7257 var node = this.tree.getNodeFromOffset( this.cursor );
73 - if ( containsElements( op ) ) {
 58+ if ( es.DocumentModel.containsElementData( op.data ) ) {
7459 var nodeParent = node.getParent();
7560 if ( !nodeParent ) {
7661 throw 'Missing parent error. Node does not have a parent node.';
@@ -105,10 +90,12 @@
10691 }
10792
10893 function remove( op ) {
109 - if ( isStructural( this.cursor ) && isStructural( this.cursor + op.data.length ) ) {
 94+ var elementLeft = es.DocumentModel.isElementOffset( this.data, this.cursor ),
 95+ elementRight = es.DocumentModel.isElementOffset( this.cursor + op.data.length );
 96+ if ( elementLeft && elementRight ) {
11097 // TODO: Support tree updates when removing whole elements
11198 } else {
112 - if ( containsElements( op ) ) {
 99+ if ( es.DocumentModel.containsElementData( op.data ) ) {
113100 // TODO: Support tree updates when removing partial elements
114101 } else {
115102 // Get the node we are removing content from
@@ -470,34 +457,108 @@
471458 return data;
472459 };
473460
474 -/* Methods */
475 -
476461 /**
477462 * Checks if a data at a given offset is content.
478463 *
 464+ * Content offsets are those which are between an opening and a closing element.
 465+ *
 466+ * @example Content offsets:
 467+ * <paragraph> a b c </paragraph> <list> <listItem> d e f </listItem> </list>
 468+ * ^ ^ ^ ^ ^ ^
 469+ *
479470 * @static
480471 * @method
 472+ * @param {Array} data Data to evaluate offset within
481473 * @param {Integer} offset Offset in data to check
482474 * @returns {Boolean} If data at offset is content
483475 */
484 -es.DocumentModel.prototype.isContent = function( offset ) {
485 - return typeof this.data[offset] === 'string' || $.isArray( this.data[offset] );
 476+es.DocumentModel.isContentOffset = function( data, offset ) {
 477+ // Content can't exist at the edges
 478+ if ( offset > 0 && offset < data.length - 1 ) {
 479+ // Shortcut: if there's already content there, we will trust it's supposed to be there
 480+ if ( typeof data[offset] === 'string' || $.isArray( data[offset] ) ) {
 481+ return true;
 482+ }
 483+ // Empty elements will have an opening and a closing next to each other
 484+ var openLeft = data[offset - 1].type !== undefined && data[offset - 1].type[0] !== '/',
 485+ closeRight = data[offset].type !== undefined && data[offset].type[0] !== '/';
 486+ // Check that there's an opening and a closing on the left and right, and the types match
 487+ if ( openLeft && closeRight && ('/' + data[offset - 1].type === data[offset].type ) ) {
 488+ return true;
 489+ }
 490+ }
 491+ return false;
486492 };
487493
488494 /**
489495 * Checks if a data at a given offset is an element.
490496 *
 497+ * Element offsets are those at which an element is present.
 498+ *
 499+ * @example Element offsets:
 500+ * <paragraph> a b c </paragraph> <list> <listItem> d e f </listItem> </list>
 501+ * ^ ^ ^ ^ ^ ^
 502+ *
491503 * @static
492504 * @method
 505+ * @param {Array} data Data to evaluate offset within
493506 * @param {Integer} offset Offset in data to check
494507 * @returns {Boolean} If data at offset is an element
495508 */
496 -es.DocumentModel.prototype.isElement = function( offset ) {
 509+es.DocumentModel.isElementOffset = function( data, offset ) {
497510 // TODO: Is there a safer way to check if it's a plain object without sacrificing speed?
498 - return this.data[offset].type !== undefined;
 511+ return offset >= 0 && offset < data.length && data[offset].type !== undefined;
499512 };
500513
501514 /**
 515+ * Checks if an offset within given data is structural.
 516+ *
 517+ * Structural offsets are those at the beginning, end or surrounded by elements. This differs
 518+ * from a location at which an element is present in that elements can be safely inserted at a
 519+ * structural location, but not nessecarily where an element is present.
 520+ *
 521+ * @example Structural offsets:
 522+ * <paragraph> a b c </paragraph> <list> <listItem> d e f </listItem> </list>
 523+ * ^ ^ ^ ^ ^
 524+ *
 525+ * @static
 526+ * @method
 527+ * @param {Array} data Data to evaluate offset within
 528+ * @param {Integer} offset Offset to check
 529+ * @returns {Boolean} Whether offset is structural or not
 530+ */
 531+es.DocumentModel.isStructuralOffset = function( data, offset ) {
 532+ // Edges are always structural
 533+ if ( offset === 0 || offset === data.length - 1 ) {
 534+ return true;
 535+ }
 536+ // Structual offsets will have elements on each side
 537+ if ( data[offset - 1].type !== undefined && data[offset].type !== undefined ) {
 538+ return true;
 539+ }
 540+ return false;
 541+};
 542+
 543+/**
 544+ * Checks if elements are present within data.
 545+ *
 546+ * @static
 547+ * @method
 548+ * @param {Array} data Data to look for elements within
 549+ * @returns {Boolean} If elements exist in data
 550+ */
 551+es.DocumentModel.containsElementData = function( data ) {
 552+ for ( var i = 0, length = data.length; i < length; i++ ) {
 553+ if ( data[i].type !== undefined ) {
 554+ return true;
 555+ }
 556+ }
 557+ return false;
 558+};
 559+
 560+/* Methods */
 561+
 562+/**
502563 * Creates a document view for this model.
503564 *
504565 * @method
@@ -653,37 +714,6 @@
654715 */
655716 es.DocumentModel.prototype.prepareInsertion = function( offset, data ) {
656717 /**
657 - * Returns true if data starts with an opening element and ends with a closing element
658 - */
659 - /*function isStructuralData( data ) {
660 - return data.length >= 2 &&
661 - data[0].type !== undefined && data[0].type.charAt( 0 ) != '/' &&
662 - data[data.length - 1].type !==
663 - undefined && data[data.length - 1].type.charAt( 0 ) == '/';
664 - }*/
665 - function isStructuralData( data ) {
666 - var i;
667 - for ( i = 0; i < data.length; i++ ) {
668 - if ( data[i].type !== undefined ) {
669 - return true;
670 - }
671 - }
672 - return false;
673 - }
674 -
675 - function isStructuralLocation( offset, data ) {
676 - // The following are structural locations:
677 - // * The beginning of the document (offset 0)
678 - // * The end of the document (offset length-1)
679 - // * Any location between elements, i.e. the item before is a closing and the item after is
680 - // * an opening
681 - return offset <= 0 || offset >= data.length - 1 || (
682 - data[offset - 1].type !== undefined && data[offset - 1].type.charAt( 0 ) == '/' &&
683 - data[offset].type !== undefined && data[offset].type.charAt( 0 ) != '/'
684 - );
685 - }
686 -
687 - /**
688718 * Balances mismatched openings/closings in data
689719 * @return data itself if nothing was changed, or a clone of data with balancing changes made.
690720 * data itself is never touched
@@ -699,7 +729,7 @@
700730 stack.push( data[i].type );
701731 } else {
702732 // Closing
703 - if ( stack.length == 0 ) {
 733+ if ( stack.length === 0 ) {
704734 // The stack is empty, so this is an unopened closing
705735 // Remove it
706736 if ( workingData === null ) {
@@ -736,13 +766,13 @@
737767
738768 var tx = new es.Transaction(),
739769 insertedData = data, // may be cloned and modified
740 - isStructuralLoc = isStructuralLocation( offset, this.data );
 770+ isStructuralLoc = es.DocumentModel.isStructuralOffset( this.data, offset );
741771
742772 if ( offset > 0 ) {
743773 tx.pushRetain( offset );
744774 }
745775
746 - if ( isStructuralData( insertedData ) ) {
 776+ if ( es.DocumentModel.containsElementData( insertedData ) ) {
747777 if ( isStructuralLoc ) {
748778 insertedData = balance( insertedData );
749779 } else {
@@ -1002,7 +1032,8 @@
10031033 'tree': this,
10041034 'cursor': 0,
10051035 'set': [],
1006 - 'clear': []
 1036+ 'clear': [],
 1037+ 'rebuild': []
10071038 };
10081039 for ( var i = 0, length = transaction.length; i < length; i++ ) {
10091040 var operation = transaction[i];
@@ -1027,7 +1058,8 @@
10281059 'tree': this,
10291060 'cursor': 0,
10301061 'set': [],
1031 - 'clear': []
 1062+ 'clear': [],
 1063+ 'rebuild': []
10321064 };
10331065 for ( var i = 0, length = transaction.length; i < length; i++ ) {
10341066 var operation = transaction[i];

Status & tagging log