diff --git a/modules/ve/ce/ve.ce.Surface.js b/modules/ve/ce/ve.ce.Surface.js index ff7403c918..cff5a4a7be 100644 --- a/modules/ve/ce/ve.ce.Surface.js +++ b/modules/ve/ce/ve.ce.Surface.js @@ -834,7 +834,7 @@ ve.ce.Surface.prototype.endRelocation = function () { * @method */ ve.ce.Surface.prototype.handleLeftOrRightArrowKey = function ( e ) { - var selection, offset, range; + var selection, offset, range, offsetDelta, toNode, selectedNodes, i; // On Mac OS pressing Command (metaKey) + Left/Right is same as pressing Home/End. // As we are not able to handle it programmatically (because we don't know at which offsets // lines starts and ends) let it happen natively. @@ -846,15 +846,44 @@ ve.ce.Surface.prototype.handleLeftOrRightArrowKey = function ( e ) { // Stop with final poll cycle so we have correct information in model this.surfaceObserver.stop( true ); selection = this.model.getSelection(); - offset = this.getDocument().getRelativeOffset( - selection.to, - e.keyCode === ve.Keys.DOM_VK_LEFT ? -1 : 1, // direction (left or right) - e.altKey === true || e.ctrlKey === true ? 'word' : 'character' // unit - ); - if ( e.shiftKey === true ) { // expanded range - range = new ve.Range( selection.from, offset ); - } else { // collapsed range (just a cursor) - range = new ve.Range( offset ); + offsetDelta = e.keyCode === ve.Keys.DOM_VK_LEFT ? -1 : 1; + + // Check for selecting/deselecting inline images and aliens + if ( selection.isCollapsed() ) { + toNode = this.documentView.documentNode.getNodeFromOffset( selection.to + offsetDelta ); + // TODO: Develop better method to test for generated content + if ( toNode.model.constructor.static.generatedContent === true ) { + range = new ve.Range( + selection.to, + selection.to + toNode.getOuterLength() * offsetDelta + ); + } + } else if ( !e.shiftKey ) { + selectedNodes = this.model.documentModel.selectNodes( selection ); + for ( i = 0; i < Math.min( selectedNodes.length, 2 ); i++ ) { + if ( + // TODO: Develop better method to test for generated content + selectedNodes[i].node.constructor.static.generatedContent === true && + selectedNodes[i].nodeOuterRange.equals( selection ) || + selectedNodes[i].nodeOuterRange.equals( selection.flip() ) + ) { + range = new ve.Range( offsetDelta === 1 ? selection.end : selection.start ); + } + } + } + + // Normal cursor movement + if ( range === undefined ) { + offset = this.getDocument().getRelativeOffset( + selection.to, + offsetDelta, + e.altKey === true || e.ctrlKey === true ? 'word' : 'character' // unit + ); + if ( e.shiftKey === true ) { // expanded range + range = new ve.Range( selection.from, offset ); + } else { // collapsed range (just a cursor) + range = new ve.Range( offset ); + } } this.model.change( null, range ); this.surfaceObserver.start(); diff --git a/modules/ve/dm/nodes/ve.dm.AlienNode.js b/modules/ve/dm/nodes/ve.dm.AlienNode.js index cdf397f50b..7275c88c12 100644 --- a/modules/ve/dm/nodes/ve.dm.AlienNode.js +++ b/modules/ve/dm/nodes/ve.dm.AlienNode.js @@ -30,6 +30,9 @@ ve.dm.AlienNode.static.name = 'alien'; ve.dm.AlienNode.static.storeHtmlAttributes = false; +// TODO: Develop better method to test for generated content +ve.dm.AlienNode.static.generatedContent = true; + ve.dm.AlienNode.static.toDataElement = function ( domElements, converter ) { var isInline = this.isHybridInline( domElements, converter ), type = isInline ? 'alienInline' : 'alienBlock', diff --git a/modules/ve/dm/nodes/ve.dm.MWImageNode.js b/modules/ve/dm/nodes/ve.dm.MWImageNode.js index fe90d98611..c72b25ccc1 100644 --- a/modules/ve/dm/nodes/ve.dm.MWImageNode.js +++ b/modules/ve/dm/nodes/ve.dm.MWImageNode.js @@ -28,6 +28,9 @@ ve.dm.MWImageNode.static.name = 'MWimage'; ve.dm.MWImageNode.static.matchTagNames = null; +// TODO: Develop better method to test for generated content +ve.dm.MWImageNode.static.generatedContent = true; + ve.dm.MWImageNode.static.matchRdfaTypes = [ 'mw:Image' ]; ve.dm.MWImageNode.static.toDataElement = function ( domElements ) {