Affordances for MenuWidget to be optionally focusable.

* ve.ui.MenuWidget.js
MenuWidget no longer creates an embeded input element by default.
In the case of no configured input element, we bind the keydown
handler to window with addEventListner while using the useCapture
flag.  This nicely prevents elements lower in the dom from triggering
( document node ) Supported in IE9 and above and all modern browsers.

* ve.ui.ListAction.js
Since MenuWidget is no longer stealing focus from the surface,
we no longer need to restore focus after a list item conversion.
This is the end goal, as browsers like Chrome like to scroll to
the top of elements that gain focus.

Bug: 50792
Change-Id: I5b6969bca1a58b040708f8ac9d3dc8b07ddf9e6b
This commit is contained in:
Rob Moen 2013-07-09 12:53:35 -07:00
parent fdedbb36e2
commit 61c708ef1c
2 changed files with 37 additions and 12 deletions

View file

@ -68,10 +68,6 @@ ve.ui.FormatAction.prototype.convert = function ( type, attributes ) {
}
selection = fragmentForSelection.getRange();
// Since format dropdown tool is a focusable menu, documentNode has lost focus.
// Restore focus to documentNode so that firefox will display the cursor after conversion.
this.surface.view.documentView.documentNode.$[0].focus();
txs = ve.dm.Transaction.newFromContentBranchConversion( doc, selection, type, attributes );
surfaceModel.change( txs, selection );
};

View file

@ -24,19 +24,14 @@ ve.ui.MenuWidget = function VeUiMenuWidget( config ) {
// Properties
this.newItems = [];
this.$input = config.input ? config.input.$input : this.$$( '<input>' );
this.$input = config.input ? config.input.$input : null;
this.$previousFocus = null;
this.isolated = !config.input;
this.visible = false;
// Events
this.$input.on( 'keydown', ve.bind( this.onKeyDown, this ) );
this.keydownHandler = ve.bind( this.onKeyDown, this );
// Initialization
this.$.hide().addClass( 've-ui-menuWidget' );
if ( !config.input ) {
this.$.append( this.$input );
}
};
/* Inheritance */
@ -78,6 +73,8 @@ ve.ui.MenuWidget.prototype.onKeyDown = function ( e ) {
break;
}
if ( handled ) {
e.preventDefault();
e.stopPropagation();
return false;
}
}
@ -93,6 +90,34 @@ ve.ui.MenuWidget.prototype.isVisible = function () {
return this.visible;
};
/**
* Bind keydown listener
*
* @method
*/
ve.ui.MenuWidget.prototype.bindKeydownListener = function () {
if ( this.$input ) {
this.$input.on( 'keydown', this.keydownHandler );
} else {
// Capture menu navigation keys
window.addEventListener( 'keydown', this.keydownHandler, true );
}
};
/**
* Unbind keydown listener
*
* @method
*/
ve.ui.MenuWidget.prototype.unbindKeydownListener = function () {
if ( this.$input ) {
this.$input.off( 'keydown' );
} else {
window.removeEventListener( 'keydown', this.keydownHandler, true );
}
};
/**
* Select an item.
*
@ -161,8 +186,10 @@ ve.ui.MenuWidget.prototype.show = function () {
if ( this.items.length ) {
this.$.show();
this.visible = true;
this.bindKeydownListener();
// Change focus to enable keyboard navigation
if ( this.isolated && !this.$input.is( ':focus' ) ) {
if ( this.isolated && this.$input && !this.$input.is( ':focus' ) ) {
this.$previousFocus = this.$$( ':focus' );
this.$input.focus();
}
@ -186,6 +213,8 @@ ve.ui.MenuWidget.prototype.show = function () {
ve.ui.MenuWidget.prototype.hide = function () {
this.$.hide();
this.visible = false;
this.unbindKeydownListener();
if ( this.isolated && this.$previousFocus ) {
this.$previousFocus.focus();
this.$previousFocus = null;