Bug 1454783 - Remove non-Android presenters in AccessFu. r=yzen

--HG--
extra : rebase_source : 1ed88a48b387022ec3e48d4dca7574744b09064d
This commit is contained in:
Eitan Isaacson 2018-04-24 14:43:00 +03:00
Родитель 4766228db5
Коммит c947f9b6ab
16 изменённых файлов: 539 добавлений и 1354 удалений

Просмотреть файл

@ -1,59 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#virtual-cursor-box {
position: fixed;
border: 1px solid orange;
pointer-events: none;
display: none;
border-radius: 2px;
box-shadow: 1px 1px 1px #444;
display: none;
z-index: 10;
}
#virtual-cursor-box.show {
display: block;
}
#virtual-cursor-box > div {
border-radius: 1px;
box-shadow: inset 1px 1px 1px #444;
display: block;
box-sizing: border-box;
width: 100%;
height: 100%;
pointer-events: none;
}
#announce-box {
position: fixed;
width: 7.5em;
height: 5em;
top: calc(100% - 50% - 2.5em);
left: calc(100% - 50% - 3.75em);
pointer-events: none;
display: table;
font-size: 28pt;
font-weight: 700;
color: orange;
background-color: black;
border-radius: 0.25em;
}
#announce-box:not(.showing) {
opacity: 0.0;
-moz-transition: opacity 0.4s linear;
}
#announce-box.showing {
opacity: 1.0;
-moz-transition: opacity 0.2s linear;
}
#announce-box * {
text-align: center;
display: table-cell;
vertical-align: middle;
}

Просмотреть файл

