Bug 1077044 - Store previous cursor position when dialog pops up, and restore it when it is hidden. r=yzen
authorEitan Isaacson <eitan@monotonous.org>
Sun, 12 Oct 2014 11:23:45 -0700
changeset 233245 b5fd3fa97b53bcd4189a999725f718e6cfc63c89
parent 233244 257d77cf8f92731ce1346c6335a14c4b2f4924e1
child 233246 4ffbb6be512d6acd0b9157492440156ecd241652
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyzen
bugs1077044
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1077044 - Store previous cursor position when dialog pops up, and restore it when it is hidden. r=yzen
accessible/jsat/EventManager.jsm
accessible/tests/mochitest/jsat/doc_content_integration.html
accessible/tests/mochitest/jsat/test_content_integration.html
--- a/accessible/jsat/EventManager.jsm
+++ b/accessible/jsat/EventManager.jsm
@@ -56,16 +56,17 @@ this.EventManager.prototype = {
         AccessibilityEventObserver.addListener(this);
 
         this.webProgress.addProgressListener(this,
           (Ci.nsIWebProgress.NOTIFY_STATE_ALL |
            Ci.nsIWebProgress.NOTIFY_LOCATION));
         this.addEventListener('wheel', this, true);
         this.addEventListener('scroll', this, true);
         this.addEventListener('resize', this, true);
+        this._preDialogPosition = new WeakMap();
       }
       this.present(Presentation.tabStateChanged(null, 'newtab'));
 
     } catch (x) {
       Logger.logException(x, 'Failed to start EventManager');
     }
   },
 
@@ -73,16 +74,17 @@ this.EventManager.prototype = {
   // late). It is only called when the AccessFu is disabled explicitly.
   stop: function stop() {
     if (!this._started) {
       return;
     }
     Logger.debug('EventManager.stop');
     AccessibilityEventObserver.removeListener(this);
     try {
+      this._preDialogPosition.clear();
       this.webProgress.removeProgressListener(this);
       this.removeEventListener('wheel', this, true);
       this.removeEventListener('scroll', this, true);
       this.removeEventListener('resize', this, true);
     } catch (x) {
       // contentScope is dead.
     } finally {
       this._started = false;
@@ -267,18 +269,18 @@ this.EventManager.prototype = {
       {
         let position = this.contentControl.vc.position;
         if (aEvent.accessible === aEvent.accessibleDocument ||
             (position && Utils.isInSubtree(position, aEvent.accessible))) {
           // Do not automove into the document if the virtual cursor is already
           // positioned inside it.
           break;
         }
-        this.contentControl.autoMove(
-          aEvent.accessible, { delay: 500 });
+        this._preDialogPosition.set(aEvent.accessible.DOMNode, position);
+        this.contentControl.autoMove(aEvent.accessible, { delay: 500 });
         break;
       }
       case Events.VALUE_CHANGE:
       {
         let position = this.contentControl.vc.position;
         let target = aEvent.accessible;
         if (position === target ||
             Utils.getEmbeddedControl(position) === target) {
@@ -361,17 +363,18 @@ this.EventManager.prototype = {
         return;
       }
       this._queueLiveEvent(Events.HIDE, liveRegion, isPolite);
     } else {
       let vc = Utils.getVirtualCursor(this.contentScope.content.document);
       if (vc.position &&
         (Utils.getState(vc.position).contains(States.DEFUNCT) ||
           Utils.isInSubtree(vc.position, acc))) {
-        let position = aEvent.targetPrevSibling || aEvent.targetParent;
+        let position = this._preDialogPosition.get(aEvent.accessible.DOMNode) ||
+          aEvent.targetPrevSibling || aEvent.targetParent;
         if (!position) {
           try {
             position = acc.previousSibling;
           } catch (x) {
             // Accessible is unattached from the accessible tree.
             position = acc.parent;
           }
         }
--- a/accessible/tests/mochitest/jsat/doc_content_integration.html
+++ b/accessible/tests/mochitest/jsat/doc_content_integration.html
@@ -70,19 +70,19 @@
 
   </style>
 
 </head>
 <body>
   <div>Phone status bar</div>
   <div id="windows">
     <button id="back">Back</button>
-    <div id="appframe"></div>
     <div role="dialog" id="alert" hidden>
       <h1>This is an alert!</h1>
       <p>Do you agree?</p>
-      <button onclick="hideAlert()">Yes</button>
+      <button onclick="setTimeout(hideAlert, 500)">Yes</button>
       <button onclick="hideAlert()">No</button>
     </div>
+    <div id="appframe"></div>
   </div>
   <button id="home">Home</button>
 </body>
 </html>
--- a/accessible/tests/mochitest/jsat/test_content_integration.html
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -174,43 +174,46 @@
             // Must not speak Back button as it is aria-hidden
            new ExpectedCursorChange(
              ["wow", {"string": "headingLevel","args": [1]}, "such app"])],
           [doc.defaultView.ariaShowBack],
           [ContentMessages.focusSelector('button#back', true), null],
           [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
 
           // Open dialog in outer doc, while cursor is also in outer doc
-          [ContentMessages.simpleMoveNext,
-           new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
+          [ContentMessages.simpleMoveLast,
+           new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
           [doc.defaultView.showAlert,
             new ExpectedCursorChange(['This is an alert!',
               {'string': 'headingLevel', 'args': [1]},
               {'string': 'dialog'}])],
 
           [doc.defaultView.hideAlert,
-           new ExpectedCursorChange(["wow",
-            {"string": "headingLevel", "args": [1]}, "such app"])],
+           new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
 
           [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
 
           // Open dialog in outer doc, while cursor is in inner frame
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(["Back", {"string": "pushbutton"}])],
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(
             ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
           [doc.defaultView.showAlert, new ExpectedCursorChange(['This is an alert!',
                     {'string': 'headingLevel', 'args': [1]},
                     {'string': 'dialog'}])],
 
-          // XXX: Place cursor back where it was.
-          [doc.defaultView.hideAlert,
+          [ContentMessages.simpleMoveNext,
+            new ExpectedCursorChange(['Do you agree?'])],
+          [ContentMessages.simpleMoveNext,
+            new ExpectedCursorChange(['Yes', {'string': 'pushbutton'}])],
+          [ContentMessages.activateCurrent(),
+           new ExpectedClickAction(),
            new ExpectedCursorChange(
             ['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
 
           [ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
 
           // Open dialog, then focus on something when closing
           [ContentMessages.simpleMoveNext,
            new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],