Add a getDirectionFromRange Method to ve.ce.Document

getDirectionFromRange returns the direction property of the ce nodes under
that range. That method is mostly useful to recognize the overall block
direction of a selection or fragment.

The method is currently used in the following locations:
* ve.ui.Toolbar onContextChange - as a means to recognize the current context's
  block direction for the icon directionality.
* ve.ui.MWExtensionInspector - if the selection is text and not an existing node
  the input directionality adjusts to the context direction.

Bug: 57421
Change-Id: Ifc01b8e5dc0a2fe39d221e59e452c5cfad709a2d
This commit is contained in:
Moriel Schottlender 2013-12-11 21:36:35 -08:00
parent da14b51b7e
commit 95d99192b4
3 changed files with 48 additions and 27 deletions

View file

@ -59,6 +59,9 @@ ve.ui.MWExtensionInspector.prototype.initialize = function () {
* @inheritdoc
*/
ve.ui.MWExtensionInspector.prototype.setup = function ( data ) {
var dir,
fragment = this.surface.getModel().getFragment( null, true );
// Parent method
ve.ui.Inspector.prototype.setup.call( this, data );
@ -66,12 +69,16 @@ ve.ui.MWExtensionInspector.prototype.setup = function ( data ) {
this.node = this.surface.getView().getFocusedNode();
this.input.setValue( this.node ? this.node.getModel().getAttribute( 'mw' ).body.extsrc : '' );
// By default, the direction of the input element should be the same
// as the direction of the content it applies to
if ( this.node ) {
// Direction of the input textarea should correspond to the
// direction of the surrounding content of the node itself
// rather than the GUI direction:
this.input.setRTL( this.node.$element.css( 'direction' ) === 'rtl' );
// The node is being edited
dir = this.node.$element.css( 'direction' );
} else {
// New insertion, base direction on the fragment range
dir = this.surface.getView().documentView.getDirectionFromRange( fragment.getRange() );
}
this.input.setRTL( dir === 'rtl' );
};
/**

View file

@ -268,3 +268,34 @@ ve.ce.Document.prototype.getRelativeRange = function ( range, direction, unit, e
return new ve.Range( contentOrSlugOffset );
}
};
/**
* Get the directionality of some range.
*
* @method
* @param {ve.Range} range Selection range
* @returns {String} 'rtl' or 'ltr' as response
*/
ve.ce.Document.prototype.getDirectionFromRange = function ( range ) {
var effectiveNode,
selectedNodes = this.selectNodes( range, 'covered' );
if ( selectedNodes.length > 1 ) {
// Selection of multiple nodes
// Get the common parent node
effectiveNode = this.selectNodes( range, 'siblings' )[0].node.getParent();
} else {
// selection of a single node
effectiveNode = selectedNodes[0].node;
while ( effectiveNode.isContent() ) {
// This means that we're in a leaf node, like TextNode
// those don't read the directionality properly, we will
// have to climb up the parentage chain until we find a
// wrapping node like paragraph or list item, etc.
effectiveNode = effectiveNode.parent;
}
}
return effectiveNode.$element.css( 'direction' );
};

View file

@ -156,14 +156,7 @@ ve.ui.Toolbar.prototype.onSurfaceViewKeyUp = function () {
*/
ve.ui.Toolbar.prototype.onContextChange = function () {
var i, len, leafNodes, dirInline, dirBlock, fragmentAnnotation,
currentNodes = {
fragNodes: null,
fragAnnotations: null,
'dm': {},
'ce': {}
},
fragment = this.surface.getModel().getFragment( null, false ),
doc = this.surface.getView().getDocument(),
nodes = [];
leafNodes = fragment.getLeafNodes();
@ -172,27 +165,17 @@ ve.ui.Toolbar.prototype.onContextChange = function () {
nodes.push( leafNodes[i].node );
}
}
// Update context direction for button icons UI:
// Update context direction for button icons UI
// block direction (direction of the current node)
currentNodes.fragNodes = fragment.getCoveredNodes();
if ( currentNodes.fragNodes.length > 1 ) {
// selection of multiple nodes
currentNodes.dm.block = fragment.getSiblingNodes()[0].node.parent;
} else {
// selection of a single node
currentNodes.dm.block = currentNodes.fragNodes[0].node;
}
// get the direction of the block:
currentNodes.ce.block = doc.getNodeFromOffset( currentNodes.dm.block.getRange().start );
dirBlock = currentNodes.ce.block.$element.css( 'direction' );
// by default, inline and block are the same, unless there's an inline-specific direction
dirInline = dirBlock;
// 'inline' direction is set by language annotation:
// by default, inline and block directions are the same
dirInline = dirBlock = this.surface.getView().documentView.getDirectionFromRange( fragment.getRange() );
// 'inline' direction is different only if we are inside a language annotation
fragmentAnnotation = fragment.getAnnotations();
if ( fragmentAnnotation.hasAnnotationWithName( 'meta/language' ) ) {
dirInline = fragmentAnnotation.getAnnotationsByName( 'meta/language' ).get( 0 ).getAttribute( 'dir' );
}
if ( dirInline !== this.contextDirection.inline ) {
// remove previous class:
this.$element.removeClass( 've-ui-dir-inline-rtl ve-ui-dir-inline-ltr' );