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( '' );
+ .html( '' )
+ .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( '' )
- );
+ )
+ .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