@ -8,6 +8,8 @@ var EXPORTED_SYMBOLS = ["AccessFu"];
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Rect",
"resource://gre/modules/Geometry.jsm");
if (Utils.MozBuildApp === "mobile/android") {
ChromeUtils.import("resource://gre/modules/Messaging.jsm");
@ -78,19 +80,10 @@ var AccessFu = {
this._loadFrameScript(mm);
}
// Add stylesheet
let stylesheetURL = "chrome://global/content/accessibility/AccessFu.css";
let stylesheet = Utils.win.document.createProcessingInstruction(
"xml-stylesheet", `href="${stylesheetURL}" type="text/css"`);
Utils.win.document.insertBefore(stylesheet, Utils.win.document.firstChild);
this.stylesheet = Cu.getWeakReference(stylesheet);
// Check for output notification
this._notifyOutputPref =
new PrefCache("accessibility.accessfu.notify_output");
Output.start();
if (Utils.MozBuildApp === "mobile/android") {
Utils.win.WindowEventDispatcher.registerListener(this,
Object.values(GECKOVIEW_MESSAGE));
@ -120,15 +113,11 @@ var AccessFu = {
this._enabled = false;
Utils.win.document.removeChild(this.stylesheet.get());
for (let mm of Utils.AllMessageManagers) {
mm.sendAsyncMessage("AccessFu:Stop");
this._removeMessageListeners(mm);
}
Output.stop();
Utils.win.removeEventListener("TabOpen", this);
Utils.win.removeEventListener("TabClose", this);
Utils.win.removeEventListener("TabSelect", this);
@ -177,20 +166,20 @@ var AccessFu = {
},
_output: function _output(aPresentationData, aBrowser) {
if (!Utils.isAliveAndVisible(
Utils.AccService.getAccessibleFor(aBrowser))) {
if (!aPresentationData || typeof aPresentationData == "string") {
// Either no android events to send or a string used for testing only.
return;
}
for (let presenter of aPresentationData) {
if (!presenter) {
continue;
}
try {
Output[presenter.type](presenter.details, aBrowser);
} catch (x) {
Logger.logException(x);
}
if (!Utils.isAliveAndVisible(Utils.AccService.getAccessibleFor(aBrowser))) {
return;
}
for (let evt of aPresentationData) {
Utils.win.WindowEventDispatcher.sendRequest({
...evt,
type: "GeckoView:AccessibilityEvent"
});
}
if (this._notifyOutputPref.value) {
@ -370,174 +359,6 @@ var AccessFu = {
}
};
var Output = {
brailleState: {
startOffset: 0,
endOffset: 0,
text: "",
selectionStart: 0,
selectionEnd: 0,
init: function init(aOutput) {
if (aOutput && "output" in aOutput) {
this.startOffset = aOutput.startOffset;
this.endOffset = aOutput.endOffset;
// We need to append a space at the end so that the routing key
// corresponding to the end of the output (i.e. the space) can be hit to
// move the caret there.
this.text = aOutput.output + " ";
this.selectionStart = typeof aOutput.selectionStart === "number" ?
aOutput.selectionStart : this.selectionStart;
this.selectionEnd = typeof aOutput.selectionEnd === "number" ?
aOutput.selectionEnd : this.selectionEnd;
return { text: this.text,
selectionStart: this.selectionStart,
selectionEnd: this.selectionEnd };
}
return null;
},
adjustText: function adjustText(aText) {
let newBraille = [];
let braille = {};
let prefix = this.text.substring(0, this.startOffset).trim();
if (prefix) {
prefix += " ";
newBraille.push(prefix);
}
newBraille.push(aText);
let suffix = this.text.substring(this.endOffset).trim();
if (suffix) {
suffix = " " + suffix;
newBraille.push(suffix);
}
this.startOffset = braille.startOffset = prefix.length;
this.text = braille.text = newBraille.join("") + " ";
this.endOffset = braille.endOffset = braille.text.length - suffix.length;
braille.selectionStart = this.selectionStart;
braille.selectionEnd = this.selectionEnd;
return braille;
},
adjustSelection: function adjustSelection(aSelection) {
let braille = {};
braille.startOffset = this.startOffset;
braille.endOffset = this.endOffset;
braille.text = this.text;
this.selectionStart = braille.selectionStart =
aSelection.selectionStart + this.startOffset;
this.selectionEnd = braille.selectionEnd =
aSelection.selectionEnd + this.startOffset;
return braille;
}
},
start: function start() {
ChromeUtils.import("resource://gre/modules/Geometry.jsm");
},
stop: function stop() {
if (this.highlightBox) {
let highlightBox = this.highlightBox.get();
if (highlightBox) {
highlightBox.remove();
}
delete this.highlightBox;
}
},
B2G: function B2G(aDetails) {
Utils.dispatchChromeEvent("accessibility-output", aDetails);
},
Visual: function Visual(aDetail, aBrowser) {
switch (aDetail.eventType) {
case "viewport-change":
case "vc-change":
{
let highlightBox = null;
if (!this.highlightBox) {
let doc = Utils.win.document;
// Add highlight box
highlightBox = Utils.win.document.
createElementNS("http://www.w3.org/1999/xhtml", "div");
let parent = doc.body || doc.documentElement;
parent.appendChild(highlightBox);
highlightBox.id = "virtual-cursor-box";
// Add highlight inset for inner shadow
highlightBox.appendChild(
doc.createElementNS("http://www.w3.org/1999/xhtml", "div"));
this.highlightBox = Cu.getWeakReference(highlightBox);
} else {
highlightBox = this.highlightBox.get();
}
let padding = aDetail.padding;
let r = AccessFu.screenToClientBounds(aDetail.bounds);
// First hide it to avoid flickering when changing the style.
highlightBox.classList.remove("show");
highlightBox.style.top = (r.top - padding) + "px";
highlightBox.style.left = (r.left - padding) + "px";
highlightBox.style.width = (r.width + padding * 2) + "px";
highlightBox.style.height = (r.height + padding * 2) + "px";
highlightBox.classList.add("show");
break;
}
case "tabstate-change":
{
let highlightBox = this.highlightBox ? this.highlightBox.get() : null;
if (highlightBox) {
highlightBox.classList.remove("show");
}
break;
}
}
},
Android: function Android(aDetails, aBrowser) {
const ANDROID_VIEW_TEXT_CHANGED = 0x10;
const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
for (let androidEvent of aDetails) {
androidEvent.type = "GeckoView:AccessibilityEvent";
switch (androidEvent.eventType) {
case ANDROID_VIEW_TEXT_CHANGED:
androidEvent.brailleOutput = this.brailleState.adjustText(
androidEvent.text);
break;
case ANDROID_VIEW_TEXT_SELECTION_CHANGED:
androidEvent.brailleOutput = this.brailleState.adjustSelection(
androidEvent.brailleOutput);
break;
default:
androidEvent.brailleOutput = this.brailleState.init(
androidEvent.brailleOutput);
break;
}
Utils.win.WindowEventDispatcher.sendRequest(androidEvent);
}
},
Braille: function Braille(aDetails) {
Logger.debug("Braille output: " + aDetails.output);
}
};
var Input = {
editState: {},
@ -592,8 +413,7 @@ var Input = {
activateCurrent: function activateCurrent(aData, aActivateIfKey = false) {
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
let offset = aData && typeof aData.keyIndex === "number" ?
aData.keyIndex - Output.brailleState.startOffset : -1;
let offset = 0;
mm.sendAsyncMessage("AccessFu:Activate",
{offset, activateIfKey: aActivateIfKey});

Просмотреть файл

@ -1,7 +1,23 @@
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
var EXPORTED_SYMBOLS = ["Roles", "Events", "Relations",
"Filters", "States", "Prefilters"];
"Filters", "States", "Prefilters", "AndroidEvents"];
const AndroidEvents = {
ANDROID_VIEW_CLICKED: 0x01,
ANDROID_VIEW_LONG_CLICKED: 0x02,
ANDROID_VIEW_SELECTED: 0x04,
ANDROID_VIEW_FOCUSED: 0x08,
ANDROID_VIEW_TEXT_CHANGED: 0x10,
ANDROID_WINDOW_STATE_CHANGED: 0x20,
ANDROID_VIEW_HOVER_ENTER: 0x80,
ANDROID_VIEW_HOVER_EXIT: 0x100,
ANDROID_VIEW_SCROLLED: 0x1000,
ANDROID_VIEW_TEXT_SELECTION_CHANGED: 0x2000,
ANDROID_ANNOUNCEMENT: 0x4000,
ANDROID_VIEW_ACCESSIBILITY_FOCUSED: 0x8000,
ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000,
};
function ConstantsMap(aObject, aPrefix, aMap = {}, aModifier = null) {
let offset = aPrefix.length;

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* exported UtteranceGenerator, BrailleGenerator */
/* exported UtteranceGenerator */
"use strict";
@ -26,7 +26,7 @@ ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
var EXPORTED_SYMBOLS = ["UtteranceGenerator", "BrailleGenerator"]; // jshint ignore:line
var EXPORTED_SYMBOLS = ["UtteranceGenerator"]; // jshint ignore:line
var OutputGenerator = {
@ -838,164 +838,3 @@ var UtteranceGenerator = { // jshint ignore:line
return utterance;
}
};
var BrailleGenerator = { // jshint ignore:line
__proto__: OutputGenerator, // jshint ignore:line
genForContext: function genForContext(aContext) {
let output = OutputGenerator.genForContext.apply(this, arguments);
let acc = aContext.accessible;
// add the static text indicating a list item; do this for both listitems or
// direct first children of listitems, because these are both common
// browsing scenarios
let addListitemIndicator = function addListitemIndicator(indicator = "*") {
output.unshift(indicator);
};
if (acc.indexInParent === 1 &&
acc.parent.role == Roles.LISTITEM &&
acc.previousSibling.role == Roles.STATICTEXT) {
if (acc.parent.parent && acc.parent.parent.DOMNode &&
acc.parent.parent.DOMNode.nodeName == "UL") {
addListitemIndicator();
} else {
addListitemIndicator(acc.previousSibling.name.trim());
}
} else if (acc.role == Roles.LISTITEM && acc.firstChild &&
acc.firstChild.role == Roles.STATICTEXT) {
if (acc.parent.DOMNode.nodeName == "UL") {
addListitemIndicator();
} else {
addListitemIndicator(acc.firstChild.name.trim());
}
}
return output;
},
objectOutputFunctions: {
__proto__: OutputGenerator.objectOutputFunctions, // jshint ignore:line
defaultFunc: function defaultFunc() {
return this.objectOutputFunctions._generateBaseOutput.apply(
this, arguments);
},
listitem: function listitem(aAccessible, aRoleStr, aState, aFlags) {
let braille = [];
this._addName(braille, aAccessible, aFlags);
this._addLandmark(braille, aAccessible);
return braille;
},
cell: function cell(aAccessible, aRoleStr, aState, aFlags, aContext) {
let braille = [];
let cell = aContext.getCellInfo(aAccessible);
if (cell) {
let addHeaders = function addHeaders(aBraille, aHeaders) {
if (aHeaders.length > 0) {
aBraille.push.apply(aBraille, aHeaders);
}
};
braille.push({
string: this._getOutputName("cellInfo"),
args: [cell.columnIndex + 1, cell.rowIndex + 1]
});
addHeaders(braille, cell.columnHeaders);
addHeaders(braille, cell.rowHeaders);
}
this._addName(braille, aAccessible, aFlags);
this._addLandmark(braille, aAccessible);
return braille;
},
columnheader: function columnheader() {
return this.objectOutputFunctions.cell.apply(this, arguments);
},
rowheader: function rowheader() {
return this.objectOutputFunctions.cell.apply(this, arguments);
},
statictext: function statictext(aAccessible) {
// Since we customize the list bullet's output, we add the static
// text from the first node in each listitem, so skip it here.
if (Utils.isListItemDecorator(aAccessible)) {
return [];
}
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
},
_useStateNotRole:
function _useStateNotRole(aAccessible, aRoleStr, aState, aFlags) {
let braille = [];
this._addState(braille, aState, aRoleStr);
this._addName(braille, aAccessible, aFlags);
this._addLandmark(braille, aAccessible);
return braille;
},
switch: function braille_generator_object_output_functions_switch() {
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
},
checkbutton: function checkbutton() {
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
},
radiobutton: function radiobutton() {
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
},
togglebutton: function togglebutton() {
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
}
},
_getContextStart: function _getContextStart(aContext) {
if (aContext.accessible.parent.role == Roles.LINK) {
return [aContext.accessible.parent];
}
return [];
},
_getOutputName: function _getOutputName(aName) {
return OutputGenerator._getOutputName(aName) + "Abbr";
},
_addRole: function _addRole(aBraille, aAccessible, aRoleStr) {
if (this.mathmlRolesSet.has(aAccessible.role)) {
this._addMathRoles(aBraille, aAccessible, aRoleStr);
} else {
aBraille.push({string: this._getOutputName(aRoleStr)});
}
},
_addState: function _addState(aBraille, aState, aRoleStr) {
if (aState.contains(States.CHECKABLE)) {
aBraille.push({
string: aState.contains(States.CHECKED) ?
this._getOutputName("stateChecked") :
this._getOutputName("stateUnchecked")
});
}
if (aRoleStr === "toggle button") {
aBraille.push({
string: aState.contains(States.PRESSED) ?
this._getOutputName("statePressed") :
this._getOutputName("stateUnpressed")
});
}
}
};

Просмотреть файл

@ -13,26 +13,20 @@ ChromeUtils.defineModuleGetter(this, "PivotContext", // jshint ignore:line
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "UtteranceGenerator", // jshint ignore:line
"resource://gre/modules/accessibility/OutputGenerator.jsm");
ChromeUtils.defineModuleGetter(this, "BrailleGenerator", // jshint ignore:line
"resource://gre/modules/accessibility/OutputGenerator.jsm");
ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "States", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "AndroidEvents", // jshint ignore:line
"resource://gre/modules/accessibility/Constants.jsm");
var EXPORTED_SYMBOLS = ["Presentation"]; // jshint ignore:line
/**
* The interface for all presenter classes. A presenter could be, for example,
* a speech output module, or a visual cursor indicator.
*/
function Presenter() {}
Presenter.prototype = {
/**
* The type of presenter. Used for matching it with the appropriate output method.
*/
type: "Base",
class AndroidPresentor {
constructor() {
this.type = "Android";
this.displayedAccessibles = new WeakMap();
}
/**
* The virtual cursor's position changed.
@ -42,211 +36,10 @@ Presenter.prototype = {
* See nsIAccessiblePivot.
* @param {bool} aIsFromUserInput the pivot change was invoked by the user
*/
pivotChanged: function pivotChanged(aContext, aReason, aIsFromUserInput) {}, // jshint ignore:line
/**
* An object's action has been invoked.
* @param {nsIAccessible} aObject the object that has been invoked.
* @param {string} aActionName the name of the action.
*/
actionInvoked: function actionInvoked(aObject, aActionName) {}, // jshint ignore:line
/**
* Text has changed, either by the user or by the system. TODO.
*/
textChanged: function textChanged(aAccessible, aIsInserted, aStartOffset, // jshint ignore:line
aLength, aText, aModifiedText) {}, // jshint ignore:line
/**
* Text selection has changed. TODO.
*/
textSelectionChanged: function textSelectionChanged(
aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput) {}, // jshint ignore:line
/**
* Selection has changed. TODO.
* @param {nsIAccessible} aObject the object that has been selected.
*/
selectionChanged: function selectionChanged(aObject) {}, // jshint ignore:line
/**
* Name has changed.
* @param {nsIAccessible} aAccessible the object whose value has changed.
*/
nameChanged: function nameChanged(aAccessible) {}, // jshint ignore: line
/**
* Value has changed.
* @param {nsIAccessible} aAccessible the object whose value has changed.
*/
valueChanged: function valueChanged(aAccessible) {}, // jshint ignore:line
/**
* The tab, or the tab's document state has changed.
* @param {nsIAccessible} aDocObj the tab document accessible that has had its
* state changed, or null if the tab has no associated document yet.
* @param {string} aPageState the state name for the tab, valid states are:
* 'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'.
*/
tabStateChanged: function tabStateChanged(aDocObj, aPageState) {}, // jshint ignore:line
/**
* The current tab has changed.
* @param {PivotContext} aDocContext context object for tab's
* document.
* @param {PivotContext} aVCContext context object for tab's current
* virtual cursor position.
*/
tabSelected: function tabSelected(aDocContext, aVCContext) {}, // jshint ignore:line
/**
* The viewport has changed, either a scroll, pan, zoom, or
* landscape/portrait toggle.
* @param {Window} aWindow window of viewport that changed.
* @param {PivotContext} aCurrentContext context of last pivot change.
*/
viewportChanged: function viewportChanged(aWindow, aCurrentContext) {}, // jshint ignore:line
/**
* We have entered or left text editing mode.
*/
editingModeChanged: function editingModeChanged(aIsEditing) {}, // jshint ignore:line
/**
* Announce something. Typically an app state change.
*/
announce: function announce(aAnnouncement) {}, // jshint ignore:line
/**
* User tried to move cursor forward or backward with no success.
* @param {string} aMoveMethod move method that was used (eg. 'moveNext').
*/
noMove: function noMove(aMoveMethod) {},
/**
* Announce a live region.
* @param {PivotContext} aContext context object for an accessible.
* @param {boolean} aIsPolite A politeness level for a live region.
* @param {boolean} aIsHide An indicator of hide/remove event.
* @param {string} aModifiedText Optional modified text.
*/
liveRegion: function liveRegionShown(aContext, aIsPolite, aIsHide, // jshint ignore:line
aModifiedText) {} // jshint ignore:line
};
/**
* Visual presenter. Draws a box around the virtual cursor's position.
*/
function VisualPresenter() {}
VisualPresenter.prototype = Object.create(Presenter.prototype);
VisualPresenter.prototype.type = "Visual";
/**
* The padding in pixels between the object and the highlight border.
*/
VisualPresenter.prototype.BORDER_PADDING = 2;
VisualPresenter.prototype.viewportChanged =
function VisualPresenter_viewportChanged(aWindow, aCurrentContext) {
if (!aCurrentContext) {
return null;
}
let currentAcc = aCurrentContext.accessibleForBounds;
let start = aCurrentContext.startOffset;
let end = aCurrentContext.endOffset;
if (Utils.isAliveAndVisible(currentAcc)) {
let bounds = (start === -1 && end === -1) ? Utils.getBounds(currentAcc) :
Utils.getTextBounds(currentAcc, start, end);
return {
type: this.type,
details: {
eventType: "viewport-change",
bounds,
padding: this.BORDER_PADDING
}
};
}
return null;
};
VisualPresenter.prototype.pivotChanged =
function VisualPresenter_pivotChanged(aContext) {
if (!aContext.accessible) {
// XXX: Don't hide because another vc may be using the highlight.
return null;
}
try {
aContext.accessibleForBounds.scrollTo(
Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
let bounds = (aContext.startOffset === -1 && aContext.endOffset === -1) ?
aContext.bounds : Utils.getTextBounds(aContext.accessibleForBounds,
aContext.startOffset,
aContext.endOffset);
return {
type: this.type,
details: {
eventType: "vc-change",
bounds,
padding: this.BORDER_PADDING
}
};
} catch (e) {
Logger.logException(e, "Failed to get bounds");
return null;
}
};
VisualPresenter.prototype.tabSelected =
function VisualPresenter_tabSelected(aDocContext, aVCContext) {
return this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
};
VisualPresenter.prototype.tabStateChanged =
function VisualPresenter_tabStateChanged(aDocObj, aPageState) {
if (aPageState == "newdoc") {
return {type: this.type, details: {eventType: "tabstate-change"}};
}
return null;
};
/**
* Android presenter. Fires Android a11y events.
*/
function AndroidPresenter() {}
AndroidPresenter.prototype = Object.create(Presenter.prototype);
AndroidPresenter.prototype.type = "Android";
// Android AccessibilityEvent type constants.
AndroidPresenter.prototype.ANDROID_VIEW_CLICKED = 0x01;
AndroidPresenter.prototype.ANDROID_VIEW_LONG_CLICKED = 0x02;
AndroidPresenter.prototype.ANDROID_VIEW_SELECTED = 0x04;
AndroidPresenter.prototype.ANDROID_VIEW_FOCUSED = 0x08;
AndroidPresenter.prototype.ANDROID_VIEW_TEXT_CHANGED = 0x10;
AndroidPresenter.prototype.ANDROID_WINDOW_STATE_CHANGED = 0x20;
AndroidPresenter.prototype.ANDROID_VIEW_HOVER_ENTER = 0x80;
AndroidPresenter.prototype.ANDROID_VIEW_HOVER_EXIT = 0x100;
AndroidPresenter.prototype.ANDROID_VIEW_SCROLLED = 0x1000;
AndroidPresenter.prototype.ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
AndroidPresenter.prototype.ANDROID_ANNOUNCEMENT = 0x4000;
AndroidPresenter.prototype.ANDROID_VIEW_ACCESSIBILITY_FOCUSED = 0x8000;
AndroidPresenter.prototype.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY =
0x20000;
AndroidPresenter.prototype.pivotChanged =
function AndroidPresenter_pivotChanged(aContext, aReason) {
if (!aContext.accessible) {
pivotChanged(aPosition, aOldPosition, aReason, aStartOffset, aEndOffset, aIsUserInput) {
let context = new PivotContext(
aPosition, aOldPosition, aStartOffset, aEndOffset);
if (!context.accessible) {
return null;
}
@ -255,57 +48,56 @@ AndroidPresenter.prototype.pivotChanged =
let isExploreByTouch = (aReason == Ci.nsIAccessiblePivot.REASON_POINT &&
Utils.AndroidSdkVersion >= 14);
let focusEventType = (Utils.AndroidSdkVersion >= 16) ?
this.ANDROID_VIEW_ACCESSIBILITY_FOCUSED :
this.ANDROID_VIEW_FOCUSED;
AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED :
AndroidEvents.ANDROID_VIEW_FOCUSED;
if (isExploreByTouch) {
// This isn't really used by TalkBack so this is a half-hearted attempt
// for now.
androidEvents.push({eventType: this.ANDROID_VIEW_HOVER_EXIT, text: []});
}
let brailleOutput = {};
if (Utils.AndroidSdkVersion >= 16) {
if (!this._braillePresenter) {
this._braillePresenter = new BraillePresenter();
}
brailleOutput = this._braillePresenter.pivotChanged(aContext, aReason).
details;
androidEvents.push({eventType: AndroidEvents.ANDROID_VIEW_HOVER_EXIT, text: []});
}
if (aReason === Ci.nsIAccessiblePivot.REASON_TEXT) {
if (Utils.AndroidSdkVersion >= 16) {
let adjustedText = aContext.textAndAdjustedOffsets;
let adjustedText = context.textAndAdjustedOffsets;
androidEvents.push({
eventType: this.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
text: [adjustedText.text],
fromIndex: adjustedText.startOffset,
toIndex: adjustedText.endOffset
});
}
} else {
let state = Utils.getState(aContext.accessible);
let state = Utils.getState(context.accessible);
androidEvents.push({eventType: (isExploreByTouch) ?
this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
AndroidEvents.ANDROID_VIEW_HOVER_ENTER : focusEventType,
text: Utils.localize(UtteranceGenerator.genForContext(
aContext)),
bounds: aContext.bounds,
clickable: aContext.accessible.actionCount > 0,
context)),
bounds: context.bounds,
clickable: context.accessible.actionCount > 0,
checkable: state.contains(States.CHECKABLE),
checked: state.contains(States.CHECKED),
brailleOutput});
checked: state.contains(States.CHECKED)});
}
try {
context.accessibleForBounds.scrollTo(
Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
} catch (e) {}
return {
type: this.type,
details: androidEvents
};
};
if (context.accessible) {
this.displayedAccessibles.set(context.accessible.document.window, context);
}
AndroidPresenter.prototype.actionInvoked =
function AndroidPresenter_actionInvoked(aObject, aActionName) {
return androidEvents;
}
/**
* An object's action has been invoked.
* @param {nsIAccessible} aObject the object that has been invoked.
* @param {string} aActionName the name of the action.
*/
actionInvoked(aObject, aActionName) {
let state = Utils.getState(aObject);
// Checkable objects use TalkBack's text derived from the event state,
@ -316,32 +108,19 @@ AndroidPresenter.prototype.actionInvoked =
aActionName));
}
return {
type: this.type,
details: [{
eventType: this.ANDROID_VIEW_CLICKED,
text,
checked: state.contains(States.CHECKED)
}]
};
};
return [{
eventType: AndroidEvents.ANDROID_VIEW_CLICKED,
text,
checked: state.contains(States.CHECKED)
}];
}
AndroidPresenter.prototype.tabSelected =
function AndroidPresenter_tabSelected(aDocContext, aVCContext) {
// Send a pivot change message with the full context utterance for this doc.
return this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
};
AndroidPresenter.prototype.tabStateChanged =
function AndroidPresenter_tabStateChanged(aDocObj, aPageState) {
return this.announce(
UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
};
AndroidPresenter.prototype.textChanged = function AndroidPresenter_textChanged(
aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
let eventDetails = {
eventType: this.ANDROID_VIEW_TEXT_CHANGED,
/**
* Text has changed, either by the user or by the system. TODO.
*/
textChanged(aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
let androidEvent = {
eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED,
text: [aText],
fromIndex: aStart,
removedCount: 0,
@ -349,37 +128,31 @@ AndroidPresenter.prototype.textChanged = function AndroidPresenter_textChanged(
};
if (aIsInserted) {
eventDetails.addedCount = aLength;
eventDetails.beforeText =
androidEvent.addedCount = aLength;
androidEvent.beforeText =
aText.substring(0, aStart) + aText.substring(aStart + aLength);
} else {
eventDetails.removedCount = aLength;
eventDetails.beforeText =
androidEvent.removedCount = aLength;
androidEvent.beforeText =
aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
}
return {type: this.type, details: [eventDetails]};
};
return [androidEvent];
}
AndroidPresenter.prototype.textSelectionChanged =
function AndroidPresenter_textSelectionChanged(aText, aStart, aEnd, aOldStart,
aOldEnd, aIsFromUserInput) {
/**
* Text selection has changed. TODO.
*/
textSelectionChanged(aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput) {
let androidEvents = [];
if (Utils.AndroidSdkVersion >= 14 && !aIsFromUserInput) {
if (!this._braillePresenter) {
this._braillePresenter = new BraillePresenter();
}
let brailleOutput = this._braillePresenter.textSelectionChanged(
aText, aStart, aEnd, aOldStart, aOldEnd, aIsFromUserInput).details;
androidEvents.push({
eventType: this.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
text: [aText],
fromIndex: aStart,
toIndex: aEnd,
itemCount: aText.length,
brailleOutput
itemCount: aText.length
});
}
@ -387,27 +160,80 @@ AndroidPresenter.prototype.textSelectionChanged =
let [from, to] = aOldStart < aStart ?
[aOldStart, aStart] : [aStart, aOldStart];
androidEvents.push({
eventType: this.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
text: [aText],
fromIndex: from,
toIndex: to
});
}
return {
type: this.type,
details: androidEvents
};
};
return androidEvents;
}
/**
* Selection has changed.
* XXX: Implement android event?
* @param {nsIAccessible} aObject the object that has been selected.
*/
selectionChanged(aObject) {
return "todo.selection-changed";
}
/**
* Name has changed.
* XXX: Implement android event?
* @param {nsIAccessible} aAccessible the object whose value has changed.
*/
nameChanged(aAccessible) {
return "todo.name-changed";
}
/**
* Value has changed.
* XXX: Implement android event?
* @param {nsIAccessible} aAccessible the object whose value has changed.
*/
valueChanged(aAccessible) {
return "todo.value-changed";
}
/**
* The tab, or the tab's document state has changed.
* @param {nsIAccessible} aDocObj the tab document accessible that has had its
* state changed, or null if the tab has no associated document yet.
* @param {string} aPageState the state name for the tab, valid states are:
* 'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'.
*/
tabStateChanged(aDocObj, aPageState) {
return this.announce(
UtteranceGenerator.genForTabStateChange(aDocObj, aPageState));
}
/**
* The current tab has changed.
* @param {PivotContext} aDocContext context object for tab's
* document.
* @param {PivotContext} aVCContext context object for tab's current
* virtual cursor position.
*/
tabSelected(aDocContext, aVCContext) {
return this.pivotChanged(aVCContext, Ci.nsIAccessiblePivot.REASON_NONE);
}
/**
* The viewport has changed, either a scroll, pan, zoom, or
* landscape/portrait toggle.
* @param {Window} aWindow window of viewport that changed.
*/
viewportChanged(aWindow) {
let currentContext = this.displayedAccessibles.get(aWindow);
AndroidPresenter.prototype.viewportChanged =
function AndroidPresenter_viewportChanged(aWindow, aCurrentContext) {
if (Utils.AndroidSdkVersion < 14) {
return null;
}
let events = [{
eventType: this.ANDROID_VIEW_SCROLLED,
eventType: AndroidEvents.ANDROID_VIEW_SCROLLED,
text: [],
scrollX: aWindow.scrollX,
scrollY: aWindow.scrollY,
@ -415,349 +241,68 @@ AndroidPresenter.prototype.viewportChanged =
maxScrollY: aWindow.scrollMaxY
}];
if (Utils.AndroidSdkVersion >= 16 && aCurrentContext) {
let currentAcc = aCurrentContext.accessibleForBounds;
if (Utils.AndroidSdkVersion >= 16 && currentContext) {
let currentAcc = currentContext.accessibleForBounds;
if (Utils.isAliveAndVisible(currentAcc)) {
events.push({
eventType: this.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
bounds: Utils.getBounds(currentAcc)
});
}
}
return {
type: this.type,
details: events
};
};
AndroidPresenter.prototype.editingModeChanged =
function AndroidPresenter_editingModeChanged(aIsEditing) {
return this.announce(UtteranceGenerator.genForEditingMode(aIsEditing));
};
AndroidPresenter.prototype.announce =
function AndroidPresenter_announce(aAnnouncement) {
let localizedAnnouncement = Utils.localize(aAnnouncement).join(" ");
return {
type: this.type,
details: [{
eventType: (Utils.AndroidSdkVersion >= 16) ?
this.ANDROID_ANNOUNCEMENT : this.ANDROID_VIEW_TEXT_CHANGED,
text: [localizedAnnouncement],
addedCount: localizedAnnouncement.length,
removedCount: 0,
fromIndex: 0
}]
};
};
AndroidPresenter.prototype.liveRegion =
function AndroidPresenter_liveRegion(aContext, aIsPolite,
aIsHide, aModifiedText) {
return this.announce(
UtteranceGenerator.genForLiveRegion(aContext, aIsHide, aModifiedText));
};
AndroidPresenter.prototype.noMove =
function AndroidPresenter_noMove(aMoveMethod) {
return {
type: this.type,
details: [
{ eventType: this.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
exitView: aMoveMethod,
text: [""]
}]
};
};
/**
* A B2G presenter for Gaia.
*/
function B2GPresenter() {}
B2GPresenter.prototype = Object.create(Presenter.prototype);
B2GPresenter.prototype.type = "B2G";
B2GPresenter.prototype.keyboardEchoSetting =
new PrefCache("accessibility.accessfu.keyboard_echo");
B2GPresenter.prototype.NO_ECHO = 0;
B2GPresenter.prototype.CHARACTER_ECHO = 1;
B2GPresenter.prototype.WORD_ECHO = 2;
B2GPresenter.prototype.CHARACTER_AND_WORD_ECHO = 3;
/**
* A pattern used for haptic feedback.
* @type {Array}
*/
B2GPresenter.prototype.PIVOT_CHANGE_HAPTIC_PATTERN = [40];
/**
* Pivot move reasons.
* @type {Array}
*/
B2GPresenter.prototype.pivotChangedReasons = ["none", "next", "prev", "first",
"last", "text", "point"];
B2GPresenter.prototype.pivotChanged =
function B2GPresenter_pivotChanged(aContext, aReason, aIsUserInput) {
if (!aContext.accessible) {
return null;
}
return {
type: this.type,
details: {
eventType: "vc-change",
data: UtteranceGenerator.genForContext(aContext),
options: {
pattern: this.PIVOT_CHANGE_HAPTIC_PATTERN,
isKey: Utils.isActivatableOnFingerUp(aContext.accessible),
reason: this.pivotChangedReasons[aReason],
isUserInput: aIsUserInput,
hints: aContext.interactionHints
}
}
};
};
B2GPresenter.prototype.nameChanged =
function B2GPresenter_nameChanged(aAccessible, aIsPolite = true) {
return {
type: this.type,
details: {
eventType: "name-change",
data: aAccessible.name,
options: {enqueue: aIsPolite}
}
};
};
B2GPresenter.prototype.valueChanged =
function B2GPresenter_valueChanged(aAccessible, aIsPolite = true) {
// the editable value changes are handled in the text changed presenter
if (Utils.getState(aAccessible).contains(States.EDITABLE)) {
return null;
}
return {
type: this.type,
details: {
eventType: "value-change",
data: aAccessible.value,
options: {enqueue: aIsPolite}
}
};
};
B2GPresenter.prototype.textChanged = function B2GPresenter_textChanged(
aAccessible, aIsInserted, aStart, aLength, aText, aModifiedText) {
let echoSetting = this.keyboardEchoSetting.value;
let text = "";
if (echoSetting == this.CHARACTER_ECHO ||
echoSetting == this.CHARACTER_AND_WORD_ECHO) {
text = aModifiedText;
}
// add word if word boundary is added
if ((echoSetting == this.WORD_ECHO ||
echoSetting == this.CHARACTER_AND_WORD_ECHO) &&
aIsInserted && aLength === 1) {
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
let startBefore = {}, endBefore = {};
let startAfter = {}, endAfter = {};
accText.getTextBeforeOffset(aStart,
Ci.nsIAccessibleText.BOUNDARY_WORD_END, startBefore, endBefore);
let maybeWord = accText.getTextBeforeOffset(aStart + 1,
Ci.nsIAccessibleText.BOUNDARY_WORD_END, startAfter, endAfter);
if (endBefore.value !== endAfter.value) {
text += maybeWord;
}
}
return {
type: this.type,
details: {
eventType: "text-change",
data: text
}
};
};
B2GPresenter.prototype.actionInvoked =
function B2GPresenter_actionInvoked(aObject, aActionName) {
return {
type: this.type,
details: {
eventType: "action",
data: UtteranceGenerator.genForAction(aObject, aActionName)
}
};
};
B2GPresenter.prototype.liveRegion = function B2GPresenter_liveRegion(aContext,
aIsPolite, aIsHide, aModifiedText) {
return {
type: this.type,
details: {
eventType: "liveregion-change",
data: UtteranceGenerator.genForLiveRegion(aContext, aIsHide,
aModifiedText),
options: {enqueue: aIsPolite}
}
};
};
B2GPresenter.prototype.announce =
function B2GPresenter_announce(aAnnouncement) {
return {
type: this.type,
details: {
eventType: "announcement",
data: aAnnouncement
}
};
};
B2GPresenter.prototype.noMove =
function B2GPresenter_noMove(aMoveMethod) {
return {
type: this.type,
details: {
eventType: "no-move",
data: aMoveMethod
}
};
};
/**
* A braille presenter
*/
function BraillePresenter() {}
BraillePresenter.prototype = Object.create(Presenter.prototype);
BraillePresenter.prototype.type = "Braille";
BraillePresenter.prototype.pivotChanged =
function BraillePresenter_pivotChanged(aContext) {
if (!aContext.accessible) {
return null;
}
return {
type: this.type,
details: {
output: Utils.localize(BrailleGenerator.genForContext(aContext)).join(
" "),
selectionStart: 0,
selectionEnd: 0
}
};
};
BraillePresenter.prototype.textSelectionChanged =
function BraillePresenter_textSelectionChanged(aText, aStart, aEnd) {
return {
type: this.type,
details: {
selectionStart: aStart,
selectionEnd: aEnd
}
};
};
var Presentation = { // jshint ignore:line
get presenters() {
delete this.presenters;
let presenterMap = {
"mobile/android": [VisualPresenter, AndroidPresenter],
"b2g": [VisualPresenter, B2GPresenter],
"browser": [VisualPresenter, B2GPresenter, AndroidPresenter]
};
this.presenters = presenterMap[Utils.MozBuildApp].map(P => new P());
return this.presenters;
},
get displayedAccessibles() {
delete this.displayedAccessibles;
this.displayedAccessibles = new WeakMap();
return this.displayedAccessibles;
},
pivotChanged: function Presentation_pivotChanged(
aPosition, aOldPosition, aReason, aStartOffset, aEndOffset, aIsUserInput) {
let context = new PivotContext(
aPosition, aOldPosition, aStartOffset, aEndOffset);
if (context.accessible) {
this.displayedAccessibles.set(context.accessible.document.window, context);
}
return this.presenters.map(p => p.pivotChanged(context, aReason, aIsUserInput));
},
actionInvoked: function Presentation_actionInvoked(aObject, aActionName) {
return this.presenters.map(p => p.actionInvoked(aObject, aActionName));
},
textChanged: function Presentation_textChanged(aAccessible, aIsInserted,
aStartOffset, aLength, aText,
aModifiedText) {
return this.presenters.map(p => p.textChanged(aAccessible, aIsInserted,
aStartOffset, aLength,
aText, aModifiedText));
},
textSelectionChanged: function textSelectionChanged(aText, aStart, aEnd,
aOldStart, aOldEnd,
aIsFromUserInput) {
return this.presenters.map(p => p.textSelectionChanged(aText, aStart, aEnd,
aOldStart, aOldEnd,
aIsFromUserInput));
},
nameChanged: function nameChanged(aAccessible) {
return this.presenters.map(p => p.nameChanged(aAccessible));
},
valueChanged: function valueChanged(aAccessible) {
return this.presenters.map(p => p.valueChanged(aAccessible));
},
tabStateChanged: function Presentation_tabStateChanged(aDocObj, aPageState) {
return this.presenters.map(p => p.tabStateChanged(aDocObj, aPageState));
},
viewportChanged: function Presentation_viewportChanged(aWindow) {
let context = this.displayedAccessibles.get(aWindow);
return this.presenters.map(p => p.viewportChanged(aWindow, context));
},
editingModeChanged: function Presentation_editingModeChanged(aIsEditing) {
return this.presenters.map(p => p.editingModeChanged(aIsEditing));
},
announce: function Presentation_announce(aAnnouncement) {
// XXX: Typically each presenter uses the UtteranceGenerator,
// but there really isn't a point here.
return this.presenters.map(p => p.announce(UtteranceGenerator.genForAnnouncement(aAnnouncement)));
},
noMove: function Presentation_noMove(aMoveMethod) {
return this.presenters.map(p => p.noMove(aMoveMethod));
},
liveRegion: function Presentation_liveRegion(aAccessible, aIsPolite, aIsHide,
aModifiedText) {
let context;
if (!aModifiedText) {
context = new PivotContext(aAccessible, null, -1, -1, true, !!aIsHide);
}
return this.presenters.map(p => p.liveRegion(context, aIsPolite, aIsHide,
aModifiedText));
return events;
}
};
/**
* We have entered or left text editing mode.
*/
editingModeChanged(aIsEditing) {
return this.announce(UtteranceGenerator.genForEditingMode(aIsEditing));
}
/**
* Announce something. Typically an app state change.
*/
announce(aAnnouncement) {
let localizedAnnouncement = Utils.localize(aAnnouncement).join(" ");
return [{
eventType: (Utils.AndroidSdkVersion >= 16) ?
AndroidEvents.ANDROID_ANNOUNCEMENT :
AndroidEvents.ANDROID_VIEW_TEXT_CHANGED,
text: [localizedAnnouncement],
addedCount: localizedAnnouncement.length,
removedCount: 0,
fromIndex: 0
}];
}
/**
* User tried to move cursor forward or backward with no success.
* @param {string} aMoveMethod move method that was used (eg. 'moveNext').
*/
noMove(aMoveMethod) {
return [{
eventType: AndroidEvents.ANDROID_VIEW_ACCESSIBILITY_FOCUSED,
exitView: aMoveMethod,
text: [""]
}];
}
/**
* Announce a live region.
* @param {PivotContext} aContext context object for an accessible.
* @param {boolean} aIsPolite A politeness level for a live region.
* @param {boolean} aIsHide An indicator of hide/remove event.
* @param {string} aModifiedText Optional modified text.
*/
liveRegion(aAccessible, aIsPolite, aIsHide, aModifiedText) {
let context = !aModifiedText ?
new PivotContext(aAccessible, null, -1, -1, true, !!aIsHide) : null;
return this.announce(
UtteranceGenerator.genForLiveRegion(context, aIsHide, aModifiedText));
}
}
const Presentation = new AndroidPresentor();

Просмотреть файл

@ -3,5 +3,4 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
toolkit.jar:
content/global/accessibility/AccessFu.css (AccessFu.css)
content/global/accessibility/content-script.js (content-script.js)

Просмотреть файл

@ -17,6 +17,7 @@ var gIterator;
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.import("resource://gre/modules/accessibility/EventManager.jsm");
ChromeUtils.import("resource://gre/modules/accessibility/Constants.jsm");
var AccessFuTest = {
@ -61,12 +62,13 @@ var AccessFuTest = {
_addObserver: function AccessFuTest__addObserver(aWaitForData, aListener) {
var listener = function listener(aSubject, aTopic, aData) {
var data = JSON.parse(aData)[1];
var data = JSON.parse(aData);
// Ignore non-relevant outputs.
if (!data) {
if (!data || (data[0] && data[0].text && data[0].text[0] == "new tab")) {
return;
}
isDeeply(data.details, aWaitForData, "Data is correct");
isDeeply(data, aWaitForData, "Data is correct (" + aData + ")");
aListener.apply(listener);
};
Services.obs.addObserver(listener, "accessibility-output");
@ -290,7 +292,7 @@ AccessFuContentTest.prototype = {
}
var actionsString = typeof this.currentAction === "function" ?
this.currentAction.name + "()" : JSON.stringify(this.currentAction);
this.currentAction.toString() : JSON.stringify(this.currentAction);
if (typeof expected === "string") {
ok(true, "Got " + expected + " after " + actionsString);
@ -472,6 +474,10 @@ ExpectedMessage.prototype.lazyCompare = function(aReceived, aExpected, aInfo) {
return [false, "Expected something but got nothing -- " + aInfo];
}
if (typeof aReceived === "string" || typeof aExpected === "string") {
return [aReceived == aExpected, `String comparison: Got '${aReceived}.', expected: ${aExpected} -- ${aInfo}`];
}
var matches = true;
var delta = [];
for (var attr in aExpected) {
@ -517,61 +523,39 @@ ExpectedMessage.prototype.ignore = function(aMessage) {
return aMessage.name !== this.name;
};
function ExpectedPresent(aB2g, aAndroid, aOptions) {
function ExpectedPresent(aAndroidEvents, aOptions) {
ExpectedMessage.call(this, "AccessFu:Present", aOptions);
if (aB2g) {
this.json.b2g = aB2g;
}
if (aAndroid) {
this.json.android = aAndroid;
}
this.expectedEvents = aAndroidEvents;
}
ExpectedPresent.prototype = Object.create(ExpectedMessage.prototype);
ExpectedPresent.prototype.is = function(aReceived, aInfo) {
var received = this.extract_presenters(aReceived);
for (var presenter of ["b2g", "android"]) {
if (!this.options["no_" + presenter]) {
var todo = this.options.todo || this.options[presenter + "_todo"];
SimpleTest[todo ? "todo" : "ok"].apply(
SimpleTest, this.lazyCompare(received[presenter],
this.json[presenter], aInfo + " (" + presenter + ")"));
}
}
};
ExpectedPresent.prototype.extract_presenters = function(aReceived) {
var received = { count: 0 };
for (var presenter of aReceived) {
if (presenter) {
received[presenter.type.toLowerCase()] = presenter.details;
received.count++;
if (typeof this.expectedEvents == "string") {
// This is an event we have yet to implement, do a simple string comparison.
if (this.expectedEvents == aReceived) {
SimpleTest.todo(false, `${aInfo} (${aReceived})`);
return;
}
}
return received;
SimpleTest[this.options.todo ? "todo" : "ok"].apply(SimpleTest,
this.lazyCompare(aReceived, this.expectedEvents, aInfo + " aReceived: " +
JSON.stringify(aReceived) + " evt: " + JSON.stringify(this.expectedEvents)));
};
ExpectedPresent.prototype.ignore = function(aMessage) {
if (ExpectedMessage.prototype.ignore.call(this, aMessage)) {
if (!aMessage.json || ExpectedMessage.prototype.ignore.call(this, aMessage)) {
return true;
}
var received = this.extract_presenters(aMessage.json);
return received.count === 0 ||
(received.visual && received.visual.eventType === "viewport-change") ||
(received.android &&
received.android[0].eventType === AndroidEvent.VIEW_SCROLLED);
let firstEvent = (aMessage.json || [])[0];
return firstEvent && firstEvent.eventType === AndroidEvents.ANDROID_VIEW_SCROLLED;
};
function ExpectedCursorChange(aSpeech, aOptions) {
ExpectedPresent.call(this, {
eventType: "vc-change",
data: aSpeech
}, [{
ExpectedPresent.call(this, [{
eventType: 0x8000, // VIEW_ACCESSIBILITY_FOCUSED
}], aOptions);
}
@ -579,11 +563,8 @@ function ExpectedCursorChange(aSpeech, aOptions) {
ExpectedCursorChange.prototype = Object.create(ExpectedPresent.prototype);
function ExpectedCursorTextChange(aSpeech, aStartOffset, aEndOffset, aOptions) {
ExpectedPresent.call(this, {
eventType: "vc-change",
data: aSpeech
}, [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: aStartOffset,
toIndex: aEndOffset
}], aOptions);
@ -596,22 +577,16 @@ ExpectedCursorTextChange.prototype =
Object.create(ExpectedCursorChange.prototype);
function ExpectedClickAction(aOptions) {
ExpectedPresent.call(this, {
eventType: "action",
data: [{ string: "clickAction" }]
}, [{
eventType: AndroidEvent.VIEW_CLICKED
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_VIEW_CLICKED
}], aOptions);
}
ExpectedClickAction.prototype = Object.create(ExpectedPresent.prototype);
function ExpectedCheckAction(aChecked, aOptions) {
ExpectedPresent.call(this, {
eventType: "action",
data: [{ string: aChecked ? "checkAction" : "uncheckAction" }]
}, [{
eventType: AndroidEvent.VIEW_CLICKED,
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_VIEW_CLICKED,
checked: aChecked
}], aOptions);
}
@ -619,40 +594,33 @@ function ExpectedCheckAction(aChecked, aOptions) {
ExpectedCheckAction.prototype = Object.create(ExpectedPresent.prototype);
function ExpectedSwitchAction(aSwitched, aOptions) {
ExpectedPresent.call(this, {
eventType: "action",
data: [{ string: aSwitched ? "onAction" : "offAction" }]
}, [{
eventType: AndroidEvent.VIEW_CLICKED,
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_VIEW_CLICKED,
checked: aSwitched
}], aOptions);
}
ExpectedSwitchAction.prototype = Object.create(ExpectedPresent.prototype);
// XXX: Implement Android event?
function ExpectedNameChange(aName, aOptions) {
ExpectedPresent.call(this, {
eventType: "name-change",
data: aName
}, null, aOptions);
ExpectedPresent.call(this, "todo.name-changed", aOptions);
}
ExpectedNameChange.prototype = Object.create(ExpectedPresent.prototype);
// XXX: Implement Android event?
function ExpectedValueChange(aValue, aOptions) {
ExpectedPresent.call(this, {
eventType: "value-change",
data: aValue
}, null, aOptions);
ExpectedPresent.call(this, "todo.value-changed", aOptions);
}
ExpectedValueChange.prototype = Object.create(ExpectedPresent.prototype);
// XXX: Implement Android event?
function ExpectedTextChanged(aValue, aOptions) {
ExpectedPresent.call(this, {
eventType: "text-change",
data: aValue
}, null, aOptions);
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_VIEW_TEXT_CHANGED
}], aOptions);
}
ExpectedTextChanged.prototype = Object.create(ExpectedPresent.prototype);
@ -665,20 +633,17 @@ function ExpectedEditState(aEditState, aOptions) {
ExpectedEditState.prototype = Object.create(ExpectedMessage.prototype);
function ExpectedTextSelectionChanged(aStart, aEnd, aOptions) {
ExpectedPresent.call(this, null, [{
eventType: AndroidEvent.VIEW_TEXT_SELECTION_CHANGED,
brailleOutput: {
selectionStart: aStart,
selectionEnd: aEnd
}}], aOptions);
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_VIEW_TEXT_SELECTION_CHANGED,
}], aOptions);
}
ExpectedTextSelectionChanged.prototype =
Object.create(ExpectedPresent.prototype);
function ExpectedTextCaretChanged(aFrom, aTo, aOptions) {
ExpectedPresent.call(this, null, [{
eventType: AndroidEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
fromIndex: aFrom,
toIndex: aTo
}], aOptions);
@ -687,8 +652,8 @@ function ExpectedTextCaretChanged(aFrom, aTo, aOptions) {
ExpectedTextCaretChanged.prototype = Object.create(ExpectedPresent.prototype);
function ExpectedAnnouncement(aAnnouncement, aOptions) {
ExpectedPresent.call(this, null, [{
eventType: AndroidEvent.ANNOUNCEMENT,
ExpectedPresent.call(this, [{
eventType: AndroidEvents.ANDROID_ANNOUNCEMENT,
text: [ aAnnouncement],
addedCount: aAnnouncement.length
}], aOptions);
@ -696,24 +661,9 @@ function ExpectedAnnouncement(aAnnouncement, aOptions) {
ExpectedAnnouncement.prototype = Object.create(ExpectedPresent.prototype);
// XXX: Implement Android event?
function ExpectedNoMove(aOptions) {
ExpectedPresent.call(this, {eventType: "no-move" }, null, aOptions);
ExpectedPresent.call(this, null, aOptions);
}
ExpectedNoMove.prototype = Object.create(ExpectedPresent.prototype);
var AndroidEvent = {
VIEW_CLICKED: 0x01,
VIEW_LONG_CLICKED: 0x02,
VIEW_SELECTED: 0x04,
VIEW_FOCUSED: 0x08,
VIEW_TEXT_CHANGED: 0x10,
WINDOW_STATE_CHANGED: 0x20,
VIEW_HOVER_ENTER: 0x80,
VIEW_HOVER_EXIT: 0x100,
VIEW_SCROLLED: 0x1000,
VIEW_TEXT_SELECTION_CHANGED: 0x2000,
ANNOUNCEMENT: 0x4000,
VIEW_ACCESSIBILITY_FOCUSED: 0x8000,
VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: 0x20000
};

Просмотреть файл

@ -84,20 +84,15 @@ function testObjectOutput(aAccOrElmOrID, aGenerator) {
* the |aAccOrElmOrID|.
* @param aOutputKind the type of output
*/
function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aOutputKind) {
var generator;
if (aOutputKind === 1) {
generator = UtteranceGenerator;
} else {
generator = BrailleGenerator;
}
testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, generator);
function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID,
UtteranceGenerator);
// Just need to test object output for individual
// accOrElmOrID.
if (aOldAccOrElmOrID) {
return;
}
testObjectOutput(aAccOrElmOrID, generator);
testObjectOutput(aAccOrElmOrID, UtteranceGenerator);
}
function testHints(expected, aAccOrElmOrID, aOldAccOrElmOrID) {

Просмотреть файл

@ -47,7 +47,7 @@
// check checkbox
[ContentMessages.activateCurrent(),
new ExpectedClickAction({ no_android: true }),
new ExpectedClickAction(),
new ExpectedCheckAction(true)],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(["much range", {"string": "label"}])],
@ -62,7 +62,7 @@
new ExpectedCursorChange(["Light", {"string": "stateOff"}, {"string": "switch"}])],
// switch on
[ContentMessages.activateCurrent(),
new ExpectedClickAction({ no_android: true }),
new ExpectedClickAction(),
new ExpectedSwitchAction(true)],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(["slider", "0", {"string": "slider"}])],
@ -72,7 +72,7 @@
new ExpectedCursorChange(["Light", {"string": "stateOn"}, {"string": "switch"}])],
// switch off
[ContentMessages.activateCurrent(),
new ExpectedClickAction({ no_android: true }),
new ExpectedClickAction(),
new ExpectedSwitchAction(false)],
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(["apple", {"string": "pushbutton"}])],
@ -91,7 +91,7 @@
{"string": "list"}, {"string": "listItemsCount", "count": 1}])],
// uncheck checkbox
[ContentMessages.activateCurrent(),
new ExpectedClickAction({ no_android: true }),
new ExpectedClickAction(),
new ExpectedCheckAction(false)],
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(["wow", {"string": "headingLevel", "args": [1]}])],
@ -110,7 +110,7 @@
// Move from an inner frame to the last element in the parent doc
[ContentMessages.simpleMoveLast,
new ExpectedCursorChange(
["slider", "0", {"string": "slider"}], { b2g_todo: true })],
["slider", "0", {"string": "slider"}])],
[ContentMessages.clearCursor, "AccessFu:CursorCleared"],
@ -153,7 +153,7 @@
{"string": "checkbutton"}, {"string": "listStart"},
{"string": "list"}, {"string": "listItemsCount", "count": 1}])],
[ContentMessages.simpleMoveFirst,
new ExpectedCursorChange(["Phone status bar"], { b2g_todo: true })],
new ExpectedCursorChange(["Phone status bar"])],
// Reset cursors
[ContentMessages.clearCursor, "AccessFu:CursorCleared"],

Просмотреть файл

@ -60,7 +60,7 @@
// XXX: Word boundary should be past the apostraphe.
[ContentMessages.moveNextBy("word"),
new ExpectedCursorTextChange("You're", 0, 6,
{ android_todo: true /* Bug 980512 */})],
{ todo: true /* Bug 980512 */})],
// Editable text tests.
[ContentMessages.focusSelector("textarea"),
@ -165,7 +165,7 @@
{ focused: "input[type=text]" }),
new ExpectedTextSelectionChanged(0, 0,
// Bug 1455749: Fix granularity control in text entries.
{ android_todo: true }
{ todo: true }
)],
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(
@ -194,74 +194,91 @@
},
new ExpectedTextChanged("a"),
new ExpectedTextSelectionChanged(1, 1),
new ExpectedValueChange(),
],
[typeKey("b"),
new ExpectedTextChanged("b"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(2, 2),
],
[typeKey("c"),
new ExpectedTextChanged("c"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(3, 3),
],
[typeKey("d"),
new ExpectedTextChanged("d"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(4, 4),
],
[typeKey(" "),
new ExpectedTextChanged(" abcd"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(5, 5),
],
[typeKey("e"),
new ExpectedTextChanged("e"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(6, 6),
],
[function() {
SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 2]]}, typeKey("a")());
},
new ExpectedTextChanged(""),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(7, 7),
],
[typeKey("d"),
new ExpectedTextChanged(""),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(8, 8),
],
[typeKey(" "),
new ExpectedTextChanged(" ead"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(9, 9),
],
[function() {
SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 1]]}, typeKey("f")());
},
new ExpectedTextChanged("f"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(10, 10),
],
[typeKey("g"),
new ExpectedTextChanged("g"),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(11, 11),
],
[typeKey(" "),
new ExpectedTextChanged(" "),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(12, 12),
],
[function() {
SpecialPowers.pushPrefEnv({"set": [[KEYBOARD_ECHO_SETTING, 0]]}, typeKey("f")());
},
new ExpectedTextChanged(""),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(13, 13),
],
[typeKey("g"),
new ExpectedTextChanged(""),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(14, 14),
],
[typeKey(" "),
new ExpectedTextChanged(""),
new ExpectedValueChange(),
new ExpectedTextSelectionChanged(15, 15),
],
]);
const KEYBOARD_ECHO_SETTING = "accessibility.accessfu.keyboard_echo";
function typeKey(key) {
return function() { synthesizeKey(key, {}, currentTabWindow()); };
let func = function() { synthesizeKey(key, {}, currentTabWindow()); };
func.toString = () => `typeKey('${key}')`;
return func;
}
addA11yLoadEvent(function() {

Просмотреть файл

@ -114,7 +114,7 @@
SpecialPowers.pushPrefEnv({"set": [[PREF_UTTERANCE_ORDER, 0]]}, function() {
// Test various explicit names vs the utterance generated from subtrees.
tests.forEach(function run(test) {
testOutput(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID, 1);
testOutput(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID);
});
SimpleTest.finish();
});

Просмотреть файл

@ -126,9 +126,7 @@
}, function() {
tests.forEach(function run(test) {
testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 1);
testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 0);
test.oldAccOrElmOrID);
});
AccessFuTest.nextTest();
});

