mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-25 06:46:26 +00:00
Defer selection-triggered updates in ve.ui.Context
Move selection change handling (closing the popup if open, and updating the context toolbar) to .afterChange(). Every time .onChange() detects a selection change, it schedules a call to afterChange(). These calls are batched so that multiple selection changes in the same tick cause afterChange() to be called only once. Deferring these updates causes them to no longer occur while a 'change' event is being emitted. This means that if an inspectors' close handler calls .change(), that call is now no longer nested inside another .change() call and doesn't run afoul of any render locks set by the caller of the outer .change(). Bug: 54675 Change-Id: Iae2f41a83b5d64251a54e42303100e84a5c25561
This commit is contained in:
parent
a12446d795
commit
febc0f567f
|
@ -31,6 +31,7 @@ ve.ui.Context = function VeUiContext( surface, config ) {
|
|||
this.embedded = false;
|
||||
this.selection = null;
|
||||
this.toolbar = null;
|
||||
this.afterChangeTimeout = null;
|
||||
this.popup = new ve.ui.PopupWidget( { '$$': this.$$, '$container': this.surface.getView().$ } );
|
||||
this.$menu = this.$$( '<div>' );
|
||||
this.inspectors = new ve.ui.SurfaceWindowSet( surface, ve.ui.inspectorFactory );
|
||||
|
@ -71,28 +72,46 @@ OO.inheritClass( ve.ui.Context, ve.Element );
|
|||
/* Methods */
|
||||
|
||||
/**
|
||||
* Handle change events on the model.
|
||||
* Handle selection changes in the model.
|
||||
*
|
||||
* Changes are ignored while the user is selecting text or relocating content, apart from closing
|
||||
* the popup if it's open. While an inspector is opening or closing, all changes are ignored so as
|
||||
* to prevent inspectors that change the selection from within their open/close handlers from
|
||||
* causing issues.
|
||||
*
|
||||
* The response to selection changes is deferred to prevent close handlers that process
|
||||
* changes from causing this function to recurse. These responses are also batched for efficiency,
|
||||
* so that if there are three selection changes in the same tick, afterChange() only runs once.
|
||||
*
|
||||
* @method
|
||||
* @see #afterChange
|
||||
* @param {ve.dm.Transaction[]} transactions Change transactions
|
||||
* @param {ve.Range} selection Change selection
|
||||
*/
|
||||
ve.ui.Context.prototype.onChange = function ( transactions, selection ) {
|
||||
if ( selection && !this.openingInspector && !this.hiding ) {
|
||||
if ( this.popup.isVisible() ) {
|
||||
this.hide();
|
||||
this.update();
|
||||
} else if ( !this.selecting && !this.relocating ) {
|
||||
this.update();
|
||||
if ( this.afterChangeTimeout === null ) {
|
||||
this.afterChangeTimeout = setTimeout( ve.bind( this.afterChange, this ) );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deferred response to one or more selection changes.
|
||||
*
|
||||
* Update the context menu for the new selection, except if the user is selecting or relocating
|
||||
* content. If the popup is open, close it, even while selecting or relocating.
|
||||
*/
|
||||
ve.ui.Context.prototype.afterChange = function () {
|
||||
this.afterChangeTimeout = null;
|
||||
if ( this.popup.isVisible() ) {
|
||||
this.hide();
|
||||
this.update();
|
||||
} else if ( !this.selecting && !this.relocating ) {
|
||||
this.update();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle selection start events on the view.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue