jenkins-bot has submitted this change and it was merged.

Change subject: Calculate slug positions in the model
......................................................................


Calculate slug positions in the model

Change-Id: I4c5cb277facd29d6a69aac95e5bcff5d56bee89a
---
M src/ce/ve.ce.BranchNode.js
M src/ce/ve.ce.Document.js
M src/dm/ve.dm.BranchNode.js
M src/dm/ve.dm.Node.js
4 files changed, 89 insertions(+), 61 deletions(-)

Approvals:
  Catrope: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/src/ce/ve.ce.BranchNode.js b/src/ce/ve.ce.BranchNode.js
index 6884f85..e0e510d 100644
--- a/src/ce/ve.ce.BranchNode.js
+++ b/src/ce/ve.ce.BranchNode.js
@@ -27,7 +27,7 @@
 
        // Properties
        this.tagName = this.$element.get( 0 ).nodeName.toLowerCase();
-       this.slugs = {};
+       this.slugNodes = {};
 
        // Events
        this.model.connect( this, { splice: 'onSplice' } );
@@ -58,11 +58,12 @@
  * TODO: Make iframe safe
  *
  * @static
- * @property {jQuery}
+ * @property {HTMLElement}
  */
-ve.ce.BranchNode.$inlineSlugTemplate = $( '<span>' )
+ve.ce.BranchNode.inlineSlugTemplate = $( '<span>' )
        .addClass( 've-ce-branchNode-slug ve-ce-branchNode-inlineSlug' )
-       .html( '&#xFEFF;' );
+       .html( '&#xFEFF;' )
+       .get( 0 );
 
 /**
  * Block slug template.
@@ -70,15 +71,16 @@
  * TODO: Make iframe safe
  *
  * @static
- * @property {jQuery}
+ * @property {HTMLElement}
  */