Просмотреть файл

@ -12,7 +12,6 @@
<script type="application/javascript"
src="./jsatcommon.js"></script>
<script type="application/javascript">
function startAccessFu() {
AccessFuTest.once_log("EventManager.start", AccessFuTest.nextTest);
AccessFu._enable();
@ -57,271 +56,343 @@
}
var tests = [{
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden I will be hidden"],
"addedCount": "hidden I will be hidden".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_hide1", "to_hide2", "to_hide3", "to_hide4"].forEach(id => hide(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden I will be hidden"],
"addedCount": "hidden I will be hidden".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_hide_descendant1", "to_hide_descendant2",
"to_hide_descendant3", "to_hide_descendant4"].forEach(id => hide(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I will be shown"],
"addedCount": "I will be shown".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_show1", "to_show2", "to_show3", "to_show4"].forEach(id => show(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I will be shown"],
"addedCount": "I will be shown".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_show_descendant1", "to_show_descendant2",
"to_show_descendant3", "to_show_descendant4"].forEach(id => show(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden I will be hidden"],
"addedCount": "hidden I will be hidden".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_hide5", "to_hide6", "to_hide7", "to_hide8", "to_hide9"].forEach(id => ariaHide(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden I will be hidden"],
"addedCount": "hidden I will be hidden".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_hide_descendant5", "to_hide_descendant6",
"to_hide_descendant7", "to_hide_descendant8"].forEach(id => ariaHide(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I will be shown"],
"addedCount": "I will be shown".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_show5", "to_show6", "to_show7", "to_show8", "to_show9"].forEach(id => ariaShow(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I will be shown"],
"addedCount": "I will be shown".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
["to_show_descendant5", "to_show_descendant6",
"to_show_descendant7", "to_show_descendant8"].forEach(id => ariaShow(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden I will be hidden"],
"addedCount": "hidden I will be hidden".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
hide("to_hide_live_assertive");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "I will be hidden"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden I will be hidden"],
"addedCount": "hidden I will be hidden".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
ariaHide("to_hide_live_assertive2");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I will be shown"],
"addedCount": "I will be shown".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
["to_show_live_off", "to_show_live_assertive"].forEach(id => show(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I will be shown"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I will be shown"],
"addedCount": "I will be shown".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
["to_show_live_off2", "to_show_live_assertive2"].forEach(id => ariaShow(id));
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["Text Added"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["Text Added"],
"addedCount": "Text Added".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateText("text_add", "Text Added");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["Text Added"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["Text Added"],
"addedCount": "Text Added".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateHTML("text_add", "Text Added");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "Text Removed"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden Text Removed"],
"addedCount": "hidden Text Removed".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
updateText("text_remove", "");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["Descendant Text Added"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["Descendant Text Added"],
"addedCount": "Descendant Text Added".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateText("text_add_descendant", "Descendant Text Added");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["Descendant Text Added"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["Descendant Text Added"],
"addedCount": "Descendant Text Added".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateHTML("text_add_descendant", "Descendant Text Added");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "Descendant Text Removed"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden Descendant Text Removed"],
"addedCount": "hidden Descendant Text Removed".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
updateText("text_remove_descendant", "");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["Descendant Text Added"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["Descendant Text Added"],
"addedCount": "Descendant Text Added".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateText("text_add_descendant2", "Descendant Text Added");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["Descendant Text Added"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["Descendant Text Added"],
"addedCount": "Descendant Text Added".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateHTML("text_add_descendant2", "Descendant Text Added");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": [{"string": "hidden"}, "Descendant Text Removed"],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["hidden Descendant Text Removed"],
"addedCount": "hidden Descendant Text Removed".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
updateText("text_remove_descendant2", "");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I am replaced", {"string": "main"}],
"options": {
"enqueue": true
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I am replaced main"],
"addedCount": "I am replaced main".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": true
// }
}],
action: function action() {
var child = document.getElementById("to_replace");
child.setAttribute("role", "main");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I am a replaced text"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I am a replaced text"],
"addedCount": "I am a replaced text".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateText("to_replace_text", "I am a replaced text");
}
}, {
expected: {
"eventType": "liveregion-change",
"data": ["I am a replaced text"],
"options": {
"enqueue": false
}
},
expected: [{
"eventType": AndroidEvents.ANDROID_ANNOUNCEMENT,
"text": ["I am a replaced text"],
"addedCount": "I am a replaced text".length,
"removedCount": 0,
"fromIndex": 0,
// "options": {
// "enqueue": false
// }
}],
action: function action() {
updateHTML("to_replace_text", "I am a replaced text");
}

Просмотреть файл

@ -507,9 +507,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
}, function() {
tests.forEach(function run(test) {
testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 1);
testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 0);
test.oldAccOrElmOrID);
});
AccessFuTest.nextTest();
});

Просмотреть файл

@ -176,9 +176,7 @@
}, function() {
tests.forEach(function run(test) {
testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 1);
testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 0);
test.oldAccOrElmOrID);
});
AccessFuTest.nextTest();
});

Просмотреть файл

@ -483,9 +483,7 @@
}, function() {
tests.forEach(function run(test) {
testOutput(test.expectedUtterance[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 1);
testOutput(test.expectedBraille[aOutputOrder], test.accOrElmOrID,
test.oldAccOrElmOrID, 0);
test.oldAccOrElmOrID);
});
AccessFuTest.nextTest();
});