jenkins-bot has submitted this change and it was merged. Change subject: Initial cursor position: outside any nails ......................................................................
Initial cursor position: outside any nails Place the initial cursor outside any nailed content, to avoid popping up context items before the user has deliberately moved their cursor. Bug: T114376 Change-Id: Ica0b85fa827e9d9bc22152bfb04a279f151c117d --- M demos/ve/pages/simple.html M src/ce/ve.ce.Document.js M src/ce/ve.ce.Surface.js M tests/ce/ve.ce.Document.test.js 4 files changed, 64 insertions(+), 11 deletions(-) Approvals: Divec: Looks good to me, approved jenkins-bot: Verified diff --git a/demos/ve/pages/simple.html b/demos/ve/pages/simple.html index 1a0ea1b..2b2844f 100644 --- a/demos/ve/pages/simple.html +++ b/demos/ve/pages/simple.html @@ -1,4 +1,4 @@ -<p><b>Lorem Ipsum</b> is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was <a href="https://www.mediawiki.org/wiki/VisualEditor">popularised</a> in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p> +<p><b><a href="https://en.wikipedia.org/wiki/Lorem_ipsum">Lorem Ipsum</a></b> is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was <a href="https://www.mediawiki.org/wiki/VisualEditor">popularised</a> in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p> <h2><b>What</b> is <i>Lorem Ipsum?</i></h2> <p>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a <a href="https://en.wikipedia.org/wiki/Latin">Latin</a> professor at Hampden-Sydney College in <a href="https://en.wikipedia.org/wiki/Virginia">Virginia</a>, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source.</p> <h3><b>Look</b> at <i>this headline</i></h3> diff --git a/src/ce/ve.ce.Document.js b/src/ce/ve.ce.Document.js index 5a1d69a..91750ee 100644 --- a/src/ce/ve.ce.Document.js +++ b/src/ce/ve.ce.Document.js @@ -49,14 +49,14 @@ * Calculate the DOM location corresponding to a DM offset * * @param {number} offset Linear model offset + * @param {boolean} outsideNail Whether to jump outside nails if directly next to them * @return {Object} DOM location * @return {Node} return.node location node * @return {number} return.offset location offset within the node * @throws {Error} Offset could not be translated to a DOM element and offset */ -ve.ce.Document.prototype.getNodeAndOffset = function ( offset ) { +ve.ce.Document.prototype.getNodeAndOffset = function ( offset, outsideNail ) { var nao, currentNode, nextLeaf, previousLeaf; - // Get the un-unicorn-adjusted result. If it is: // - just before pre unicorn (in same branch node), return cursor location just after it // - just after post unicorn (in same branch node), return cursor location just before it @@ -130,6 +130,28 @@ // At text offset or slug just after the post unicorn; return the point just before it return ve.ce.previousCursorOffset( previousLeaf ); } + + if ( outsideNail ) { + if ( + nao.offset === currentNode.length && + nextLeaf && + nextLeaf.nodeType === Node.ELEMENT_NODE && + nextLeaf.classList.contains( 've-ce-nail-pre-close' ) + ) { + // Being outside the nails requested and right next to the ending nail: jump outside + return ve.ce.nextCursorOffset( getAdjacentLeaf( 1, nextLeaf ) ); + } + if ( + nao.offset === 0 && + previousLeaf && + previousLeaf.nodeType === Node.ELEMENT_NODE && + previousLeaf.classList.contains( 've-ce-nail-post-open' ) + ) { + // Being outside the nails requested and right next to the starting nail: jump outside + return ve.ce.previousCursorOffset( getAdjacentLeaf( -1, previousLeaf ) ); + } + } + return nao; }; diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js index f16ef33..5df0790 100644 --- a/src/ce/ve.ce.Surface.js +++ b/src/ce/ve.ce.Surface.js @@ -3155,12 +3155,16 @@ var anchor, focus, dmDoc = this.getModel().getDocument(); - // Anchor/focus at the nearest correct position in the direction that grows the selection + // Anchor/focus at the nearest correct position in the direction that + // grows the selection. If we're not yet fully focused, move the selection + // outside any nails to avoid popping up a context menu. anchor = this.documentView.getNodeAndOffset( - dmDoc.getNearestCursorOffset( range.from, range.isBackwards() ? 1 : -1 ) + dmDoc.getNearestCursorOffset( range.from, range.isBackwards() ? 1 : -1 ), + !this.focused ); focus = this.documentView.getNodeAndOffset( - dmDoc.getNearestCursorOffset( range.to, range.isBackwards() ? -1 : 1 ) + dmDoc.getNearestCursorOffset( range.to, range.isBackwards() ? -1 : 1 ), + !this.focused ); return new ve.SelectionState( { anchorNode: anchor.node, diff --git a/tests/ce/ve.ce.Document.test.js b/tests/ce/ve.ce.Document.test.js index 6db066a..d7145db 100644 --- a/tests/ce/ve.ce.Document.test.js +++ b/tests/ce/ve.ce.Document.test.js @@ -89,8 +89,35 @@ replacement: { path: [ 0 ], innerHtml: '<br>' }, data: [ '<paragraph>', '</paragraph>' ], positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><p class='ve-ce-branchNode ve-ce-contentBranchNode ve-ce-paragraphNode'><br>||</br></p></div>" + }, + { + title: 'Paragraph with links, inside nails', + html: '<p><a href="A">A</a><a href="B">B</a></p>', + data: [ '<paragraph>', 'A', 'B', '</paragraph>' ], + positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><p class='ve-ce-branchNode ve-ce-contentBranchNode ve-ce-paragraphNode'><img class='ve-ce-nail ve-ce-nail-pre-open'></img><a class='ve-ce-linkAnnotation'><img class='ve-ce-nail ve-ce-nail-post-open'></img><#text>||A|</#text><img class='ve-ce-nail ve-ce-nail-pre-close'></img></a><img class='ve-ce-nail ve-ce-nail-post-close'></img><img class='ve-ce-nail ve-ce-nail-pre-open'></img><a class='ve-ce-linkAnnotation'><img class='ve-ce-nail ve-ce-nail-post-open'></img><#text>B|</#text><img class='ve-ce-nail ve-ce-nail-pre-close'></img></a><img class='ve-ce-nail ve-ce-nail-post-close'></img></p></div>" + }, + { + title: 'Paragraph with links, outside nails', + html: '<p><a href="A">A</a><a href="B">B</a></p>', + data: [ '<paragraph>', 'A', 'B', '</paragraph>' ], + positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><p class='ve-ce-branchNode ve-ce-contentBranchNode ve-ce-paragraphNode'>||<img class='ve-ce-nail ve-ce-nail-pre-open'></img><a class='ve-ce-linkAnnotation'><img class='ve-ce-nail ve-ce-nail-post-open'></img><#text>A</#text><img class='ve-ce-nail ve-ce-nail-pre-close'></img></a><img class='ve-ce-nail ve-ce-nail-post-close'></img>|<img class='ve-ce-nail ve-ce-nail-pre-open'></img><a class='ve-ce-linkAnnotation'><img class='ve-ce-nail ve-ce-nail-post-open'></img><#text>B</#text><img class='ve-ce-nail ve-ce-nail-pre-close'></img></a><img class='ve-ce-nail ve-ce-nail-post-close'></img>|</p></div>", + outsideNails: true + }, + { + title: 'Paragraph with links, non-text nodes, inside nails', + html: '<p><a href="A"><b>A<img></b></a></p>', + data: [ '<paragraph>', 'A', '<inlineImage>', '</inlineImage>', '</paragraph>' ], + dies: [ 3 ], + positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><p class='ve-ce-branchNode ve-ce-contentBranchNode ve-ce-paragraphNode'><img class='ve-ce-nail ve-ce-nail-pre-open'></img><a class='ve-ce-linkAnnotation'><img class='ve-ce-nail ve-ce-nail-post-open'></img><b class='ve-ce-textStyleAnnotation ve-ce-boldAnnotation'><#text>||A||</#text><img class='ve-ce-leafNode ve-ce-focusableNode ve-ce-imageNode ve-ce-inlineImageNode'></img></b><img class='ve-ce-nail ve-ce-nail-pre-close'></img></a><img class='ve-ce-nail ve-ce-nail-post-close'></img><span class='ve-ce-branchNode-slug ve-ce-branchNode-inlineSlug'>|</span></p></div>" + }, + { + title: 'Paragraph with links, non-text nodes, outside nails', + html: '<p><a href="A"><b>A<img></b></a></p>', + data: [ '<paragraph>', 'A', '<inlineImage>', '</inlineImage>', '</paragraph>' ], + dies: [ 3 ], + positions: "<div class='ve-ce-branchNode ve-ce-documentNode'><p class='ve-ce-branchNode ve-ce-contentBranchNode ve-ce-paragraphNode'>||<img class='ve-ce-nail ve-ce-nail-pre-open'></img><a class='ve-ce-linkAnnotation'><img class='ve-ce-nail ve-ce-nail-post-open'></img><b class='ve-ce-textStyleAnnotation ve-ce-boldAnnotation'><#text>A||</#text><img class='ve-ce-leafNode ve-ce-focusableNode ve-ce-imageNode ve-ce-inlineImageNode'></img></b><img class='ve-ce-nail ve-ce-nail-pre-close'></img></a><img class='ve-ce-nail ve-ce-nail-post-close'></img><span class='ve-ce-branchNode-slug ve-ce-branchNode-inlineSlug'>|</span></p></div>", + outsideNails: true } - ]; /*jscs:enable validateQuoteMarks */ @@ -141,7 +168,7 @@ for ( offset = 0; offset < offsetCount; offset++ ) { try { - position = ceDoc.getNodeAndOffset( offset ); + position = ceDoc.getNodeAndOffset( offset, test.outsideNails ); if ( test.dies && test.dies.indexOf( offset ) !== -1 ) { assert.ok( false, test.title + ' (' + offset + ') does not die' ); continue; @@ -154,12 +181,12 @@ continue; } - position = ceDoc.getNodeAndOffset( offset ); + position = ceDoc.getNodeAndOffset( offset, test.outsideNails ); assert.strictEqual( ve.test.utils.serializePosition( rootNode, - ceDoc.getNodeAndOffset( offset ), - { ignore: '.ve-ce-branchNode-blockSlug>*' } + ceDoc.getNodeAndOffset( offset, test.outsideNails ), + { ignore: '.ve-ce-branchNode-slug>*' } ), [].concat( parts.slice( 0, offset + 1 ), -- To view, visit https://gerrit.wikimedia.org/r/260057 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ica0b85fa827e9d9bc22152bfb04a279f151c117d Gerrit-PatchSet: 9 Gerrit-Project: VisualEditor/VisualEditor Gerrit-Branch: master Gerrit-Owner: DLynch <[email protected]> Gerrit-Reviewer: Divec <[email protected]> Gerrit-Reviewer: Esanders <[email protected]> Gerrit-Reviewer: Jforrester <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
