Bartosz Dziewoński has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/364259 )

Change subject: WindowManager: Avoid inconsistent state due to asynchronous 
promise resolution
......................................................................

WindowManager: Avoid inconsistent state due to asynchronous promise resolution

WindowInstance:
* New methods #isOpening, #isOpened, #isClosing, #isClosed.
  These should be used instead of checking the .state() of
  the promises #opening, #opened, #closing, #closed, as that
  is updated asynchronously and not immediately when the
  window lifecycle stage changes.

WindowManager:
* Use the new WindowInstance methods instead of checking .state().
* Tweak error handling in #openWindow to reduce code duplication.

Bug: T170164
Change-Id: I63b81e12a9ffdf8b95fa7cccfa984672d534b4ba
---
M src/WindowInstance.js
M src/WindowManager.js
2 files changed, 54 insertions(+), 22 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/oojs/ui refs/changes/59/364259/1

diff --git a/src/WindowInstance.js b/src/WindowInstance.js
index 72490c7..f6883ae 100644
--- a/src/WindowInstance.js
+++ b/src/WindowInstance.js
@@ -58,3 +58,41 @@
 /* Setup */
 
 OO.initClass( OO.ui.WindowInstance );
+
+/**
+ * Check if window is opening.
+ *
+ * @return {boolean} Window is opening
+ */
+OO.ui.WindowInstance.prototype.isOpening = function ( win ) {
+       return this.deferreds.opened.state() === 'pending';
+};
+
+/**
+ * Check if window is opened.
+ *
+ * @return {boolean} Window is opened
+ */
+OO.ui.WindowInstance.prototype.isOpened = function ( win ) {
+       return this.deferreds.opened.state() === 'resolved' &&
+               this.deferreds.closing.state() === 'pending';
+};
+
+/**
+ * Check if window is closing.
+ *
+ * @return {boolean} Window is closing
+ */
+OO.ui.WindowInstance.prototype.isClosing = function ( win ) {
+       return this.deferreds.closing.state() === 'resolved' &&
+               this.deferreds.closed.state() === 'pending';
+};
+
+/**
+ * Check if window is closed.
+ *
+ * @return {boolean} Window is closed
+ */
+OO.ui.WindowInstance.prototype.isClosed = function ( win ) {
+       return this.deferreds.closed.state() === 'resolved';
+};
diff --git a/src/WindowManager.js b/src/WindowManager.js
index 2c58fe4..1a256d3 100644
--- a/src/WindowManager.js
+++ b/src/WindowManager.js
@@ -194,7 +194,7 @@
  */
 OO.ui.WindowManager.prototype.isOpening = function ( win ) {
        return win === this.currentWindow && !!this.lifecycle &&
-               this.lifecycle.opened.state() === 'pending';
+               this.lifecycle.isOpening();
 };
 
 /**
@@ -205,8 +205,7 @@
  */
 OO.ui.WindowManager.prototype.isClosing = function ( win ) {
        return win === this.currentWindow && !!this.lifecycle &&
-               this.lifecycle.closing.state() === 'resolved' &&
-               this.lifecycle.closed.state() === 'pending';
+               this.lifecycle.isClosing();
 };
 
 /**
@@ -217,8 +216,7 @@
  */
 OO.ui.WindowManager.prototype.isOpened = function ( win ) {
        return win === this.currentWindow && !!this.lifecycle &&
-               this.lifecycle.opened.state() === 'resolved' &&
-               this.lifecycle.closing.state() === 'pending';
+               this.lifecycle.isOpened();
 };
 
 /**
@@ -347,7 +345,8 @@
  * @fires opening
  */
 OO.ui.WindowManager.prototype.openWindow = function ( win, data, lifecycle, 
compatOpening ) {
-       var manager = this;
+       var error,
+               manager = this;
        data = data || {};
 
        // Internal parameter 'lifecycle' allows this method to always return
@@ -384,21 +383,16 @@
 
        // Error handling
        if ( !this.hasWindow( win ) ) {
-               compatOpening.reject( new OO.ui.Error(
-                       'Cannot open window: window is not attached to manager'
-               ) );
-               lifecycle.deferreds.opening.reject( new OO.ui.Error(
-                       'Cannot open window: window is not attached to manager'
-               ) );
-               return lifecycle;
+               error = 'Cannot open window: window is not attached to manager';
+       } else if ( this.lifecycle && this.lifecycle.isOpened() ) {
+               error = 'Cannot open window: another window is open';
+       } else if ( this.preparingToOpen || ( this.lifecycle && 
this.lifecycle.isOpening() ) ) {
+               error = 'Cannot open window: another window is opening';
        }
-       if ( this.preparingToOpen || ( this.lifecycle && 
this.lifecycle.closing.state() !== 'resolved' ) ) {
-               compatOpening.reject( new OO.ui.Error(
-                       'Cannot open window: another window is opening or open'
-               ) );
-               lifecycle.deferreds.opening.reject( new OO.ui.Error(
-                       'Cannot open window: another window is opening or open'
-               ) );
+
+       if ( error ) {
+               compatOpening.reject( new OO.ui.Error( error ) );
+               lifecycle.deferreds.opening.reject( new OO.ui.Error( error ) );
                return lifecycle;
        }
 
@@ -472,9 +466,9 @@
                error = 'Cannot close window: no window is currently open';
        } else if ( !win ) {
                error = 'Cannot close window: window is not attached to 
manager';
-       } else if ( win !== this.currentWindow ) {
+       } else if ( win !== this.currentWindow || this.lifecycle.isClosed() ) {
                error = 'Cannot close window: window already closed with 
different data';
-       } else if ( this.preparingToClose || 
lifecycle.deferreds.closing.state() === 'resolved' ) {
+       } else if ( this.preparingToClose || this.lifecycle.isClosing() ) {
                error = 'Cannot close window: window already closing with 
different data';
        }
 

-- 
To view, visit https://gerrit.wikimedia.org/r/364259
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I63b81e12a9ffdf8b95fa7cccfa984672d534b4ba
Gerrit-PatchSet: 1
Gerrit-Project: oojs/ui
Gerrit-Branch: master
Gerrit-Owner: Bartosz Dziewoński <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to