-ve.ce.BranchNode.$blockSlugTemplate = $( '<div>' )
+ve.ce.BranchNode.blockSlugTemplate = $( '<div>' )
        .addClass( 've-ce-branchNode-blockSlugWrapper 
ve-ce-branchNode-blockSlugWrapper-unfocused' )
        .append(
                $( '<p>' )
                        .addClass( 've-ce-branchNode-slug 
ve-ce-branchNode-blockSlug' )
                        .html( '&#xFEFF;' )
-       );
+       )
+       .get( 0 );
 
 /* Methods */
 
@@ -213,66 +215,28 @@
  * @method
  */
 ve.ce.BranchNode.prototype.setupSlugs = function () {
-       var key, slug, i, len, first, last,
+       var i, slugTemplate, slugNode,
                isBlock = this.canHaveChildrenNotContent(),
                doc = this.getElementDocument();
 
-       function canContainParagraph( node ) {
-               var childTypes = node.getChildNodeTypes();
-               return childTypes === null || ve.indexOf( 'paragraph', 
childTypes ) !== -1;
-       }
-
        // Remove all slugs in this branch
-       for ( key in this.slugs ) {
-               if ( this.slugs[key].parentNode ) {
-                       this.slugs[key].parentNode.removeChild( this.slugs[key] 
);
+       for ( i in this.slugNodes ) {
+               if ( this.slugNodes[i].parentNode ) {
+                       this.slugNodes[i].parentNode.removeChild( 
this.slugNodes[i] );
                }
-               delete this.slugs[key];
+               delete this.slugNodes[i];
        }
 
-       if ( isBlock ) {
-               if ( !canContainParagraph( this ) ) {
-                       // Don't put slugs in nodes which can't contain 
paragraphs
-                       return;
-               }
-               slug = ve.ce.BranchNode.$blockSlugTemplate[0];
-       } else {
-               slug = ve.ce.BranchNode.$inlineSlugTemplate[0];
-       }
+       slugTemplate = isBlock ? ve.ce.BranchNode.blockSlugTemplate : 
ve.ce.BranchNode.inlineSlugTemplate;
 
-       // If this content branch no longer has any rendered children, insert a 
slug to keep the node
-       // from becoming invisible/unfocusable. In Firefox, backspace after 
Ctrl-A leaves the document
-       // completely empty, so this ensures DocumentNode gets a slug.
-       // Can't use this.getLength() because the internal list adds to the 
length but doesn't render.
-       if ( this.$element.contents().length === 0 ) {
-               this.slugs[0] = doc.importNode( slug, true );
-               this.$element[0].appendChild( this.slugs[0] );
-       } else {
-               // Iterate over all children of this branch and add slugs in 
appropriate places
-               for ( i = 0, len = this.children.length; i < len; i++ ) {
-                       // Don't put slugs after internal nodes
-                       if ( ve.dm.nodeFactory.isNodeInternal( 
this.children[i].model.type ) ) {
-                               continue;
-                       }
-                       // First sluggable child (left side)
-                       if ( i === 0 && 
this.children[i].getModel().canHaveSlugBefore() ) {
-                               this.slugs[i] = doc.importNode( slug, true );
-                               first = this.children[i].$element[0];
-                               first.parentNode.insertBefore( this.slugs[i], 
first );
-                       }
-                       if ( this.children[i].getModel().canHaveSlugAfter() ) {
-                               if (
-                                       // Last sluggable child (right side)
-                                       i === this.children.length - 1 ||
-                                       // Sluggable child followed by another 
sluggable child (in between)
-                                       ( this.children[i + 1] && 
this.children[i + 1].getModel().canHaveSlugBefore() )
-                               ) {
-                                       this.slugs[i + 1] = doc.importNode( 
slug, true );
-                                       last = 
this.children[i].$element[this.children[i].$element.length - 1];
-                                       last.parentNode.insertBefore( 
this.slugs[i + 1], last.nextSibling );
-                               }
-                       }
+       for ( i in this.getModel().slugPositions ) {
+               slugNode = doc.importNode( slugTemplate, true );
+               if ( this.children[i] ) {
+                       this.$element[0].insertBefore( slugNode, 
this.children[i].$element[0] );
+               } else {
+                       this.$element[0].appendChild( slugNode );
                }
+               this.slugNodes[i] = slugNode;
        }
 };
 
@@ -288,12 +252,12 @@
                startOffset = this.model.getOffset() + ( this.isWrapped() ? 1 : 
0 );
 
        if ( offset === startOffset ) {
-               return this.slugs[0] || null;
+               return this.slugNodes[0] || null;
        }
        for ( i = 0; i < this.children.length; i++ ) {
                startOffset += this.children[i].model.getOuterLength();
                if ( offset === startOffset ) {
-                       return this.slugs[i + 1] || null;
+                       return this.slugNodes[i + 1] || null;
                }
        }
 };
diff --git a/src/ce/ve.ce.Document.js b/src/ce/ve.ce.Document.js
index 65ab884..566a1bf 100644
--- a/src/ce/ve.ce.Document.js
+++ b/src/ce/ve.ce.Document.js
@@ -52,7 +52,7 @@
 };
 
 /**
- * Get a slug a an offset.
+ * Get a slug at an offset.
  *
  * @method
  * @param {number} offset Offset to get slug at
diff --git a/src/dm/ve.dm.BranchNode.js b/src/dm/ve.dm.BranchNode.js
index 42d1fc1..c6f3932 100644
--- a/src/dm/ve.dm.BranchNode.js
+++ b/src/dm/ve.dm.BranchNode.js
@@ -25,6 +25,9 @@
        // Parent constructor
        ve.dm.Node.call( this, element );
 
+       // Properties
+       this.slugPositions = {};
+
        // TODO: children is only ever used in tests
        if ( ve.isArray( children ) && children.length ) {
                this.splice.apply( this, [0, 0].concat( children ) );
@@ -143,6 +146,57 @@
        }
 
        this.adjustLength( diff, true );
+       this.setupSlugs();
        this.emit.apply( this, ['splice'].concat( args ) );
+
        return removals;
 };
+
+/**
+ * Setup a sparse array of booleans indicating where to place slugs
+ */
+ve.dm.BranchNode.prototype.setupSlugs = function () {
+       var i, len,
+               isBlock = this.canHaveChildrenNotContent(),
+               childTypes = this.getChildNodeTypes(),
+               canContainParagraph = childTypes === null || ve.indexOf( 
'paragraph', childTypes ) !== -1;
+
+       this.slugPositions = {};
+
+       if ( isBlock && !canContainParagraph ) {
+               // Don't put slugs in nodes which can't contain paragraphs
+               return;
+       }
+
+       // If this content branch no longer has any non-internal items, insert 
a slug to keep the node
+       // from becoming invisible/unfocusable. In Firefox, backspace after 
Ctrl+A leaves the document
+       // completely empty, so this ensures DocumentNode gets a slug.
+       if (
+               this.getLength() === 0 ||
+               ( this.children.length === 1 && this.children[0].isInternal() )
+       ) {
+               this.slugPositions[0] = true;
+       } else {
+               // Iterate over all children of this branch and add slugs in 
appropriate places
+               for ( i = 0, len = this.children.length; i < len; i++ ) {
+                       // Don't put slugs after internal nodes
+                       if ( this.children[i].isInternal() ) {
+                               continue;
+                       }
+                       // First sluggable child (left side)
+                       if ( i === 0 && this.children[i].canHaveSlugBefore() ) {
+                               this.slugPositions[i] = true;
+                       }
+                       if ( this.children[i].canHaveSlugAfter() ) {
+                               if (
+                                       // Last sluggable child (right side)
+                                       i === this.children.length - 1 ||
+                                       // Sluggable child followed by another 
sluggable child (in between)
+                                       ( this.children[i + 1] && 
this.children[i + 1].canHaveSlugBefore() )
+                               ) {
+                                       this.slugPositions[i + 1] = true;
+                               }
+                       }
+               }
+       }
+};
diff --git a/src/dm/ve.dm.Node.js b/src/dm/ve.dm.Node.js
index 9d318dc..24b6604 100644
--- a/src/dm/ve.dm.Node.js
+++ b/src/dm/ve.dm.Node.js
@@ -338,6 +338,16 @@
 };
 
 /**
+ * Check if the node is an internal node
+ *
+ * @method
+ * @returns {boolean} Node is an internal node
+ */
+ve.dm.Node.prototype.isInternal = function () {
+       return this.constructor.static.isInternal;
+};
+
+/**
  * Check if the node has a wrapped element in the document data.
  *
  * @method

-- 
To view, visit https://gerrit.wikimedia.org/r/160838
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I4c5cb277facd29d6a69aac95e5bcff5d56bee89a
Gerrit-PatchSet: 2
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to