mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-15 10:35:48 +00:00
ve.ui.PopupWidget visibility fixes
Objective: * Context popup would stop opening sometimes "mysteriously" which ended up having to do with the automatic closing on blur functionality added to popups for use in the category popup widget * Mousedown event canceling was being applied a little too widely, and was causing popup widgets to not allow child elements to be focused (unless they contained an iframe, like an inspector) Changes: ve.ui.Context.js * Make use of the popup's show and hide methods within the inspector ve.ui.MWCategoryPopupWidget.js * Override autoClose option for category popup widgets ve.ui.PopupWidget.js * Add autoClose option to popup widgets * Move event handler to the top of the methods (convention) * Only bind blur event if autoClose is enabled * Inline the getFocusedChild method Change-Id: I22aedb5fbd51b327ea7ce2ecdd6123e79cbebb9c
This commit is contained in:
parent
0eb2581b64
commit
3a99b99876
|
@ -295,6 +295,7 @@ ve.ui.Context.prototype.show = function ( transition ) {
|
||||||
this.showing = true;
|
this.showing = true;
|
||||||
|
|
||||||
this.$.show();
|
this.$.show();
|
||||||
|
this.popup.show();
|
||||||
|
|
||||||
// Show either inspector or menu
|
// Show either inspector or menu
|
||||||
if ( inspector ) {
|
if ( inspector ) {
|
||||||
|
@ -346,8 +347,7 @@ ve.ui.Context.prototype.hide = function () {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inspectors.$.hide();
|
this.popup.hide();
|
||||||
this.$menu.hide();
|
|
||||||
this.$.hide();
|
this.$.hide();
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
* @param {Object} [config] Config options
|
* @param {Object} [config] Config options
|
||||||
*/
|
*/
|
||||||
ve.ui.MWCategoryPopupWidget = function VeUiMwCategoryPopupWidget ( config ) {
|
ve.ui.MWCategoryPopupWidget = function VeUiMwCategoryPopupWidget ( config ) {
|
||||||
|
// Configuration initialization
|
||||||
|
config = ve.extendObject( {}, config, { 'autoClose': true } );
|
||||||
|
|
||||||
// Parent constructor
|
// Parent constructor
|
||||||
ve.ui.PopupWidget.call( this, config );
|
ve.ui.PopupWidget.call( this, config );
|
||||||
|
|
||||||
|
@ -50,6 +53,11 @@ ve.ui.MWCategoryPopupWidget = function VeUiMwCategoryPopupWidget ( config ) {
|
||||||
config.$overlay.append( this.$ );
|
config.$overlay.append( this.$ );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @cfg {boolean} [autoClose=true] Overridden in this subclass
|
||||||
|
*/
|
||||||
|
|
||||||
/* Inheritance */
|
/* Inheritance */
|
||||||
|
|
||||||
ve.inheritClass( ve.ui.MWCategoryPopupWidget, ve.ui.PopupWidget );
|
ve.inheritClass( ve.ui.MWCategoryPopupWidget, ve.ui.PopupWidget );
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {Object} [config] Config options
|
* @param {Object} [config] Config options
|
||||||
|
* @cfg {boolean} [autoClose=false] Popup auto-closes when it loses focus
|
||||||
*/
|
*/
|
||||||
ve.ui.PopupWidget = function VeUiPopupWidget( config ) {
|
ve.ui.PopupWidget = function VeUiPopupWidget( config ) {
|
||||||
// Config intialization
|
// Config intialization
|
||||||
|
@ -24,24 +25,31 @@ ve.ui.PopupWidget = function VeUiPopupWidget( config ) {
|
||||||
// Properties
|
// Properties
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.$callout = this.$$( '<div>' );
|
this.$callout = this.$$( '<div>' );
|
||||||
// Tab index on body so that it may blur
|
this.$body = this.$$( '<div>' );
|
||||||
this.$body = this.$$( '<div>' ).attr( 'tabindex', 1 );
|
|
||||||
this.transitionTimeout = null;
|
this.transitionTimeout = null;
|
||||||
this.align = config.align || 'center';
|
this.align = config.align || 'center';
|
||||||
|
this.autoClose = !!config.autoClose;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
this.$body.on( 'blur', ve.bind( this.onPopupBlur, this ) );
|
|
||||||
this.$.add( this.$body ).add( this.$callout )
|
this.$.add( this.$body ).add( this.$callout )
|
||||||
.on( 'mousedown', false );
|
.on( 'mousedown', function ( e ) {
|
||||||
|
// Cancel only local mousedown events
|
||||||
|
return e.target !== this;
|
||||||
|
} );
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
|
if ( this.autoClose ) {
|
||||||
|
// Tab index on body so that it may blur
|
||||||
|
this.$body.attr( 'tabindex', 1 );
|
||||||
|
// Listen for blur events
|
||||||
|
this.$body.on( 'blur', ve.bind( this.onPopupBlur, this ) );
|
||||||
|
}
|
||||||
this.$
|
this.$
|
||||||
.addClass( 've-ui-popupWidget' )
|
.addClass( 've-ui-popupWidget' )
|
||||||
.append(
|
.append(
|
||||||
this.$callout.addClass( 've-ui-popupWidget-callout' ),
|
this.$callout.addClass( 've-ui-popupWidget-callout' ),
|
||||||
this.$body.addClass( 've-ui-popupWidget-body' )
|
this.$body.addClass( 've-ui-popupWidget-body' )
|
||||||
);
|
);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Inheritance */
|
/* Inheritance */
|
||||||
|
@ -56,6 +64,38 @@ ve.inheritClass( ve.ui.PopupWidget, ve.ui.Widget );
|
||||||
|
|
||||||
/* Methods */
|
/* Methods */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle blur events.
|
||||||
|
*
|
||||||
|
* @param {jQuery.Event} e Blur event
|
||||||
|
*/
|
||||||
|
ve.ui.PopupWidget.prototype.onPopupBlur = function () {
|
||||||
|
var $body = this.$body;
|
||||||
|
|
||||||
|
// Find out what is focused after blur
|
||||||
|
setTimeout( ve.bind( function () {
|
||||||
|
var $focused = $body.find( ':focus' );
|
||||||
|
// Is there a focused child element?
|
||||||
|
if ( $focused.length > 0 ) {
|
||||||
|
// Bind a one off blur event to that focused child element
|
||||||
|
$focused.one( 'blur', ve.bind( function () {
|
||||||
|
setTimeout( ve.bind( function () {
|
||||||
|
if ( $body.find( ':focus' ).length === 0 ) {
|
||||||
|
// Be sure focus is not the popup itself.
|
||||||
|
if ( $body.is( ':focus' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Not a child and not the popup itself, so hide.
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
}, this ), 0 );
|
||||||
|
}, this ) );
|
||||||
|
} else {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
}, this ), 0 );
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the context.
|
* Show the context.
|
||||||
*
|
*
|
||||||
|
@ -65,8 +105,10 @@ ve.inheritClass( ve.ui.PopupWidget, ve.ui.Widget );
|
||||||
ve.ui.PopupWidget.prototype.show = function () {
|
ve.ui.PopupWidget.prototype.show = function () {
|
||||||
this.$.show();
|
this.$.show();
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
// Focus body so that it may blur.
|
if ( this.autoClose ) {
|
||||||
this.$body.focus();
|
// Focus body so that it may blur
|
||||||
|
this.$body.focus();
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,34 +125,6 @@ ve.ui.PopupWidget.prototype.hide = function () {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.ui.PopupWidget.prototype.getFocusedChild = function () {
|
|
||||||
return this.$body.find( ':focus' );
|
|
||||||
};
|
|
||||||
|
|
||||||
ve.ui.PopupWidget.prototype.onPopupBlur = function () {
|
|
||||||
// Find out what is focused after blur
|
|
||||||
setTimeout( ve.bind( function () {
|
|
||||||
var $focused = this.getFocusedChild();
|
|
||||||
// Is there a focused child element?
|
|
||||||
if ( $focused.length > 0 ) {
|
|
||||||
// Bind a one off blur event to that focused child element
|
|
||||||
$focused.one( 'blur', ve.bind( function () {
|
|
||||||
setTimeout( ve.bind( function () {
|
|
||||||
if ( this.getFocusedChild().length === 0 ) {
|
|
||||||
// Be sure focus is not the popup itself.
|
|
||||||
if ( this.$.find( ':focus' ).is( this.$body ) ){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Not a child and not the popup itself, so hide.
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
}, this ), 0 );
|
|
||||||
}, this ) );
|
|
||||||
} else {
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
}, this ), 0 );
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the position and size.
|
* Updates the position and size.
|
||||||
|
|
Loading…
Reference in a new issue