Bug 1058750 - Focus iframe when active cursor moves into it. r=yzen
authorEitan Isaacson <eitan@monotonous.org>
Tue, 26 Aug 2014 13:21:00 +0200
changeset 223746 f5f5837481b915f3fb47d240527eb1344a23b97e
parent 223745 a4aa926f8518aaecc8cf732a076b5132de5630a4
child 223747 2a7db469d28a4255f163ff07754804ed1bf366cb
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyzen
bugs1058750
milestone34.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 1058750 - Focus iframe when active cursor moves into it. r=yzen
accessible/jsat/ContentControl.jsm
accessible/tests/mochitest/jsat/jsatcommon.js
accessible/tests/mochitest/jsat/test_content_integration.html
--- a/accessible/jsat/ContentControl.jsm
+++ b/accessible/jsat/ContentControl.jsm
@@ -115,32 +115,34 @@ this.ContentControl.prototype = {
         if (action === 'moveNext') {
           childAction = 'moveFirst';
         } else if (action === 'movePrevious') {
           childAction = 'moveLast';
         }
 
         // Attempt to forward move to a potential child cursor in our
         // new position.
-        this.sendToChild(vc, aMessage, { action: childAction});
+        this.sendToChild(vc, aMessage, { action: childAction }, true);
       }
     } else if (!this._childMessageSenders.has(aMessage.target)) {
       // We failed to move, and the message is not from a child, so forward
       // to parent.
       this.sendToParent(aMessage);
     }
   },
 
   handleEvent: function cc_handleEvent(aEvent) {
     if (aEvent.type === 'mousemove') {
       this.handleMoveToPoint(
         { json: { x: aEvent.screenX, y: aEvent.screenY, rule: 'Simple' } });
     }
     if (!Utils.getMessageManager(aEvent.target)) {
       aEvent.preventDefault();
+    } else {
+      aEvent.target.focus();
     }
   },
 
   handleMoveToPoint: function cc_handleMoveToPoint(aMessage) {
     let [x, y] = [aMessage.json.x, aMessage.json.y];
     let rule = TraversalRules[aMessage.json.rule];
 
     let dpr = this.window.devicePixelRatio;
@@ -148,16 +150,17 @@ this.ContentControl.prototype = {
   },
 
   handleClearCursor: function cc_handleClearCursor(aMessage) {
     let forwarded = this.sendToChild(this.vc, aMessage);
     this.vc.position = null;
     if (!forwarded) {
       this._contentScope.get().sendAsyncMessage('AccessFu:CursorCleared');
     }
+    this.document.activeElement.blur();
   },
 
   handleAutoMove: function cc_handleAutoMove(aMessage) {
     this.autoMove(null, aMessage.json);
   },
 
   handleActivate: function cc_handleActivate(aMessage) {
     let activateAccessible = (aAccessible) => {
@@ -243,17 +246,17 @@ this.ContentControl.prototype = {
           return activatable;
         }
       }
 
       return null;
     };
 
     let vc = this.vc;
-    if (!this.sendToChild(vc, aMessage)) {
+    if (!this.sendToChild(vc, aMessage, null, true)) {
       let position = vc.position;
       activateAccessible(getActivatableDescendant(position) || position);
     }
   },
 
   handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
     // XXX: Add sendToChild. Right now this is only used in Android, so no need.
     let direction = aMessage.json.direction;
@@ -342,22 +345,28 @@ this.ContentControl.prototype = {
       }
 
       return mm;
     }
 
     return null;
   },
 
-  sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer) {
-    let mm = this.getChildCursor(aVirtualCursor.position);
+  sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer,
+                                       aFocus) {
+    let position = aVirtualCursor.position;
+    let mm = this.getChildCursor(position);
     if (!mm) {
       return false;
     }
 
+    if (aFocus) {
+      position.takeFocus();
+    }
+
     // XXX: This is a silly way to make a deep copy
     let newJSON = JSON.parse(JSON.stringify(aMessage.json));
     newJSON.origin = 'parent';
     for (let attr in aReplacer) {
       newJSON[attr] = aReplacer[attr];
     }
 
     mm.sendAsyncMessage(aMessage.name, newJSON);
@@ -427,17 +436,17 @@ this.ContentControl.prototype = {
       let sentToChild = this.sendToChild(vc, {
         name: 'AccessFu:AutoMove',
         json: {
           moveMethod: aOptions.moveMethod,
           moveToFocused: aOptions.moveToFocused,
           noOpIfOnScreen: true,
           forcePresent: true
         }
-      });
+      }, null, true);
 
       if (!moved && !sentToChild) {
         forcePresentFunc();
       }
     };
 
     if (aOptions.delay) {
       this._autoMove = this.window.setTimeout(moveFunc, aOptions.delay);
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -298,16 +298,22 @@ AccessFuContentTest.prototype = {
       }
 
       if (expected.android) {
         var checkFunc = SimpleTest[expected.android_checkFunc] || ok;
         checkFunc.apply(SimpleTest,
           this.lazyCompare(android, expected.android));
       }
 
+      if (expected.focused) {
+        var doc = currentTabDocument();
+        is(doc.activeElement, doc.querySelector(expected.focused),
+          'Correct element is focused');
+      }
+
       this.pump();
     }
 
   },
 
   lazyCompare: function lazyCompare(aReceived, aExpected) {
     var matches = true;
     var delta = [];
--- a/accessible/tests/mochitest/jsat/test_content_integration.html
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -25,20 +25,22 @@
       var doc = currentTabDocument();
       var iframe = doc.createElement('iframe');
       iframe.mozbrowser = true;
       iframe.addEventListener('mozbrowserloadend', function () {
       var contentTest = new AccessFuContentTest(
         [
           // Simple traversal forward
           [ContentMessages.simpleMoveNext, {
-            speak: ['Phone status bar', 'Traversal Rule test document']
+            speak: ['Phone status bar', 'Traversal Rule test document'],
+            focused: 'body'
           }],
           [ContentMessages.simpleMoveNext, {
-            speak: ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app']
+            speak: ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'],
+            focused: 'iframe'
           }],
           [ContentMessages.simpleMoveNext, {
             speak: ['many option', {'string': 'stateNotChecked'},
               {'string': 'checkbutton'}, {'string': 'listStart'},
               {'string': 'list'}, {'string': 'listItemsCount', 'count': 1}]
           }],
           // check checkbox
           [ContentMessages.activateCurrent(), {