зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1561435 - Format accessible/, a=automatic-formatting
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D35895 --HG-- extra : source : e786ed0773342d7c897007bb1be5a101945b894a
This commit is contained in:
Родитель
10375c0418
Коммит
058dce8bba
|
@ -44,7 +44,6 @@ module.exports = {
|
|||
],
|
||||
"overrides": [{
|
||||
"files": [
|
||||
"accessible/**",
|
||||
"browser/**",
|
||||
"build/**",
|
||||
"caps/**",
|
||||
|
|
|
@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
|
|||
toolkit/components/telemetry/healthreport-prefs.js
|
||||
|
||||
# Ignore all top-level directories for now.
|
||||
accessible/**
|
||||
browser/**
|
||||
build/**
|
||||
caps/**
|
||||
|
|
|
@ -6,10 +6,15 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["AccessFu"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Logger, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Rect",
|
||||
"resource://gre/modules/Geometry.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Logger, Utils } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Rect",
|
||||
"resource://gre/modules/Geometry.jsm"
|
||||
);
|
||||
|
||||
const GECKOVIEW_MESSAGE = {
|
||||
ACTIVATE: "GeckoView:AccessibilityActivate",
|
||||
|
@ -121,8 +126,10 @@ var AccessFu = {
|
|||
};
|
||||
this._eventDispatcherListeners.set(win, listener);
|
||||
// desktop mochitests don't have this.
|
||||
win.WindowEventDispatcher.registerListener(listener,
|
||||
Object.values(GECKOVIEW_MESSAGE));
|
||||
win.WindowEventDispatcher.registerListener(
|
||||
listener,
|
||||
Object.values(GECKOVIEW_MESSAGE)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -139,7 +146,8 @@ var AccessFu = {
|
|||
// desktop mochitests don't have this.
|
||||
win.WindowEventDispatcher.unregisterListener(
|
||||
this._eventDispatcherListeners.get(win),
|
||||
Object.values(GECKOVIEW_MESSAGE));
|
||||
Object.values(GECKOVIEW_MESSAGE)
|
||||
);
|
||||
this._eventDispatcherListeners.delete(win);
|
||||
}
|
||||
},
|
||||
|
@ -157,7 +165,8 @@ var AccessFu = {
|
|||
case GECKOVIEW_MESSAGE.PREVIOUS: {
|
||||
let rule = "Simple";
|
||||
if (data && data.rule && data.rule.length) {
|
||||
rule = data.rule.substr(0, 1).toUpperCase() +
|
||||
rule =
|
||||
data.rule.substr(0, 1).toUpperCase() +
|
||||
data.rule.substr(1).toLowerCase();
|
||||
}
|
||||
let method = event.replace(/GeckoView:Accessibility(\w+)/, "move$1");
|
||||
|
@ -198,9 +207,13 @@ var AccessFu = {
|
|||
switch (aTopic) {
|
||||
case "domwindowopened": {
|
||||
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
win.addEventListener("load", () => {
|
||||
this._attachWindow(win);
|
||||
}, { once: true });
|
||||
win.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
this._attachWindow(win);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -208,8 +221,7 @@ var AccessFu = {
|
|||
|
||||
_handleEvent: function _handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "TabSelect":
|
||||
{
|
||||
case "TabSelect": {
|
||||
if (this._focused) {
|
||||
// We delay this for half a second so the awesomebar could close,
|
||||
// and we could use the current coordinates for the content item.
|
||||
|
@ -218,7 +230,8 @@ var AccessFu = {
|
|||
delay: 500,
|
||||
forcePresent: true,
|
||||
noOpIfOnScreen: true,
|
||||
moveMethod: "moveFirst" });
|
||||
moveMethod: "moveFirst",
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -247,36 +260,48 @@ var AccessFu = {
|
|||
* @param {Window} aWindow the window containing the item
|
||||
*/
|
||||
screenToClientBounds(aJsonBounds, aWindow) {
|
||||
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
|
||||
aJsonBounds.right - aJsonBounds.left,
|
||||
aJsonBounds.bottom - aJsonBounds.top);
|
||||
let { devicePixelRatio, mozInnerScreenX, mozInnerScreenY } = aWindow;
|
||||
let bounds = new Rect(
|
||||
aJsonBounds.left,
|
||||
aJsonBounds.top,
|
||||
aJsonBounds.right - aJsonBounds.left,
|
||||
aJsonBounds.bottom - aJsonBounds.top
|
||||
);
|
||||
let { devicePixelRatio, mozInnerScreenX, mozInnerScreenY } = aWindow;
|
||||
|
||||
bounds = bounds.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
|
||||
bounds = bounds.translate(-mozInnerScreenX, -mozInnerScreenY);
|
||||
return bounds.expandToIntegers();
|
||||
},
|
||||
bounds = bounds.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
|
||||
bounds = bounds.translate(-mozInnerScreenX, -mozInnerScreenY);
|
||||
return bounds.expandToIntegers();
|
||||
},
|
||||
};
|
||||
|
||||
var Input = {
|
||||
moveToPoint: function moveToPoint(aRule, aX, aY, aWindow) {
|
||||
Logger.debug("moveToPoint", aX, aY);
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:MoveToPoint",
|
||||
{rule: aRule, x: aX, y: aY, origin: "top"});
|
||||
mm.sendAsyncMessage("AccessFu:MoveToPoint", {
|
||||
rule: aRule,
|
||||
x: aX,
|
||||
y: aY,
|
||||
origin: "top",
|
||||
});
|
||||
},
|
||||
|
||||
moveCursor: function moveCursor(aAction, aRule, aInputType, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:MoveCursor",
|
||||
{ action: aAction, rule: aRule,
|
||||
origin: "top", inputType: aInputType });
|
||||
mm.sendAsyncMessage("AccessFu:MoveCursor", {
|
||||
action: aAction,
|
||||
rule: aRule,
|
||||
origin: "top",
|
||||
inputType: aInputType,
|
||||
});
|
||||
},
|
||||
|
||||
androidScroll: function androidScroll(aDirection, aWindow) {
|
||||
const mm = Utils.getCurrentMessageManager(aWindow);
|
||||
mm.sendAsyncMessage("AccessFu:AndroidScroll",
|
||||
{ direction: aDirection, origin: "top" });
|
||||
mm.sendAsyncMessage("AccessFu:AndroidScroll", {
|
||||
direction: aDirection,
|
||||
origin: "top",
|
||||
});
|
||||
},
|
||||
|
||||
moveByGranularity: function moveByGranularity(aDetails, aWindow) {
|
||||
|
@ -305,9 +330,18 @@ var Input = {
|
|||
let win = aBrowser.ownerGlobal;
|
||||
let winUtils = win.windowUtils;
|
||||
let p = AccessFu.screenToClientBounds(aDetails.bounds, win).center();
|
||||
winUtils.sendWheelEvent(p.x, p.y,
|
||||
horizontal ? page : 0, horizontal ? 0 : page, 0,
|
||||
win.WheelEvent.DOM_DELTA_PAGE, 0, 0, 0, 0);
|
||||
winUtils.sendWheelEvent(
|
||||
p.x,
|
||||
p.y,
|
||||
horizontal ? page : 0,
|
||||
horizontal ? 0 : page,
|
||||
0,
|
||||
win.WheelEvent.DOM_DELTA_PAGE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
},
|
||||
};
|
||||
AccessFu.Input = Input;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const AndroidEvents = {
|
||||
VIEW_CLICKED: 0x01,
|
||||
|
@ -21,53 +23,51 @@ function ConstantsMap(aObject, aPrefix, aMap = {}, aModifier = null) {
|
|||
let offset = aPrefix.length;
|
||||
for (var name in aObject) {
|
||||
if (name.indexOf(aPrefix) === 0) {
|
||||
aMap[name.slice(offset)] = aModifier ?
|
||||
aModifier(aObject[name]) : aObject[name];
|
||||
aMap[name.slice(offset)] = aModifier
|
||||
? aModifier(aObject[name])
|
||||
: aObject[name];
|
||||
}
|
||||
}
|
||||
|
||||
return aMap;
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this, "Roles",
|
||||
function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleRole, "ROLE_");
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "Roles", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleRole, "ROLE_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this, "Events",
|
||||
function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleEvent, "EVENT_");
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "Events", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleEvent, "EVENT_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this, "Relations",
|
||||
function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleRelation, "RELATION_");
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "Relations", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleRelation, "RELATION_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this, "Prefilters",
|
||||
function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "PREFILTER_");
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "Prefilters", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "PREFILTER_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this, "Filters",
|
||||
function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "FILTER_");
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "Filters", function() {
|
||||
return ConstantsMap(Ci.nsIAccessibleTraversalRule, "FILTER_");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
this, "States",
|
||||
function() {
|
||||
let statesMap = ConstantsMap(Ci.nsIAccessibleStates, "STATE_", {},
|
||||
(val) => { return { base: val, extended: 0 }; });
|
||||
ConstantsMap(Ci.nsIAccessibleStates, "EXT_STATE_", statesMap,
|
||||
(val) => { return { base: 0, extended: val }; });
|
||||
return statesMap;
|
||||
XPCOMUtils.defineLazyGetter(this, "States", function() {
|
||||
let statesMap = ConstantsMap(Ci.nsIAccessibleStates, "STATE_", {}, val => {
|
||||
return { base: val, extended: 0 };
|
||||
});
|
||||
ConstantsMap(Ci.nsIAccessibleStates, "EXT_STATE_", statesMap, val => {
|
||||
return { base: 0, extended: val };
|
||||
});
|
||||
return statesMap;
|
||||
});
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Roles", "Events", "Relations",
|
||||
"Filters", "States", "Prefilters", "AndroidEvents"];
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"Roles",
|
||||
"Events",
|
||||
"Relations",
|
||||
"Filters",
|
||||
"States",
|
||||
"Prefilters",
|
||||
"AndroidEvents",
|
||||
];
|
||||
|
|
|
@ -2,18 +2,36 @@
|
|||
* 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/. */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Roles",
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "States",
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "TraversalRules",
|
||||
"resource://gre/modules/accessibility/Traversal.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "TraversalHelper",
|
||||
"resource://gre/modules/accessibility/Traversal.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Roles",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"States",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"TraversalRules",
|
||||
"resource://gre/modules/accessibility/Traversal.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"TraversalHelper",
|
||||
"resource://gre/modules/accessibility/Traversal.jsm"
|
||||
);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ContentControl"];
|
||||
|
||||
|
@ -31,15 +49,17 @@ function ContentControl(aContentScope) {
|
|||
}
|
||||
|
||||
this.ContentControl.prototype = {
|
||||
messagesOfInterest: ["AccessFu:Activate",
|
||||
"AccessFu:AndroidScroll",
|
||||
"AccessFu:AutoMove",
|
||||
"AccessFu:ClearCursor",
|
||||
"AccessFu:Clipboard",
|
||||
"AccessFu:MoveByGranularity",
|
||||
"AccessFu:MoveCursor",
|
||||
"AccessFu:MoveToPoint",
|
||||
"AccessFu:SetSelection"],
|
||||
messagesOfInterest: [
|
||||
"AccessFu:Activate",
|
||||
"AccessFu:AndroidScroll",
|
||||
"AccessFu:AutoMove",
|
||||
"AccessFu:ClearCursor",
|
||||
"AccessFu:Clipboard",
|
||||
"AccessFu:MoveByGranularity",
|
||||
"AccessFu:MoveCursor",
|
||||
"AccessFu:MoveToPoint",
|
||||
"AccessFu:SetSelection",
|
||||
],
|
||||
|
||||
start: function cc_start() {
|
||||
let cs = this._contentScope.get();
|
||||
|
@ -69,9 +89,11 @@ this.ContentControl.prototype = {
|
|||
|
||||
receiveMessage: function cc_receiveMessage(aMessage) {
|
||||
Logger.debug(() => {
|
||||
return ["ContentControl.receiveMessage",
|
||||
return [
|
||||
"ContentControl.receiveMessage",
|
||||
aMessage.name,
|
||||
JSON.stringify(aMessage.json)];
|
||||
JSON.stringify(aMessage.json),
|
||||
];
|
||||
});
|
||||
|
||||
// If we get an explicit message, we should immediately cancel any autoMove
|
||||
|
@ -86,7 +108,9 @@ this.ContentControl.prototype = {
|
|||
}
|
||||
} catch (x) {
|
||||
Logger.logException(
|
||||
x, "Error handling message: " + JSON.stringify(aMessage.json));
|
||||
x,
|
||||
"Error handling message: " + JSON.stringify(aMessage.json)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -105,10 +129,11 @@ this.ContentControl.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
this._contentScope.get().sendAsyncMessage("AccessFu:DoScroll",
|
||||
{ bounds: Utils.getBounds(position),
|
||||
page: aMessage.json.direction === "forward" ? 1 : -1,
|
||||
horizontal: false });
|
||||
this._contentScope.get().sendAsyncMessage("AccessFu:DoScroll", {
|
||||
bounds: Utils.getBounds(position),
|
||||
page: aMessage.json.direction === "forward" ? 1 : -1,
|
||||
horizontal: false,
|
||||
});
|
||||
},
|
||||
|
||||
handleMoveCursor: function cc_handleMoveCursor(aMessage) {
|
||||
|
@ -132,7 +157,9 @@ this.ContentControl.prototype = {
|
|||
if (origin === "child") {
|
||||
// We just stepped out of a child, clear child cursor.
|
||||
Utils.getMessageManagerForFrame(aMessage.target).sendAsyncMessage(
|
||||
"AccessFu:ClearCursor", {});
|
||||
"AccessFu:ClearCursor",
|
||||
{}
|
||||
);
|
||||
} else {
|
||||
// We potentially landed on a new child cursor. If so, we want to
|
||||
// either be on the first or last item in the child doc.
|
||||
|
@ -147,8 +174,10 @@ this.ContentControl.prototype = {
|
|||
// new position.
|
||||
this.sendToChild(vc, aMessage, { action: childAction }, true);
|
||||
}
|
||||
} else if (!this._childMessageSenders.has(aMessage.target) &&
|
||||
origin !== "top") {
|
||||
} else if (
|
||||
!this._childMessageSenders.has(aMessage.target) &&
|
||||
origin !== "top"
|
||||
) {
|
||||
// We failed to move, and the message is not from a parent, so forward
|
||||
// to it.
|
||||
this.sendToParent(aMessage);
|
||||
|
@ -176,7 +205,7 @@ this.ContentControl.prototype = {
|
|||
},
|
||||
|
||||
handleActivate: function cc_handleActivate(aMessage) {
|
||||
let activateAccessible = (aAccessible) => {
|
||||
let activateAccessible = aAccessible => {
|
||||
Logger.debug(() => {
|
||||
return ["activateAccessible", Logger.accessibleToString(aAccessible)];
|
||||
});
|
||||
|
@ -194,30 +223,55 @@ this.ContentControl.prototype = {
|
|||
// Could possibly be made simpler in the future. Maybe core
|
||||
// engine could expose nsCoreUtiles::DispatchMouseEvent()?
|
||||
let docAcc = Utils.AccService.getAccessibleFor(this.document);
|
||||
let docX = {}, docY = {}, docW = {}, docH = {};
|
||||
let docX = {},
|
||||
docY = {},
|
||||
docW = {},
|
||||
docH = {};
|
||||
docAcc.getBounds(docX, docY, docW, docH);
|
||||
|
||||
let objX = {}, objY = {}, objW = {}, objH = {};
|
||||
let objX = {},
|
||||
objY = {},
|
||||
objW = {},
|
||||
objH = {};
|
||||
aAccessible.getBounds(objX, objY, objW, objH);
|
||||
|
||||
let x = Math.round((objX.value - docX.value) + objW.value / 2);
|
||||
let y = Math.round((objY.value - docY.value) + objH.value / 2);
|
||||
let x = Math.round(objX.value - docX.value + objW.value / 2);
|
||||
let y = Math.round(objY.value - docY.value + objH.value / 2);
|
||||
|
||||
let node = aAccessible.DOMNode || aAccessible.parent.DOMNode;
|
||||
|
||||
for (let eventType of ["mousedown", "mouseup"]) {
|
||||
let evt = this.document.createEvent("MouseEvents");
|
||||
evt.initMouseEvent(eventType, true, true, this.window,
|
||||
x, y, 0, 0, 0, false, false, false, false, 0, null);
|
||||
evt.initMouseEvent(
|
||||
eventType,
|
||||
true,
|
||||
true,
|
||||
this.window,
|
||||
x,
|
||||
y,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
0,
|
||||
null
|
||||
);
|
||||
node.dispatchEvent(evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement);
|
||||
if (focusedAcc && this.vc.position === focusedAcc
|
||||
&& focusedAcc.role === Roles.ENTRY) {
|
||||
this.document.activeElement
|
||||
);
|
||||
if (
|
||||
focusedAcc &&
|
||||
this.vc.position === focusedAcc &&
|
||||
focusedAcc.role === Roles.ENTRY
|
||||
) {
|
||||
let accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
|
||||
let newOffset = aMessage.json.offset;
|
||||
if (newOffset >= 0 && newOffset <= accText.characterCount) {
|
||||
|
@ -228,7 +282,7 @@ this.ContentControl.prototype = {
|
|||
}
|
||||
|
||||
// recursively find a descendant that is activatable.
|
||||
let getActivatableDescendant = (aAccessible) => {
|
||||
let getActivatableDescendant = aAccessible => {
|
||||
if (aAccessible.actionCount > 0) {
|
||||
return aAccessible;
|
||||
}
|
||||
|
@ -273,7 +327,17 @@ this.ContentControl.prototype = {
|
|||
let evt = this.document.createEvent("KeyboardEvent");
|
||||
let keycode = aStepUp ? evt.DOM_VK_DOWN : evt.DOM_VK_UP;
|
||||
evt.initKeyEvent(
|
||||
"keypress", false, true, null, false, false, false, false, keycode, 0);
|
||||
"keypress",
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
keycode,
|
||||
0
|
||||
);
|
||||
elem.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
|
@ -282,11 +346,13 @@ this.ContentControl.prototype = {
|
|||
|
||||
handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
|
||||
const { direction, granularity, select } = aMessage.json;
|
||||
const focusedAcc =
|
||||
Utils.AccService.getAccessibleFor(this.document.activeElement);
|
||||
const focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement
|
||||
);
|
||||
const editable =
|
||||
focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE) ?
|
||||
focusedAcc.QueryInterface(Ci.nsIAccessibleText) : null;
|
||||
focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE)
|
||||
? focusedAcc.QueryInterface(Ci.nsIAccessibleText)
|
||||
: null;
|
||||
|
||||
if (editable) {
|
||||
const caretOffset = editable.caretOffset;
|
||||
|
@ -315,8 +381,8 @@ this.ContentControl.prototype = {
|
|||
}
|
||||
|
||||
if (editable) {
|
||||
const newOffset = direction === "Next" ?
|
||||
this.vc.endOffset : this.vc.startOffset;
|
||||
const newOffset =
|
||||
direction === "Next" ? this.vc.endOffset : this.vc.startOffset;
|
||||
if (select) {
|
||||
let anchor = editable.caretOffset;
|
||||
if (editable.selectionCount) {
|
||||
|
@ -332,8 +398,9 @@ this.ContentControl.prototype = {
|
|||
|
||||
handleSetSelection: function cc_handleSetSelection(aMessage) {
|
||||
const { start, end } = aMessage.json;
|
||||
const focusedAcc =
|
||||
Utils.AccService.getAccessibleFor(this.document.activeElement);
|
||||
const focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement
|
||||
);
|
||||
if (focusedAcc) {
|
||||
const accText = focusedAcc.QueryInterface(Ci.nsIAccessibleText);
|
||||
if (start == end) {
|
||||
|
@ -346,8 +413,9 @@ this.ContentControl.prototype = {
|
|||
|
||||
handleClipboard: function cc_handleClipboard(aMessage) {
|
||||
const { action } = aMessage.json;
|
||||
const focusedAcc =
|
||||
Utils.AccService.getAccessibleFor(this.document.activeElement);
|
||||
const focusedAcc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement
|
||||
);
|
||||
if (focusedAcc) {
|
||||
const [startSel, endSel] = Utils.getTextSelection(focusedAcc);
|
||||
const editText = focusedAcc.QueryInterface(Ci.nsIAccessibleEditableText);
|
||||
|
@ -389,8 +457,12 @@ this.ContentControl.prototype = {
|
|||
return null;
|
||||
},
|
||||
|
||||
sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer,
|
||||
aFocus) {
|
||||
sendToChild: function cc_sendToChild(
|
||||
aVirtualCursor,
|
||||
aMessage,
|
||||
aReplacer,
|
||||
aFocus
|
||||
) {
|
||||
let position = aVirtualCursor.position;
|
||||
let mm = this.getChildCursor(position);
|
||||
if (!mm) {
|
||||
|
@ -436,17 +508,20 @@ this.ContentControl.prototype = {
|
|||
let moveFunc = () => {
|
||||
let vc = this.vc;
|
||||
let acc = aAnchor;
|
||||
let rule = aOptions.onScreenOnly ?
|
||||
TraversalRules.SimpleOnScreen : TraversalRules.Simple;
|
||||
let rule = aOptions.onScreenOnly
|
||||
? TraversalRules.SimpleOnScreen
|
||||
: TraversalRules.Simple;
|
||||
|
||||
if (aOptions.noOpIfOnScreen &&
|
||||
Utils.isAliveAndVisible(vc.position, true)) {
|
||||
if (
|
||||
aOptions.noOpIfOnScreen &&
|
||||
Utils.isAliveAndVisible(vc.position, true)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aOptions.moveToFocused) {
|
||||
acc = Utils.AccService.getAccessibleFor(
|
||||
this.document.activeElement) || acc;
|
||||
acc =
|
||||
Utils.AccService.getAccessibleFor(this.document.activeElement) || acc;
|
||||
}
|
||||
|
||||
let moved = false;
|
||||
|
@ -454,22 +529,31 @@ this.ContentControl.prototype = {
|
|||
let moveFirstOrLast = moveMethod in ["moveFirst", "moveLast"];
|
||||
if (!moveFirstOrLast || acc) {
|
||||
// We either need next/previous or there is an anchor we need to use.
|
||||
moved = vc[moveFirstOrLast ? "moveNext" : moveMethod](rule, acc, true,
|
||||
true);
|
||||
moved = vc[moveFirstOrLast ? "moveNext" : moveMethod](
|
||||
rule,
|
||||
acc,
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (moveFirstOrLast && !moved) {
|
||||
// We move to first/last after no anchor move happened or succeeded.
|
||||
moved = vc[moveMethod](rule, true);
|
||||
}
|
||||
|
||||
this.sendToChild(vc, {
|
||||
name: "AccessFu:AutoMove",
|
||||
json: {
|
||||
moveMethod: aOptions.moveMethod,
|
||||
moveToFocused: aOptions.moveToFocused,
|
||||
noOpIfOnScreen: true,
|
||||
this.sendToChild(
|
||||
vc,
|
||||
{
|
||||
name: "AccessFu:AutoMove",
|
||||
json: {
|
||||
moveMethod: aOptions.moveMethod,
|
||||
moveToFocused: aOptions.moveToFocused,
|
||||
noOpIfOnScreen: true,
|
||||
},
|
||||
},
|
||||
}, null, true);
|
||||
null,
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
if (aOptions.delay) {
|
||||
|
@ -484,7 +568,8 @@ this.ContentControl.prototype = {
|
|||
this._autoMove = 0;
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference,
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIMessageListener,
|
||||
]),
|
||||
};
|
||||
|
|
|
@ -4,25 +4,38 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Events",
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Events",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["EventManager"];
|
||||
|
||||
function EventManager(aContentScope) {
|
||||
this.contentScope = aContentScope;
|
||||
this.addEventListener = this.contentScope.addEventListener.bind(
|
||||
this.contentScope);
|
||||
this.contentScope
|
||||
);
|
||||
this.removeEventListener = this.contentScope.removeEventListener.bind(
|
||||
this.contentScope);
|
||||
this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(
|
||||
this.contentScope);
|
||||
this.contentScope
|
||||
);
|
||||
this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(this.contentScope);
|
||||
}
|
||||
|
||||
this.EventManager.prototype = {
|
||||
|
@ -65,67 +78,72 @@ this.EventManager.prototype = {
|
|||
|
||||
handleAccEvent: function handleAccEvent(aEvent) {
|
||||
Logger.debug(() => {
|
||||
return ["A11yEvent", Logger.eventToString(aEvent),
|
||||
Logger.accessibleToString(aEvent.accessible)];
|
||||
return [
|
||||
"A11yEvent",
|
||||
Logger.eventToString(aEvent),
|
||||
Logger.accessibleToString(aEvent.accessible),
|
||||
];
|
||||
});
|
||||
|
||||
// Don't bother with non-content events in firefox.
|
||||
if (Utils.MozBuildApp == "browser" &&
|
||||
aEvent.eventType != Events.VIRTUALCURSOR_CHANGED &&
|
||||
// XXX Bug 442005 results in DocAccessible::getDocType returning
|
||||
// NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
|
||||
// 'window' does not currently work.
|
||||
(aEvent.accessibleDocument.DOMDocument.doctype &&
|
||||
aEvent.accessibleDocument.DOMDocument.doctype.name === "window")) {
|
||||
if (
|
||||
Utils.MozBuildApp == "browser" &&
|
||||
aEvent.eventType != Events.VIRTUALCURSOR_CHANGED &&
|
||||
// XXX Bug 442005 results in DocAccessible::getDocType returning
|
||||
// NS_ERROR_FAILURE. Checking for aEvent.accessibleDocument.docType ==
|
||||
// 'window' does not currently work.
|
||||
(aEvent.accessibleDocument.DOMDocument.doctype &&
|
||||
aEvent.accessibleDocument.DOMDocument.doctype.name === "window")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aEvent.eventType) {
|
||||
case Events.TEXT_CARET_MOVED:
|
||||
{
|
||||
if (aEvent.accessible != aEvent.accessibleDocument &&
|
||||
!aEvent.isFromUserInput) {
|
||||
case Events.TEXT_CARET_MOVED: {
|
||||
if (
|
||||
aEvent.accessible != aEvent.accessibleDocument &&
|
||||
!aEvent.isFromUserInput
|
||||
) {
|
||||
// If caret moves in document without direct user
|
||||
// we are probably stepping through results in find-in-page.
|
||||
let acc = Utils.getTextLeafForOffset(aEvent.accessible,
|
||||
aEvent.QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset);
|
||||
let acc = Utils.getTextLeafForOffset(
|
||||
aEvent.accessible,
|
||||
aEvent.QueryInterface(Ci.nsIAccessibleCaretMoveEvent).caretOffset
|
||||
);
|
||||
this.contentControl.autoMove(acc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Events.NAME_CHANGE:
|
||||
{
|
||||
case Events.NAME_CHANGE: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
case Events.SCROLLING_START:
|
||||
{
|
||||
case Events.SCROLLING_START: {
|
||||
this.contentControl.autoMove(aEvent.accessible);
|
||||
break;
|
||||
}
|
||||
case Events.SHOW:
|
||||
{
|
||||
case Events.SHOW: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
case Events.HIDE:
|
||||
{
|
||||
case Events.HIDE: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
case Events.VALUE_CHANGE:
|
||||
{
|
||||
case Events.VALUE_CHANGE: {
|
||||
// XXX: Port to Android
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsIObserver]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIObserver,
|
||||
]),
|
||||
};
|
||||
|
||||
const AccessibilityEventObserver = {
|
||||
|
||||
/**
|
||||
* A WeakMap containing [content, EventManager] pairs.
|
||||
*/
|
||||
|
@ -180,8 +198,10 @@ const AccessibilityEventObserver = {
|
|||
}
|
||||
this.eventManagers.set(content, aEventManager);
|
||||
// Since at least one EventManager was registered, start listening.
|
||||
Logger.debug("AccessibilityEventObserver.addListener. Total:",
|
||||
this.listenerCount);
|
||||
Logger.debug(
|
||||
"AccessibilityEventObserver.addListener. Total:",
|
||||
this.listenerCount
|
||||
);
|
||||
this.start();
|
||||
},
|
||||
|
||||
|
@ -198,8 +218,10 @@ const AccessibilityEventObserver = {
|
|||
return;
|
||||
}
|
||||
this.listenerCount--;
|
||||
Logger.debug("AccessibilityEventObserver.removeListener. Total:",
|
||||
this.listenerCount);
|
||||
Logger.debug(
|
||||
"AccessibilityEventObserver.removeListener. Total:",
|
||||
this.listenerCount
|
||||
);
|
||||
if (this.listenerCount === 0) {
|
||||
// If there are no EventManagers registered at the moment, stop listening
|
||||
// to the 'accessible-event' messages.
|
||||
|
@ -237,8 +259,10 @@ const AccessibilityEventObserver = {
|
|||
if (!event.accessibleDocument) {
|
||||
Logger.warning(
|
||||
"AccessibilityEventObserver.observe: no accessible document:",
|
||||
Logger.eventToString(event), "accessible:",
|
||||
Logger.accessibleToString(event.accessible));
|
||||
Logger.eventToString(event),
|
||||
"accessible:",
|
||||
Logger.accessibleToString(event.accessible)
|
||||
);
|
||||
return;
|
||||
}
|
||||
let content;
|
||||
|
@ -247,8 +271,10 @@ const AccessibilityEventObserver = {
|
|||
} catch (e) {
|
||||
Logger.warning(
|
||||
"AccessibilityEventObserver.observe: no window for accessible document:",
|
||||
Logger.eventToString(event), "accessible:",
|
||||
Logger.accessibleToString(event.accessible));
|
||||
Logger.eventToString(event),
|
||||
"accessible:",
|
||||
Logger.accessibleToString(event.accessible)
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Match the content window to its EventManager.
|
||||
|
@ -257,9 +283,12 @@ const AccessibilityEventObserver = {
|
|||
if (Utils.MozBuildApp === "browser" && !content.isChromeWindow) {
|
||||
Logger.warning(
|
||||
"AccessibilityEventObserver.observe: ignored event:",
|
||||
Logger.eventToString(event), "accessible:",
|
||||
Logger.accessibleToString(event.accessible), "document:",
|
||||
Logger.accessibleToString(event.accessibleDocument));
|
||||
Logger.eventToString(event),
|
||||
"accessible:",
|
||||
Logger.accessibleToString(event.accessible),
|
||||
"document:",
|
||||
Logger.accessibleToString(event.accessibleDocument)
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -6,17 +6,33 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["TraversalRules", "TraversalHelper"]; // jshint ignore:line
|
||||
|
||||
const {PrefCache, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Filters", // 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, "Prefilters", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
const { PrefCache, Utils } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Roles", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Filters", // 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,
|
||||
"Prefilters", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
|
||||
var gSkipEmptyImages = new PrefCache("accessibility.accessfu.skip_empty_images");
|
||||
var gSkipEmptyImages = new PrefCache(
|
||||
"accessibility.accessfu.skip_empty_images"
|
||||
);
|
||||
|
||||
function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter, aContainerRule) {
|
||||
this._explicitMatchRoles = new Set(aRoles);
|
||||
|
@ -30,66 +46,71 @@ function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter, aContainerRule) {
|
|||
this._matchRoles.push(Roles.INTERNAL_FRAME);
|
||||
}
|
||||
}
|
||||
this._matchFunc = aMatchFunc || function() { return Filters.MATCH; };
|
||||
this._matchFunc =
|
||||
aMatchFunc ||
|
||||
function() {
|
||||
return Filters.MATCH;
|
||||
};
|
||||
this.preFilter = aPreFilter || gSimplePreFilter;
|
||||
this.containerRule = aContainerRule;
|
||||
}
|
||||
|
||||
BaseTraversalRule.prototype = {
|
||||
getMatchRoles: function BaseTraversalRule_getmatchRoles() {
|
||||
return this._matchRoles;
|
||||
},
|
||||
getMatchRoles: function BaseTraversalRule_getmatchRoles() {
|
||||
return this._matchRoles;
|
||||
},
|
||||
|
||||
match: function BaseTraversalRule_match(aAccessible) {
|
||||
let role = aAccessible.role;
|
||||
if (role == Roles.INTERNAL_FRAME) {
|
||||
return (Utils.getMessageManagerForFrame(aAccessible.DOMNode)) ?
|
||||
Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
|
||||
}
|
||||
match: function BaseTraversalRule_match(aAccessible) {
|
||||
let role = aAccessible.role;
|
||||
if (role == Roles.INTERNAL_FRAME) {
|
||||
return Utils.getMessageManagerForFrame(aAccessible.DOMNode)
|
||||
? Filters.MATCH | Filters.IGNORE_SUBTREE
|
||||
: Filters.IGNORE;
|
||||
}
|
||||
|
||||
if (this._explicitMatchRoles.has(role) ||
|
||||
!this._explicitMatchRoles.size) {
|
||||
return this._matchFunc(aAccessible);
|
||||
}
|
||||
if (this._explicitMatchRoles.has(role) || !this._explicitMatchRoles.size) {
|
||||
return this._matchFunc(aAccessible);
|
||||
}
|
||||
|
||||
return Filters.IGNORE;
|
||||
},
|
||||
return Filters.IGNORE;
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIAccessibleTraversalRule]),
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIAccessibleTraversalRule]),
|
||||
};
|
||||
|
||||
var gSimpleTraversalRoles =
|
||||
[Roles.MENUITEM,
|
||||
Roles.LINK,
|
||||
Roles.PAGETAB,
|
||||
Roles.GRAPHIC,
|
||||
Roles.STATICTEXT,
|
||||
Roles.TEXT_LEAF,
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.COMBOBOX,
|
||||
Roles.PROGRESSBAR,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONMENU,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.ENTRY,
|
||||
Roles.KEY,
|
||||
Roles.HEADER,
|
||||
Roles.HEADING,
|
||||
Roles.SLIDER,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.OPTION,
|
||||
Roles.LISTITEM,
|
||||
Roles.GRID_CELL,
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.STATUSBAR,
|
||||
Roles.SWITCH,
|
||||
Roles.MATHML_MATH];
|
||||
var gSimpleTraversalRoles = [
|
||||
Roles.MENUITEM,
|
||||
Roles.LINK,
|
||||
Roles.PAGETAB,
|
||||
Roles.GRAPHIC,
|
||||
Roles.STATICTEXT,
|
||||
Roles.TEXT_LEAF,
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.COMBOBOX,
|
||||
Roles.PROGRESSBAR,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONMENU,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.ENTRY,
|
||||
Roles.KEY,
|
||||
Roles.HEADER,
|
||||
Roles.HEADING,
|
||||
Roles.SLIDER,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.OPTION,
|
||||
Roles.LISTITEM,
|
||||
Roles.GRID_CELL,
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.STATUSBAR,
|
||||
Roles.SWITCH,
|
||||
Roles.MATHML_MATH,
|
||||
];
|
||||
|
||||
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
|
||||
// An object is simple, if it either has a single child lineage,
|
||||
|
@ -118,90 +139,101 @@ var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
|
|||
}
|
||||
|
||||
switch (aAccessible.role) {
|
||||
case Roles.COMBOBOX:
|
||||
// We don't want to ignore the subtree because this is often
|
||||
// where the list box hangs out.
|
||||
return Filters.MATCH;
|
||||
case Roles.TEXT_LEAF:
|
||||
{
|
||||
case Roles.COMBOBOX:
|
||||
// We don't want to ignore the subtree because this is often
|
||||
// where the list box hangs out.
|
||||
return Filters.MATCH;
|
||||
case Roles.TEXT_LEAF: {
|
||||
// Nameless text leaves are boring, skip them.
|
||||
let name = aAccessible.name;
|
||||
return (name && name.trim()) ? Filters.MATCH : Filters.IGNORE;
|
||||
return name && name.trim() ? Filters.MATCH : Filters.IGNORE;
|
||||
}
|
||||
case Roles.STATICTEXT:
|
||||
// Ignore prefix static text in list items. They are typically bullets or numbers.
|
||||
return Utils.isListItemDecorator(aAccessible) ?
|
||||
Filters.IGNORE : Filters.MATCH;
|
||||
case Roles.GRAPHIC:
|
||||
return TraversalRules._shouldSkipImage(aAccessible);
|
||||
case Roles.HEADER:
|
||||
case Roles.HEADING:
|
||||
case Roles.COLUMNHEADER:
|
||||
case Roles.ROWHEADER:
|
||||
case Roles.STATUSBAR:
|
||||
if ((aAccessible.childCount > 0 || aAccessible.name) &&
|
||||
(isSingleLineage(aAccessible) || isFlatSubtree(aAccessible))) {
|
||||
case Roles.STATICTEXT:
|
||||
// Ignore prefix static text in list items. They are typically bullets or numbers.
|
||||
return Utils.isListItemDecorator(aAccessible)
|
||||
? Filters.IGNORE
|
||||
: Filters.MATCH;
|
||||
case Roles.GRAPHIC:
|
||||
return TraversalRules._shouldSkipImage(aAccessible);
|
||||
case Roles.HEADER:
|
||||
case Roles.HEADING:
|
||||
case Roles.COLUMNHEADER:
|
||||
case Roles.ROWHEADER:
|
||||
case Roles.STATUSBAR:
|
||||
if (
|
||||
(aAccessible.childCount > 0 || aAccessible.name) &&
|
||||
(isSingleLineage(aAccessible) || isFlatSubtree(aAccessible))
|
||||
) {
|
||||
return Filters.MATCH | Filters.IGNORE_SUBTREE;
|
||||
}
|
||||
return Filters.IGNORE;
|
||||
case Roles.GRID_CELL:
|
||||
return isSingleLineage(aAccessible) || isFlatSubtree(aAccessible)
|
||||
? Filters.MATCH | Filters.IGNORE_SUBTREE
|
||||
: Filters.IGNORE;
|
||||
case Roles.LISTITEM: {
|
||||
let item =
|
||||
aAccessible.childCount === 2 &&
|
||||
aAccessible.firstChild.role === Roles.STATICTEXT
|
||||
? aAccessible.lastChild
|
||||
: aAccessible;
|
||||
return isSingleLineage(item) || isFlatSubtree(item)
|
||||
? Filters.MATCH | Filters.IGNORE_SUBTREE
|
||||
: Filters.IGNORE;
|
||||
}
|
||||
default:
|
||||
// Ignore the subtree, if there is one. So that we don't land on
|
||||
// the same content that was already presented by its parent.
|
||||
return Filters.MATCH | Filters.IGNORE_SUBTREE;
|
||||
}
|
||||
return Filters.IGNORE;
|
||||
case Roles.GRID_CELL:
|
||||
return isSingleLineage(aAccessible) || isFlatSubtree(aAccessible) ?
|
||||
Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
|
||||
case Roles.LISTITEM:
|
||||
{
|
||||
let item = aAccessible.childCount === 2 &&
|
||||
aAccessible.firstChild.role === Roles.STATICTEXT ?
|
||||
aAccessible.lastChild : aAccessible;
|
||||
return isSingleLineage(item) || isFlatSubtree(item) ?
|
||||
Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE;
|
||||
}
|
||||
default:
|
||||
// Ignore the subtree, if there is one. So that we don't land on
|
||||
// the same content that was already presented by its parent.
|
||||
return Filters.MATCH |
|
||||
Filters.IGNORE_SUBTREE;
|
||||
}
|
||||
};
|
||||
|
||||
var gSimplePreFilter = Prefilters.DEFUNCT |
|
||||
var gSimplePreFilter =
|
||||
Prefilters.DEFUNCT |
|
||||
Prefilters.INVISIBLE |
|
||||
Prefilters.TRANSPARENT |
|
||||
Prefilters.PLATFORM_PRUNED;
|
||||
|
||||
var TraversalRules = { // jshint ignore:line
|
||||
var TraversalRules = {
|
||||
// jshint ignore:line
|
||||
Simple: new BaseTraversalRule(gSimpleTraversalRoles, gSimpleMatchFunc),
|
||||
|
||||
SimpleOnScreen: new BaseTraversalRule(
|
||||
gSimpleTraversalRoles, gSimpleMatchFunc,
|
||||
gSimplePreFilter | Prefilters.OFFSCREEN),
|
||||
gSimpleTraversalRoles,
|
||||
gSimpleMatchFunc,
|
||||
gSimplePreFilter | Prefilters.OFFSCREEN
|
||||
),
|
||||
|
||||
Anchor: new BaseTraversalRule(
|
||||
[Roles.LINK],
|
||||
function Anchor_match(aAccessible) {
|
||||
// We want to ignore links, only focus named anchors.
|
||||
if (Utils.getState(aAccessible).contains(States.LINKED)) {
|
||||
return Filters.IGNORE;
|
||||
}
|
||||
return Filters.MATCH;
|
||||
}),
|
||||
Anchor: new BaseTraversalRule([Roles.LINK], function Anchor_match(
|
||||
aAccessible
|
||||
) {
|
||||
// We want to ignore links, only focus named anchors.
|
||||
if (Utils.getState(aAccessible).contains(States.LINKED)) {
|
||||
return Filters.IGNORE;
|
||||
}
|
||||
return Filters.MATCH;
|
||||
}),
|
||||
|
||||
Button: new BaseTraversalRule(
|
||||
[Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID]),
|
||||
Button: new BaseTraversalRule([
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
]),
|
||||
|
||||
Combobox: new BaseTraversalRule(
|
||||
[Roles.COMBOBOX,
|
||||
Roles.LISTBOX]),
|
||||
Combobox: new BaseTraversalRule([Roles.COMBOBOX, Roles.LISTBOX]),
|
||||
|
||||
Landmark: new BaseTraversalRule(
|
||||
[],
|
||||
function Landmark_match(aAccessible) {
|
||||
return Utils.getLandmarkName(aAccessible) ? Filters.MATCH :
|
||||
Filters.IGNORE;
|
||||
}, null, true),
|
||||
return Utils.getLandmarkName(aAccessible)
|
||||
? Filters.MATCH
|
||||
: Filters.IGNORE;
|
||||
},
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
/* A rule for Android's section navigation, lands on landmarks, regions, and
|
||||
on headings to aid navigation of traditionally structured documents */
|
||||
|
@ -220,123 +252,131 @@ var TraversalRules = { // jshint ignore:line
|
|||
"navigation",
|
||||
"search",
|
||||
"region",
|
||||
]);
|
||||
]);
|
||||
|
||||
return matchedRole ? Filters.MATCH : Filters.IGNORE;
|
||||
}, null, true),
|
||||
},
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
Entry: new BaseTraversalRule(
|
||||
[Roles.ENTRY,
|
||||
Roles.PASSWORD_TEXT]),
|
||||
Entry: new BaseTraversalRule([Roles.ENTRY, Roles.PASSWORD_TEXT]),
|
||||
|
||||
FormElement: new BaseTraversalRule(
|
||||
[Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
Roles.COMBOBOX,
|
||||
Roles.LISTBOX,
|
||||
Roles.ENTRY,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.PAGETAB,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.SLIDER,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH]),
|
||||
FormElement: new BaseTraversalRule([
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
Roles.COMBOBOX,
|
||||
Roles.LISTBOX,
|
||||
Roles.ENTRY,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.PAGETAB,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.SLIDER,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH,
|
||||
]),
|
||||
|
||||
Graphic: new BaseTraversalRule(
|
||||
[Roles.GRAPHIC],
|
||||
function Graphic_match(aAccessible) {
|
||||
return TraversalRules._shouldSkipImage(aAccessible);
|
||||
}),
|
||||
Graphic: new BaseTraversalRule([Roles.GRAPHIC], function Graphic_match(
|
||||
aAccessible
|
||||
) {
|
||||
return TraversalRules._shouldSkipImage(aAccessible);
|
||||
}),
|
||||
|
||||
Heading: new BaseTraversalRule(
|
||||
[Roles.HEADING],
|
||||
function Heading_match(aAccessible) {
|
||||
return aAccessible.childCount > 0 ? Filters.MATCH : Filters.IGNORE;
|
||||
}),
|
||||
Heading: new BaseTraversalRule([Roles.HEADING], function Heading_match(
|
||||
aAccessible
|
||||
) {
|
||||
return aAccessible.childCount > 0 ? Filters.MATCH : Filters.IGNORE;
|
||||
}),
|
||||
|
||||
ListItem: new BaseTraversalRule(
|
||||
[Roles.LISTITEM,
|
||||
Roles.TERM]),
|
||||
ListItem: new BaseTraversalRule([Roles.LISTITEM, Roles.TERM]),
|
||||
|
||||
Link: new BaseTraversalRule(
|
||||
[Roles.LINK],
|
||||
function Link_match(aAccessible) {
|
||||
// We want to ignore anchors, only focus real links.
|
||||
if (Utils.getState(aAccessible).contains(States.LINKED)) {
|
||||
return Filters.MATCH;
|
||||
}
|
||||
return Filters.IGNORE;
|
||||
}),
|
||||
Link: new BaseTraversalRule([Roles.LINK], function Link_match(aAccessible) {
|
||||
// We want to ignore anchors, only focus real links.
|
||||
if (Utils.getState(aAccessible).contains(States.LINKED)) {
|
||||
return Filters.MATCH;
|
||||
}
|
||||
return Filters.IGNORE;
|
||||
}),
|
||||
|
||||
/* For TalkBack's "Control" granularity. Form conrols and links */
|
||||
Control: new BaseTraversalRule(
|
||||
[Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
Roles.COMBOBOX,
|
||||
Roles.LISTBOX,
|
||||
Roles.ENTRY,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.PAGETAB,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.SLIDER,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH,
|
||||
Roles.LINK,
|
||||
Roles.MENUITEM],
|
||||
[
|
||||
Roles.PUSHBUTTON,
|
||||
Roles.SPINBUTTON,
|
||||
Roles.TOGGLE_BUTTON,
|
||||
Roles.BUTTONDROPDOWN,
|
||||
Roles.BUTTONDROPDOWNGRID,
|
||||
Roles.COMBOBOX,
|
||||
Roles.LISTBOX,
|
||||
Roles.ENTRY,
|
||||
Roles.PASSWORD_TEXT,
|
||||
Roles.PAGETAB,
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.SLIDER,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH,
|
||||
Roles.LINK,
|
||||
Roles.MENUITEM,
|
||||
],
|
||||
function Control_match(aAccessible) {
|
||||
// We want to ignore anchors, only focus real links.
|
||||
if (aAccessible.role == Roles.LINK &&
|
||||
!Utils.getState(aAccessible).contains(States.LINKED)) {
|
||||
if (
|
||||
aAccessible.role == Roles.LINK &&
|
||||
!Utils.getState(aAccessible).contains(States.LINKED)
|
||||
) {
|
||||
return Filters.IGNORE;
|
||||
}
|
||||
return Filters.MATCH;
|
||||
}),
|
||||
}
|
||||
),
|
||||
|
||||
List: new BaseTraversalRule(
|
||||
[Roles.LIST,
|
||||
Roles.DEFINITION_LIST],
|
||||
null, null, true),
|
||||
[Roles.LIST, Roles.DEFINITION_LIST],
|
||||
null,
|
||||
null,
|
||||
true
|
||||
),
|
||||
|
||||
PageTab: new BaseTraversalRule(
|
||||
[Roles.PAGETAB]),
|
||||
PageTab: new BaseTraversalRule([Roles.PAGETAB]),
|
||||
|
||||
Paragraph: new BaseTraversalRule(
|
||||
[Roles.PARAGRAPH,
|
||||
Roles.SECTION],
|
||||
[Roles.PARAGRAPH, Roles.SECTION],
|
||||
function Paragraph_match(aAccessible) {
|
||||
for (let child = aAccessible.firstChild; child; child = child.nextSibling) {
|
||||
for (
|
||||
let child = aAccessible.firstChild;
|
||||
child;
|
||||
child = child.nextSibling
|
||||
) {
|
||||
if (child.role === Roles.TEXT_LEAF) {
|
||||
return Filters.MATCH | Filters.IGNORE_SUBTREE;
|
||||
}
|
||||
}
|
||||
|
||||
return Filters.IGNORE;
|
||||
}),
|
||||
}
|
||||
),
|
||||
|
||||
RadioButton: new BaseTraversalRule(
|
||||
[Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM]),
|
||||
RadioButton: new BaseTraversalRule([
|
||||
Roles.RADIOBUTTON,
|
||||
Roles.RADIO_MENU_ITEM,
|
||||
]),
|
||||
|
||||
Separator: new BaseTraversalRule(
|
||||
[Roles.SEPARATOR]),
|
||||
Separator: new BaseTraversalRule([Roles.SEPARATOR]),
|
||||
|
||||
Table: new BaseTraversalRule(
|
||||
[Roles.TABLE]),
|
||||
Table: new BaseTraversalRule([Roles.TABLE]),
|
||||
|
||||
Checkbox: new BaseTraversalRule(
|
||||
[Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH /* A type of checkbox that represents on/off values */]),
|
||||
Checkbox: new BaseTraversalRule([
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH /* A type of checkbox that represents on/off values */,
|
||||
]),
|
||||
|
||||
_shouldSkipImage: function _shouldSkipImage(aAccessible) {
|
||||
if (gSkipEmptyImages.value && aAccessible.name === "") {
|
||||
|
@ -390,5 +430,4 @@ var TraversalHelper = {
|
|||
}
|
||||
return aVirtualCursor[aMethod](rule);
|
||||
},
|
||||
|
||||
};
|
||||
|
|
|
@ -4,24 +4,46 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Services", // jshint ignore:line
|
||||
"resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Rect", // jshint ignore:line
|
||||
"resource://gre/modules/Geometry.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Roles", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Events", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Relations", // 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, "PluralForm", // jshint ignore:line
|
||||
"resource://gre/modules/PluralForm.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services", // jshint ignore:line
|
||||
"resource://gre/modules/Services.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Rect", // jshint ignore:line
|
||||
"resource://gre/modules/Geometry.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Roles", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Events", // jshint ignore:line
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Relations", // 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,
|
||||
"PluralForm", // jshint ignore:line
|
||||
"resource://gre/modules/PluralForm.jsm"
|
||||
);
|
||||
|
||||
var EXPORTED_SYMBOLS = ["Utils", "Logger", "PivotContext", "PrefCache"]; // jshint ignore:line
|
||||
|
||||
var Utils = { // jshint ignore:line
|
||||
var Utils = {
|
||||
// jshint ignore:line
|
||||
_buildAppMap: {
|
||||
"{3c2e2abc-06d4-11e1-ac3b-374f68613e61}": "b2g",
|
||||
"{d1bfe7d9-c01e-4237-998b-7b5f960a4314}": "graphene",
|
||||
|
@ -31,8 +53,9 @@ var Utils = { // jshint ignore:line
|
|||
|
||||
get AccService() {
|
||||
if (!this._AccService) {
|
||||
this._AccService = Cc["@mozilla.org/accessibilityService;1"].
|
||||
getService(Ci.nsIAccessibilityService);
|
||||
this._AccService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
}
|
||||
|
||||
return this._AccService;
|
||||
|
@ -52,7 +75,7 @@ var Utils = { // jshint ignore:line
|
|||
get ScriptName() {
|
||||
if (!this._ScriptName) {
|
||||
this._ScriptName =
|
||||
(Services.appinfo.processType == 2) ? "AccessFuContent" : "AccessFu";
|
||||
Services.appinfo.processType == 2 ? "AccessFuContent" : "AccessFu";
|
||||
}
|
||||
return this._ScriptName;
|
||||
},
|
||||
|
@ -61,7 +84,8 @@ var Utils = { // jshint ignore:line
|
|||
if (!this._AndroidSdkVersion) {
|
||||
if (Services.appinfo.OS == "Android") {
|
||||
this._AndroidSdkVersion = Services.sysinfo.getPropertyAsInt32(
|
||||
"version");
|
||||
"version"
|
||||
);
|
||||
} else {
|
||||
// Most useful in desktop debugging.
|
||||
this._AndroidSdkVersion = 16;
|
||||
|
@ -76,7 +100,9 @@ var Utils = { // jshint ignore:line
|
|||
},
|
||||
|
||||
getCurrentBrowser: function getCurrentBrowser(aWindow) {
|
||||
return aWindow.document.querySelector("browser[type=content][primary=true]");
|
||||
return aWindow.document.querySelector(
|
||||
"browser[type=content][primary=true]"
|
||||
);
|
||||
},
|
||||
|
||||
get isContentProcess() {
|
||||
|
@ -88,17 +114,19 @@ var Utils = { // jshint ignore:line
|
|||
|
||||
localize: function localize(aOutput) {
|
||||
let outputArray = Array.isArray(aOutput) ? aOutput : [aOutput];
|
||||
let localized =
|
||||
outputArray.map(details => this.stringBundle.get(details));
|
||||
let localized = outputArray.map(details => this.stringBundle.get(details));
|
||||
// Clean up the white space.
|
||||
return localized.filter(word => word).map(word => word.trim()).
|
||||
filter(trimmed => trimmed);
|
||||
return localized
|
||||
.filter(word => word)
|
||||
.map(word => word.trim())
|
||||
.filter(trimmed => trimmed);
|
||||
},
|
||||
|
||||
get stringBundle() {
|
||||
delete this.stringBundle;
|
||||
let bundle = Services.strings.createBundle(
|
||||
"chrome://global/locale/AccessFu.properties");
|
||||
"chrome://global/locale/AccessFu.properties"
|
||||
);
|
||||
this.stringBundle = {
|
||||
get: function stringBundle_get(aDetails = {}) {
|
||||
if (!aDetails || typeof aDetails === "string") {
|
||||
|
@ -150,12 +178,13 @@ var Utils = { // jshint ignore:line
|
|||
if (aAccessibleOrEvent instanceof Ci.nsIAccessibleStateChangeEvent) {
|
||||
return new State(
|
||||
aAccessibleOrEvent.isExtraState ? 0 : aAccessibleOrEvent.state,
|
||||
aAccessibleOrEvent.isExtraState ? aAccessibleOrEvent.state : 0);
|
||||
aAccessibleOrEvent.isExtraState ? aAccessibleOrEvent.state : 0
|
||||
);
|
||||
}
|
||||
let state = {};
|
||||
let extState = {};
|
||||
aAccessibleOrEvent.getState(state, extState);
|
||||
return new State(state.value, extState.value);
|
||||
let state = {};
|
||||
let extState = {};
|
||||
aAccessibleOrEvent.getState(state, extState);
|
||||
return new State(state.value, extState.value);
|
||||
},
|
||||
|
||||
getAttributes: function getAttributes(aAccessible) {
|
||||
|
@ -173,8 +202,10 @@ var Utils = { // jshint ignore:line
|
|||
},
|
||||
|
||||
getVirtualCursor: function getVirtualCursor(aDocument) {
|
||||
let doc = (aDocument instanceof Ci.nsIAccessible) ? aDocument :
|
||||
this.AccService.getAccessibleFor(aDocument);
|
||||
let doc =
|
||||
aDocument instanceof Ci.nsIAccessible
|
||||
? aDocument
|
||||
: this.AccService.getAccessibleFor(aDocument);
|
||||
|
||||
return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
|
||||
},
|
||||
|
@ -184,7 +215,10 @@ var Utils = { // jshint ignore:line
|
|||
},
|
||||
|
||||
getBounds: function getBounds(aAccessible) {
|
||||
let objX = {}, objY = {}, objW = {}, objH = {};
|
||||
let objX = {},
|
||||
objY = {},
|
||||
objW = {},
|
||||
objH = {};
|
||||
aAccessible.getBounds(objX, objY, objW, objH);
|
||||
|
||||
return new Rect(objX.value, objY.value, objW.value, objH.value);
|
||||
|
@ -192,7 +226,8 @@ var Utils = { // jshint ignore:line
|
|||
|
||||
getTextSelection: function getTextSelection(aAccessible) {
|
||||
const accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
|
||||
const start = {}, end = {};
|
||||
const start = {},
|
||||
end = {};
|
||||
if (accText.selectionCount) {
|
||||
accText.getSelectionBounds(0, start, end);
|
||||
} else {
|
||||
|
@ -202,12 +237,26 @@ var Utils = { // jshint ignore:line
|
|||
return [start.value, end.value];
|
||||
},
|
||||
|
||||
getTextBounds: function getTextBounds(aAccessible, aStart, aEnd,
|
||||
aPreserveContentScale) {
|
||||
getTextBounds: function getTextBounds(
|
||||
aAccessible,
|
||||
aStart,
|
||||
aEnd,
|
||||
aPreserveContentScale
|
||||
) {
|
||||
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
|
||||
let objX = {}, objY = {}, objW = {}, objH = {};
|
||||
accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
|
||||
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
|
||||
let objX = {},
|
||||
objY = {},
|
||||
objW = {},
|
||||
objH = {};
|
||||
accText.getRangeExtents(
|
||||
aStart,
|
||||
aEnd,
|
||||
objX,
|
||||
objY,
|
||||
objW,
|
||||
objH,
|
||||
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE
|
||||
);
|
||||
|
||||
return new Rect(objX.value, objY.value, objW.value, objH.value);
|
||||
},
|
||||
|
@ -219,8 +268,10 @@ var Utils = { // jshint ignore:line
|
|||
// ancestry of documents and skip everything else.
|
||||
if (aSubTreeRoot instanceof Ci.nsIAccessibleDocument) {
|
||||
while (acc) {
|
||||
let parentDoc = acc instanceof Ci.nsIAccessibleDocument ?
|
||||
acc.parentDocument : acc.document;
|
||||
let parentDoc =
|
||||
acc instanceof Ci.nsIAccessibleDocument
|
||||
? acc.parentDocument
|
||||
: acc.document;
|
||||
if (parentDoc === aSubTreeRoot) {
|
||||
return true;
|
||||
}
|
||||
|
@ -260,8 +311,11 @@ var Utils = { // jshint ignore:line
|
|||
|
||||
try {
|
||||
let state = this.getState(aAccessible);
|
||||
if (state.contains(States.DEFUNCT) || state.contains(States.INVISIBLE) ||
|
||||
(aIsOnScreen && state.contains(States.OFFSCREEN))) {
|
||||
if (
|
||||
state.contains(States.DEFUNCT) ||
|
||||
state.contains(States.INVISIBLE) ||
|
||||
(aIsOnScreen && state.contains(States.OFFSCREEN))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
} catch (x) {
|
||||
|
@ -333,15 +387,20 @@ var Utils = { // jshint ignore:line
|
|||
return null;
|
||||
},
|
||||
|
||||
isListItemDecorator: function isListItemDecorator(aStaticText,
|
||||
aExcludeOrdered) {
|
||||
isListItemDecorator: function isListItemDecorator(
|
||||
aStaticText,
|
||||
aExcludeOrdered
|
||||
) {
|
||||
let parent = aStaticText.parent;
|
||||
if (aExcludeOrdered && parent.parent.DOMNode.nodeName === "OL") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent.role === Roles.LISTITEM && parent.childCount > 1 &&
|
||||
aStaticText.indexInParent === 0;
|
||||
return (
|
||||
parent.role === Roles.LISTITEM &&
|
||||
parent.childCount > 1 &&
|
||||
aStaticText.indexInParent === 0
|
||||
);
|
||||
},
|
||||
|
||||
getTextLeafForOffset: function getTextLeafForOffset(aAccessible, aOffset) {
|
||||
|
@ -380,8 +439,10 @@ State.prototype = {
|
|||
return !!(this.base & other.base || this.extended & other.extended);
|
||||
},
|
||||
toString: function State_toString() {
|
||||
let stateStrings = Utils.AccService.
|
||||
getStringStates(this.base, this.extended);
|
||||
let stateStrings = Utils.AccService.getStringStates(
|
||||
this.base,
|
||||
this.extended
|
||||
);
|
||||
let statesArray = new Array(stateStrings.length);
|
||||
for (let i = 0; i < statesArray.length; i++) {
|
||||
statesArray[i] = stateStrings.item(i);
|
||||
|
@ -390,7 +451,8 @@ State.prototype = {
|
|||
},
|
||||
};
|
||||
|
||||
var Logger = { // jshint ignore:line
|
||||
var Logger = {
|
||||
// jshint ignore:line
|
||||
GESTURE: -1,
|
||||
DEBUG: 0,
|
||||
INFO: 1,
|
||||
|
@ -409,9 +471,15 @@ var Logger = { // jshint ignore:line
|
|||
}
|
||||
|
||||
let args = Array.prototype.slice.call(arguments, 1);
|
||||
let message = (typeof(args[0]) === "function" ? args[0]() : args).join(" ");
|
||||
message = "[" + Utils.ScriptName + "] " + this._LEVEL_NAMES[aLogLevel + 1] +
|
||||
" " + message + "\n";
|
||||
let message = (typeof args[0] === "function" ? args[0]() : args).join(" ");
|
||||
message =
|
||||
"[" +
|
||||
Utils.ScriptName +
|
||||
"] " +
|
||||
this._LEVEL_NAMES[aLogLevel + 1] +
|
||||
" " +
|
||||
message +
|
||||
"\n";
|
||||
dump(message);
|
||||
if (this.useConsoleService) {
|
||||
try {
|
||||
|
@ -424,31 +492,43 @@ var Logger = { // jshint ignore:line
|
|||
|
||||
info: function info() {
|
||||
this.log.apply(
|
||||
this, [this.INFO].concat(Array.prototype.slice.call(arguments)));
|
||||
this,
|
||||
[this.INFO].concat(Array.prototype.slice.call(arguments))
|
||||
);
|
||||
},
|
||||
|
||||
gesture: function gesture() {
|
||||
this.log.apply(
|
||||
this, [this.GESTURE].concat(Array.prototype.slice.call(arguments)));
|
||||
this,
|
||||
[this.GESTURE].concat(Array.prototype.slice.call(arguments))
|
||||
);
|
||||
},
|
||||
|
||||
debug: function debug() {
|
||||
this.log.apply(
|
||||
this, [this.DEBUG].concat(Array.prototype.slice.call(arguments)));
|
||||
this,
|
||||
[this.DEBUG].concat(Array.prototype.slice.call(arguments))
|
||||
);
|
||||
},
|
||||
|
||||
warning: function warning() {
|
||||
this.log.apply(
|
||||
this, [this.WARNING].concat(Array.prototype.slice.call(arguments)));
|
||||
this,
|
||||
[this.WARNING].concat(Array.prototype.slice.call(arguments))
|
||||
);
|
||||
},
|
||||
|
||||
error: function error() {
|
||||
this.log.apply(
|
||||
this, [this.ERROR].concat(Array.prototype.slice.call(arguments)));
|
||||
this,
|
||||
[this.ERROR].concat(Array.prototype.slice.call(arguments))
|
||||
);
|
||||
},
|
||||
|
||||
logException: function logException(
|
||||
aException, aErrorMessage = "An exception has occured") {
|
||||
aException,
|
||||
aErrorMessage = "An exception has occured"
|
||||
) {
|
||||
try {
|
||||
let stackMessage = "";
|
||||
if (aException.stack) {
|
||||
|
@ -458,7 +538,8 @@ var Logger = { // jshint ignore:line
|
|||
let stackLines = [];
|
||||
while (frame && frame.lineNumber) {
|
||||
stackLines.push(
|
||||
" " + frame.name + "@" + frame.filename + ":" + frame.lineNumber);
|
||||
" " + frame.name + "@" + frame.filename + ":" + frame.lineNumber
|
||||
);
|
||||
frame = frame.caller;
|
||||
}
|
||||
stackMessage = stackLines.join("\n");
|
||||
|
@ -466,9 +547,9 @@ var Logger = { // jshint ignore:line
|
|||
stackMessage =
|
||||
"(" + aException.fileName + ":" + aException.lineNumber + ")";
|
||||
}
|
||||
this.error(aErrorMessage + ":\n " +
|
||||
aException.message + "\n" +
|
||||
stackMessage);
|
||||
this.error(
|
||||
aErrorMessage + ":\n " + aException.message + "\n" + stackMessage
|
||||
);
|
||||
} catch (x) {
|
||||
this.error(x);
|
||||
}
|
||||
|
@ -480,8 +561,13 @@ var Logger = { // jshint ignore:line
|
|||
}
|
||||
|
||||
try {
|
||||
return "[ " + Utils.AccService.getStringRole(aAccessible.role) +
|
||||
" | " + aAccessible.name + " ]";
|
||||
return (
|
||||
"[ " +
|
||||
Utils.AccService.getStringRole(aAccessible.role) +
|
||||
" | " +
|
||||
aAccessible.name +
|
||||
" ]"
|
||||
);
|
||||
} catch (x) {
|
||||
return "[ defunct ]";
|
||||
}
|
||||
|
@ -491,19 +577,24 @@ var Logger = { // jshint ignore:line
|
|||
let str = Utils.AccService.getStringEventType(aEvent.eventType);
|
||||
if (aEvent.eventType == Events.STATE_CHANGE) {
|
||||
let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
|
||||
let stateStrings = event.isExtraState ?
|
||||
Utils.AccService.getStringStates(0, event.state) :
|
||||
Utils.AccService.getStringStates(event.state, 0);
|
||||
let stateStrings = event.isExtraState
|
||||
? Utils.AccService.getStringStates(0, event.state)
|
||||
: Utils.AccService.getStringStates(event.state, 0);
|
||||
str += " (" + stateStrings.item(0) + ")";
|
||||
}
|
||||
|
||||
if (aEvent.eventType == Events.VIRTUALCURSOR_CHANGED) {
|
||||
let event = aEvent.QueryInterface(
|
||||
Ci.nsIAccessibleVirtualCursorChangeEvent);
|
||||
let pivot = aEvent.accessible.QueryInterface(
|
||||
Ci.nsIAccessibleDocument).virtualCursor;
|
||||
str += " (" + this.accessibleToString(event.oldAccessible) + " -> " +
|
||||
this.accessibleToString(pivot.position) + ")";
|
||||
Ci.nsIAccessibleVirtualCursorChangeEvent
|
||||
);
|
||||
let pivot = aEvent.accessible.QueryInterface(Ci.nsIAccessibleDocument)
|
||||
.virtualCursor;
|
||||
str +=
|
||||
" (" +
|
||||
this.accessibleToString(event.oldAccessible) +
|
||||
" -> " +
|
||||
this.accessibleToString(pivot.position) +
|
||||
")";
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -521,20 +612,25 @@ var Logger = { // jshint ignore:line
|
|||
this._dumpTreeInternal(aLogLevel, aRootAccessible, 0);
|
||||
},
|
||||
|
||||
_dumpTreeInternal:
|
||||
function _dumpTreeInternal(aLogLevel, aAccessible, aIndent) {
|
||||
let indentStr = "";
|
||||
for (let i = 0; i < aIndent; i++) {
|
||||
indentStr += " ";
|
||||
}
|
||||
this.log(aLogLevel, indentStr,
|
||||
this.accessibleToString(aAccessible),
|
||||
"(" + this.statesToString(aAccessible) + ")");
|
||||
for (let i = 0; i < aAccessible.childCount; i++) {
|
||||
this._dumpTreeInternal(aLogLevel, aAccessible.getChildAt(i),
|
||||
aIndent + 1);
|
||||
}
|
||||
},
|
||||
_dumpTreeInternal: function _dumpTreeInternal(
|
||||
aLogLevel,
|
||||
aAccessible,
|
||||
aIndent
|
||||
) {
|
||||
let indentStr = "";
|
||||
for (let i = 0; i < aIndent; i++) {
|
||||
indentStr += " ";
|
||||
}
|
||||
this.log(
|
||||
aLogLevel,
|
||||
indentStr,
|
||||
this.accessibleToString(aAccessible),
|
||||
"(" + this.statesToString(aAccessible) + ")"
|
||||
);
|
||||
for (let i = 0; i < aAccessible.childCount; i++) {
|
||||
this._dumpTreeInternal(aLogLevel, aAccessible.getChildAt(i), aIndent + 1);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -547,13 +643,17 @@ var Logger = { // jshint ignore:line
|
|||
* label. In this case the |accessible| field would be the embedded control,
|
||||
* and the |accessibleForBounds| field would be the label.
|
||||
*/
|
||||
function PivotContext(aAccessible, aOldAccessible, // jshint ignore:line
|
||||
aStartOffset, aEndOffset, aIgnoreAncestry = false,
|
||||
aIncludeInvisible = false) {
|
||||
function PivotContext(
|
||||
aAccessible,
|
||||
aOldAccessible, // jshint ignore:line
|
||||
aStartOffset,
|
||||
aEndOffset,
|
||||
aIgnoreAncestry = false,
|
||||
aIncludeInvisible = false
|
||||
) {
|
||||
this._accessible = aAccessible;
|
||||
this._nestedControl = Utils.getEmbeddedControl(aAccessible);
|
||||
this._oldAccessible =
|
||||
this._isDefunct(aOldAccessible) ? null : aOldAccessible;
|
||||
this._oldAccessible = this._isDefunct(aOldAccessible) ? null : aOldAccessible;
|
||||
this.startOffset = aStartOffset;
|
||||
this.endOffset = aEndOffset;
|
||||
this._ignoreAncestry = aIgnoreAncestry;
|
||||
|
@ -585,13 +685,16 @@ PivotContext.prototype = {
|
|||
}
|
||||
|
||||
if (!this._textAndAdjustedOffsets) {
|
||||
let result = {startOffset: this.startOffset,
|
||||
endOffset: this.endOffset,
|
||||
text: this._accessible.QueryInterface(Ci.nsIAccessibleText).
|
||||
getText(0,
|
||||
Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT)};
|
||||
let result = {
|
||||
startOffset: this.startOffset,
|
||||
endOffset: this.endOffset,
|
||||
text: this._accessible
|
||||
.QueryInterface(Ci.nsIAccessibleText)
|
||||
.getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT),
|
||||
};
|
||||
let hypertextAcc = this._accessible.QueryInterface(
|
||||
Ci.nsIAccessibleHyperText);
|
||||
Ci.nsIAccessibleHyperText
|
||||
);
|
||||
|
||||
// Iterate through the links in backwards order so text replacements don't
|
||||
// affect the offsets of links yet to be processed.
|
||||
|
@ -599,9 +702,9 @@ PivotContext.prototype = {
|
|||
let link = hypertextAcc.getLinkAt(i);
|
||||
let linkText = "";
|
||||
if (link instanceof Ci.nsIAccessibleText) {
|
||||
linkText = link.QueryInterface(Ci.nsIAccessibleText).
|
||||
getText(0,
|
||||
Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
|
||||
linkText = link
|
||||
.QueryInterface(Ci.nsIAccessibleText)
|
||||
.getText(0, Ci.nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT);
|
||||
}
|
||||
|
||||
let start = link.startIndex;
|
||||
|
@ -611,8 +714,10 @@ PivotContext.prototype = {
|
|||
result[offset] += linkText.length - (end - start);
|
||||
}
|
||||
}
|
||||
result.text = result.text.substring(0, start) + linkText +
|
||||
result.text.substring(end);
|
||||
result.text =
|
||||
result.text.substring(0, start) +
|
||||
linkText +
|
||||
result.text.substring(end);
|
||||
}
|
||||
|
||||
this._textAndAdjustedOffsets = result;
|
||||
|
@ -631,7 +736,7 @@ PivotContext.prototype = {
|
|||
let parent = aAccessible;
|
||||
try {
|
||||
while (parent && (parent = parent.parent)) {
|
||||
ancestry.push(parent);
|
||||
ancestry.push(parent);
|
||||
}
|
||||
} catch (x) {
|
||||
// A defunct accessible will raise an exception geting parent.
|
||||
|
@ -660,8 +765,9 @@ PivotContext.prototype = {
|
|||
*/
|
||||
get currentAncestry() {
|
||||
if (!this._currentAncestry) {
|
||||
this._currentAncestry = this._ignoreAncestry ? [] :
|
||||
this._getAncestry(this.accessible);
|
||||
this._currentAncestry = this._ignoreAncestry
|
||||
? []
|
||||
: this._getAncestry(this.accessible);
|
||||
}
|
||||
return this._currentAncestry;
|
||||
},
|
||||
|
@ -673,9 +779,11 @@ PivotContext.prototype = {
|
|||
*/
|
||||
get newAncestry() {
|
||||
if (!this._newAncestry) {
|
||||
this._newAncestry = this._ignoreAncestry ? [] :
|
||||
this.currentAncestry.filter(
|
||||
(currentAncestor, i) => currentAncestor !== this.oldAncestry[i]);
|
||||
this._newAncestry = this._ignoreAncestry
|
||||
? []
|
||||
: this.currentAncestry.filter(
|
||||
(currentAncestor, i) => currentAncestor !== this.oldAncestry[i]
|
||||
);
|
||||
}
|
||||
return this._newAncestry;
|
||||
},
|
||||
|
@ -716,17 +824,23 @@ PivotContext.prototype = {
|
|||
*/
|
||||
get interactionHints() {
|
||||
let hints = [];
|
||||
this.newAncestry.concat(this.accessible).reverse().forEach(aAccessible => {
|
||||
let hint = Utils.getAttributes(aAccessible)["moz-hint"];
|
||||
if (hint) {
|
||||
hints.push(hint);
|
||||
} else if (aAccessible.actionCount > 0) {
|
||||
hints.push({
|
||||
string: Utils.AccService.getStringRole(
|
||||
aAccessible.role).replace(/\s/g, "") + "-hint",
|
||||
});
|
||||
}
|
||||
});
|
||||
this.newAncestry
|
||||
.concat(this.accessible)
|
||||
.reverse()
|
||||
.forEach(aAccessible => {
|
||||
let hint = Utils.getAttributes(aAccessible)["moz-hint"];
|
||||
if (hint) {
|
||||
hints.push(hint);
|
||||
} else if (aAccessible.actionCount > 0) {
|
||||
hints.push({
|
||||
string:
|
||||
Utils.AccService.getStringRole(aAccessible.role).replace(
|
||||
/\s/g,
|
||||
""
|
||||
) + "-hint",
|
||||
});
|
||||
}
|
||||
});
|
||||
return hints;
|
||||
},
|
||||
|
||||
|
@ -758,13 +872,15 @@ PivotContext.prototype = {
|
|||
if (!aAccessible) {
|
||||
return null;
|
||||
}
|
||||
if (![
|
||||
Roles.CELL,
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.MATHML_CELL,
|
||||
].includes(aAccessible.role)) {
|
||||
return null;
|
||||
if (
|
||||
![
|
||||
Roles.CELL,
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.MATHML_CELL,
|
||||
].includes(aAccessible.role)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return aAccessible.QueryInterface(Ci.nsIAccessibleTableCell);
|
||||
|
@ -774,7 +890,7 @@ PivotContext.prototype = {
|
|||
}
|
||||
};
|
||||
let getHeaders = function* getHeaders(aHeaderCells) {
|
||||
for (let {name} of aHeaderCells.enumerate(Ci.nsIAccessible)) {
|
||||
for (let { name } of aHeaderCells.enumerate(Ci.nsIAccessible)) {
|
||||
yield name;
|
||||
}
|
||||
};
|
||||
|
@ -782,8 +898,10 @@ PivotContext.prototype = {
|
|||
cellInfo.current = getAccessibleCell(aAccessible);
|
||||
|
||||
if (!cellInfo.current) {
|
||||
Logger.warning(aAccessible,
|
||||
"does not support nsIAccessibleTableCell interface.");
|
||||
Logger.warning(
|
||||
aAccessible,
|
||||
"does not support nsIAccessibleTableCell interface."
|
||||
);
|
||||
this._cells.set(domNode, null);
|
||||
return null;
|
||||
}
|
||||
|
@ -806,10 +924,10 @@ PivotContext.prototype = {
|
|||
}
|
||||
|
||||
if (cellInfo.previous) {
|
||||
cellInfo.rowChanged = cellInfo.current.rowIndex !==
|
||||
cellInfo.previous.rowIndex;
|
||||
cellInfo.columnChanged = cellInfo.current.columnIndex !==
|
||||
cellInfo.previous.columnIndex;
|
||||
cellInfo.rowChanged =
|
||||
cellInfo.current.rowIndex !== cellInfo.previous.rowIndex;
|
||||
cellInfo.columnChanged =
|
||||
cellInfo.current.columnIndex !== cellInfo.previous.columnIndex;
|
||||
} else {
|
||||
cellInfo.rowChanged = true;
|
||||
cellInfo.columnChanged = true;
|
||||
|
@ -821,14 +939,20 @@ PivotContext.prototype = {
|
|||
cellInfo.rowIndex = cellInfo.current.rowIndex;
|
||||
|
||||
cellInfo.columnHeaders = [];
|
||||
if (cellInfo.columnChanged && cellInfo.current.role !==
|
||||
Roles.COLUMNHEADER) {
|
||||
cellInfo.columnHeaders = [...getHeaders(cellInfo.current.columnHeaderCells)];
|
||||
if (
|
||||
cellInfo.columnChanged &&
|
||||
cellInfo.current.role !== Roles.COLUMNHEADER
|
||||
) {
|
||||
cellInfo.columnHeaders = [
|
||||
...getHeaders(cellInfo.current.columnHeaderCells),
|
||||
];
|
||||
}
|
||||
cellInfo.rowHeaders = [];
|
||||
if (cellInfo.rowChanged &&
|
||||
(cellInfo.current.role === Roles.CELL ||
|
||||
cellInfo.current.role === Roles.MATHML_CELL)) {
|
||||
if (
|
||||
cellInfo.rowChanged &&
|
||||
(cellInfo.current.role === Roles.CELL ||
|
||||
cellInfo.current.role === Roles.MATHML_CELL)
|
||||
) {
|
||||
cellInfo.rowHeaders = [...getHeaders(cellInfo.current.rowHeaderCells)];
|
||||
}
|
||||
|
||||
|
@ -853,7 +977,8 @@ PivotContext.prototype = {
|
|||
},
|
||||
};
|
||||
|
||||
function PrefCache(aName, aCallback, aRunCallbackNow) { // jshint ignore:line
|
||||
function PrefCache(aName, aCallback, aRunCallbackNow) {
|
||||
// jshint ignore:line
|
||||
this.name = aName;
|
||||
this.callback = aCallback;
|
||||
|
||||
|
@ -905,6 +1030,8 @@ PrefCache.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference,
|
||||
]),
|
||||
};
|
||||
|
|
|
@ -4,16 +4,31 @@
|
|||
|
||||
/* eslint-env mozilla/frame-script */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "EventManager",
|
||||
"resource://gre/modules/accessibility/EventManager.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ContentControl",
|
||||
"resource://gre/modules/accessibility/ContentControl.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "States",
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"EventManager",
|
||||
"resource://gre/modules/accessibility/EventManager.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ContentControl",
|
||||
"resource://gre/modules/accessibility/ContentControl.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"States",
|
||||
"resource://gre/modules/accessibility/Constants.jsm"
|
||||
);
|
||||
|
||||
Logger.info("content-script.js", content.document.location);
|
||||
|
||||
|
|
|
@ -13,15 +13,19 @@ async function testScaledBounds(browser, accDoc, scale, id, type = "object") {
|
|||
let [docX, docY] = getBounds(accDoc);
|
||||
|
||||
// Get the unscaled bounds of the accessible
|
||||
let [x, y, width, height] = type == "text" ?
|
||||
getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE) : getBounds(acc);
|
||||
let [x, y, width, height] =
|
||||
type == "text"
|
||||
? getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE)
|
||||
: getBounds(acc);
|
||||
|
||||
await ContentTask.spawn(browser, scale, _scale => {
|
||||
setResolution(content.document, _scale);
|
||||
});
|
||||
|
||||
let [scaledX, scaledY, scaledWidth, scaledHeight] = type == "text" ?
|
||||
getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE) : getBounds(acc);
|
||||
let [scaledX, scaledY, scaledWidth, scaledHeight] =
|
||||
type == "text"
|
||||
? getRangeExtents(acc, 0, -1, COORDTYPE_SCREEN_RELATIVE)
|
||||
: getBounds(acc);
|
||||
|
||||
let name = prettyName(acc);
|
||||
isWithin(scaledWidth, width * scale, 2, "Wrong scaled width of " + name);
|
||||
|
@ -48,7 +52,8 @@ async function runTests(browser, accDoc) {
|
|||
/**
|
||||
* Test accessible boundaries when page is zoomed
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p>
|
||||
<p id="p2">para 2</p>
|
||||
<button id="b1">Hello</button>
|
||||
|
|
|
@ -16,8 +16,12 @@ async function getContentBoundsForDOMElm(browser, id) {
|
|||
}
|
||||
|
||||
async function testContentBounds(browser, acc) {
|
||||
let [expectedX, expectedY, expectedWidth, expectedHeight] =
|
||||
await getContentBoundsForDOMElm(browser, getAccessibleDOMNodeID(acc));
|
||||
let [
|
||||
expectedX,
|
||||
expectedY,
|
||||
expectedWidth,
|
||||
expectedHeight,
|
||||
] = await getContentBoundsForDOMElm(browser, getAccessibleDOMNodeID(acc));
|
||||
|
||||
let contentDPR = await getContentDPR(browser);
|
||||
let [x, y, width, height] = getBounds(acc, contentDPR);
|
||||
|
@ -58,7 +62,8 @@ async function runTests(browser, accDoc) {
|
|||
/**
|
||||
* Test accessible boundaries when page is zoomed
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id="p1">para 1</p><p id="p2">para 2</p>
|
||||
<map name="atoz_map" id="map">
|
||||
<area id="area1" href="http://mozilla.org"
|
||||
|
|
|
@ -15,18 +15,33 @@ async function runTests(browser, accDoc) {
|
|||
|
||||
let contentDPR = await getContentDPR(browser);
|
||||
let [x, y, width, height] = getBounds(textNode, contentDPR);
|
||||
testTextBounds(hyperTextNode, 0, -1, [x, y, width, height],
|
||||
COORDTYPE_SCREEN_RELATIVE);
|
||||
testTextBounds(
|
||||
hyperTextNode,
|
||||
0,
|
||||
-1,
|
||||
[x, y, width, height],
|
||||
COORDTYPE_SCREEN_RELATIVE
|
||||
);
|
||||
}
|
||||
|
||||
async function testEmptyInputNode(id) {
|
||||
let inputNode = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
let [x, y, width, height] = getBounds(inputNode);
|
||||
testTextBounds(inputNode, 0, -1, [x, y, width, height],
|
||||
COORDTYPE_SCREEN_RELATIVE);
|
||||
testTextBounds(inputNode, 0, 0, [x, y, width, height],
|
||||
COORDTYPE_SCREEN_RELATIVE);
|
||||
testTextBounds(
|
||||
inputNode,
|
||||
0,
|
||||
-1,
|
||||
[x, y, width, height],
|
||||
COORDTYPE_SCREEN_RELATIVE
|
||||
);
|
||||
testTextBounds(
|
||||
inputNode,
|
||||
0,
|
||||
0,
|
||||
[x, y, width, height],
|
||||
COORDTYPE_SCREEN_RELATIVE
|
||||
);
|
||||
}
|
||||
|
||||
loadFrameScripts(browser, { name: "layout.js", dir: MOCHITESTS_DIR });
|
||||
|
@ -49,8 +64,10 @@ async function runTests(browser, accDoc) {
|
|||
/**
|
||||
* Test the text range boundary when page is zoomed
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id='p1' style='font-family: monospace;'>Tilimilitryamdiya</p>
|
||||
<p id='p2'>ل</p>
|
||||
<form><input id='i1' /></form>`, runTests
|
||||
<form><input id='i1' /></form>`,
|
||||
runTests
|
||||
);
|
||||
|
|
|
@ -11,16 +11,24 @@
|
|||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
loadScripts({ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "layout.js", dir: MOCHITESTS_DIR }, "events.js");
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "layout.js", dir: MOCHITESTS_DIR },
|
||||
"events.js"
|
||||
);
|
||||
|
||||
/**
|
||||
* Get content window DPR that can be different from parent window DPR.
|
||||
*/
|
||||
async function getContentDPR(browser) {
|
||||
return ContentTask.spawn(browser, null, () => content.window.devicePixelRatio);
|
||||
return ContentTask.spawn(
|
||||
browser,
|
||||
null,
|
||||
() => content.window.devicePixelRatio
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ add_task(async function() {
|
|||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
|
||||
await a11yInit;
|
||||
ok(accService, "Service initialized");
|
||||
|
@ -31,8 +32,12 @@ add_task(async function() {
|
|||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
|
|
|
@ -8,7 +8,8 @@ add_task(async function() {
|
|||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
|
||||
await a11yInit;
|
||||
ok(accService, "Service initialized");
|
||||
|
@ -23,8 +24,12 @@ add_task(async function() {
|
|||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
|
|
|
@ -8,7 +8,8 @@ add_task(async function() {
|
|||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
|
||||
await a11yInit;
|
||||
ok(accService, "Service initialized");
|
||||
|
@ -34,8 +35,12 @@ add_task(async function() {
|
|||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
|
|
|
@ -8,7 +8,8 @@ add_task(async function() {
|
|||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
|
||||
await a11yInit;
|
||||
ok(accService, "Service initialized");
|
||||
|
@ -34,8 +35,12 @@ add_task(async function() {
|
|||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
|
|
|
@ -9,67 +9,77 @@ add_task(async function() {
|
|||
await setE10sPrefs();
|
||||
|
||||
let docLoaded = waitForEvent(
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, "body");
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE,
|
||||
"body"
|
||||
);
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized");
|
||||
await a11yInit;
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body id="body"><div id="div"></div></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
let docLoadedEvent = await docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, "Accessible document proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
let docLoadedEvent = await docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, "Accessible document proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
|
||||
let acc = docAcc.getChildAt(0);
|
||||
ok(acc, "Accessible proxy is created");
|
||||
let acc = docAcc.getChildAt(0);
|
||||
ok(acc, "Accessible proxy is created");
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Remove a reference to an accessible proxy.
|
||||
acc = null;
|
||||
ok(!acc, "Accessible proxy is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible document proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
// Remove a reference to an accessible proxy.
|
||||
acc = null;
|
||||
ok(!acc, "Accessible proxy is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible document proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, "Accessible document proxy is removed");
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, "Accessible document proxy is removed");
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
});
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
}
|
||||
);
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
|
|
|
@ -9,67 +9,77 @@ add_task(async function() {
|
|||
await setE10sPrefs();
|
||||
|
||||
let docLoaded = waitForEvent(
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, "body");
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE,
|
||||
"body"
|
||||
);
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized");
|
||||
await a11yInit;
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body id="body"><div id="div"></div></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
let docLoadedEvent = await docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, "Accessible document proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
let docLoadedEvent = await docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, "Accessible document proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
|
||||
let acc = docAcc.getChildAt(0);
|
||||
ok(acc, "Accessible proxy is created");
|
||||
let acc = docAcc.getChildAt(0);
|
||||
ok(acc, "Accessible proxy is created");
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Remove a reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, "Accessible document proxy is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
// Remove a reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, "Accessible document proxy is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there is
|
||||
// a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible proxy.
|
||||
acc = null;
|
||||
ok(!acc, "Accessible proxy is removed");
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible proxy.
|
||||
acc = null;
|
||||
ok(!acc, "Accessible proxy is removed");
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
});
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
}
|
||||
);
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
|
|
|
@ -9,14 +9,16 @@ add_task(async function() {
|
|||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService1 = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
await a11yInit;
|
||||
ok(accService1, "Service initialized");
|
||||
|
||||
// Add another reference to a11y service. This will not trigger
|
||||
// 'a11y-init-or-shutdown' event
|
||||
let accService2 = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService2, "Service initialized");
|
||||
|
||||
info("Removing all service references");
|
||||
|
@ -25,8 +27,12 @@ add_task(async function() {
|
|||
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
|
||||
// down, the promise will reject.
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ?
|
||||
resolve() : reject("Accessible service was shut down incorrectly")));
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
// Remove first a11y service reference.
|
||||
accService1 = null;
|
||||
ok(!accService1, "Service is removed");
|
||||
|
|
|
@ -8,65 +8,85 @@ add_task(async function() {
|
|||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
await setE10sPrefs();
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
info("Creating a service in parent and waiting for service to be created " +
|
||||
"in content");
|
||||
// Create a11y service in the main process. This will trigger creating of
|
||||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
info(
|
||||
"Creating a service in parent and waiting for service to be created " +
|
||||
"in content"
|
||||
);
|
||||
// Create a11y service in the main process. This will trigger creating of
|
||||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
|
||||
info("Adding additional reference to accessibility service in content " +
|
||||
"process");
|
||||
// Add a new reference to the a11y service inside the content process.
|
||||
loadFrameScripts(browser, `let accService = Components.classes[
|
||||
info(
|
||||
"Adding additional reference to accessibility service in content " +
|
||||
"process"
|
||||
);
|
||||
// Add a new reference to the a11y service inside the content process.
|
||||
loadFrameScripts(
|
||||
browser,
|
||||
`let accService = Components.classes[
|
||||
'@mozilla.org/accessibilityService;1'].getService(
|
||||
Components.interfaces.nsIAccessibilityService);`);
|
||||
Components.interfaces.nsIAccessibilityService);`
|
||||
);
|
||||
|
||||
info("Trying to shut down a service in content and making sure it stays " +
|
||||
"alive as it was started by parent");
|
||||
let contentCanShutdown = false;
|
||||
// This promise will resolve only if contentCanShutdown flag is set to true.
|
||||
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
|
||||
// it can be shut down, the promise will reject.
|
||||
let contentA11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise(browser).then(flag => contentCanShutdown ?
|
||||
resolve() : reject("Accessible service was shut down incorrectly")));
|
||||
// Remove a11y service reference in content and force garbage collection.
|
||||
// This should not trigger shutdown since a11y was originally initialized by
|
||||
// the main process.
|
||||
loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
|
||||
info(
|
||||
"Trying to shut down a service in content and making sure it stays " +
|
||||
"alive as it was started by parent"
|
||||
);
|
||||
let contentCanShutdown = false;
|
||||
// This promise will resolve only if contentCanShutdown flag is set to true.
|
||||
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
|
||||
// it can be shut down, the promise will reject.
|
||||
let contentA11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise(browser).then(flag =>
|
||||
contentCanShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
// Remove a11y service reference in content and force garbage collection.
|
||||
// This should not trigger shutdown since a11y was originally initialized by
|
||||
// the main process.
|
||||
loadFrameScripts(
|
||||
browser,
|
||||
`accService = null; Components.utils.forceGC();`
|
||||
);
|
||||
|
||||
// Have some breathing room between a11y service shutdowns.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
// Have some breathing room between a11y service shutdowns.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
info("Removing a service in parent");
|
||||
// Now allow a11y service to shutdown in content.
|
||||
contentCanShutdown = true;
|
||||
// Remove the a11y service reference in the main process.
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed in parent");
|
||||
// Force garbage collection that should trigger shutdown in both parent and
|
||||
// content.
|
||||
forceGC();
|
||||
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
|
||||
info("Removing a service in parent");
|
||||
// Now allow a11y service to shutdown in content.
|
||||
contentCanShutdown = true;
|
||||
// Remove the a11y service reference in the main process.
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed in parent");
|
||||
// Force garbage collection that should trigger shutdown in both parent and
|
||||
// content.
|
||||
forceGC();
|
||||
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
});
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
|
||||
|
||||
add_task(async function testForceDisable() {
|
||||
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled by default");
|
||||
ok(
|
||||
!Services.appinfo.accessibilityEnabled,
|
||||
"Accessibility is disabled by default"
|
||||
);
|
||||
|
||||
info("Reset force disabled preference");
|
||||
Services.prefs.clearUserPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
|
||||
|
@ -15,7 +18,8 @@ add_task(async function testForceDisable() {
|
|||
info("Enable accessibility service via XPCOM");
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
await a11yInit;
|
||||
ok(Services.appinfo.accessibilityEnabled, "Accessibility is enabled");
|
||||
|
||||
|
@ -27,12 +31,16 @@ add_task(async function testForceDisable() {
|
|||
|
||||
info("Attempt to get an instance of a11y service and call its method.");
|
||||
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
try {
|
||||
accService.getAccesssibleFor(document);
|
||||
ok(false, "getAccesssibleFor should've triggered an exception.");
|
||||
} catch (e) {
|
||||
ok(true, "getAccesssibleFor triggers an exception as a11y service is shutdown.");
|
||||
ok(
|
||||
true,
|
||||
"getAccesssibleFor triggers an exception as a11y service is shutdown."
|
||||
);
|
||||
}
|
||||
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled");
|
||||
|
||||
|
@ -42,7 +50,8 @@ add_task(async function testForceDisable() {
|
|||
info("Create a11y service again");
|
||||
a11yInit = initPromise();
|
||||
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
await a11yInit;
|
||||
ok(Services.appinfo.accessibilityEnabled, "Accessibility is enabled");
|
||||
|
||||
|
|
|
@ -10,54 +10,62 @@ add_task(async function() {
|
|||
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized");
|
||||
await a11yInit;
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body><div id="div" style="visibility: hidden;"></div></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
let onShow = waitForEvent(Ci.nsIAccessibleEvent.EVENT_SHOW, "div");
|
||||
await invokeSetStyle(browser, "div", "visibility", "visible");
|
||||
let showEvent = await onShow;
|
||||
let divAcc = showEvent.accessible;
|
||||
ok(divAcc, "Accessible proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
onShow = null;
|
||||
showEvent = null;
|
||||
forceGC();
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
let onShow = waitForEvent(Ci.nsIAccessibleEvent.EVENT_SHOW, "div");
|
||||
await invokeSetStyle(browser, "div", "visibility", "visible");
|
||||
let showEvent = await onShow;
|
||||
let divAcc = showEvent.accessible;
|
||||
ok(divAcc, "Accessible proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
onShow = null;
|
||||
showEvent = null;
|
||||
forceGC();
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible proxy.
|
||||
divAcc = null;
|
||||
ok(!divAcc, "Accessible proxy is removed");
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible proxy.
|
||||
divAcc = null;
|
||||
ok(!divAcc, "Accessible proxy is removed");
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
});
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
}
|
||||
);
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
|
|
|
@ -9,55 +9,65 @@ add_task(async function() {
|
|||
await setE10sPrefs();
|
||||
|
||||
let docLoaded = waitForEvent(
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, "body");
|
||||
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE,
|
||||
"body"
|
||||
);
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized");
|
||||
await a11yInit;
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body id="body"></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
let docLoadedEvent = await docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, "Accessible document proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
let docLoadedEvent = await docLoaded;
|
||||
let docAcc = docLoadedEvent.accessibleDocument;
|
||||
ok(docAcc, "Accessible document proxy is created");
|
||||
// Remove unnecessary dangling references
|
||||
docLoaded = null;
|
||||
docLoadedEvent = null;
|
||||
forceGC();
|
||||
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag => canShutdown ? resolve() :
|
||||
reject("Accessible service was shut down incorrectly")));
|
||||
let canShutdown = false;
|
||||
let a11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise().then(flag =>
|
||||
canShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference to an accessible proxy.
|
||||
forceGC();
|
||||
// Have some breathing room when removing a11y service references.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, "Accessible document proxy is removed");
|
||||
// Now allow a11y service to shutdown.
|
||||
canShutdown = true;
|
||||
// Remove a last reference to an accessible document proxy.
|
||||
docAcc = null;
|
||||
ok(!docAcc, "Accessible document proxy is removed");
|
||||
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
});
|
||||
// Force garbage collection that should now trigger shutdown.
|
||||
forceGC();
|
||||
await a11yShutdown;
|
||||
}
|
||||
);
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
|
|
|
@ -8,62 +8,114 @@ add_task(async function() {
|
|||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
await setE10sPrefs();
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
info("Creating a service in parent and waiting for service to be created " +
|
||||
"in content");
|
||||
// Create a11y service in the main process. This will trigger creating of
|
||||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let parentConsumersChanged = a11yConsumersChangedPromise();
|
||||
let contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
await parentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: true, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers in parent are correct."));
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: true, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
info(
|
||||
"Creating a service in parent and waiting for service to be created " +
|
||||
"in content"
|
||||
);
|
||||
// Create a11y service in the main process. This will trigger creating of
|
||||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let parentConsumersChanged = a11yConsumersChangedPromise();
|
||||
let contentConsumersChanged = ContentTask.spawn(
|
||||
browser,
|
||||
{},
|
||||
a11yConsumersChangedPromise
|
||||
);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
await parentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: true,
|
||||
MainProcess: false,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in parent are correct."
|
||||
)
|
||||
);
|
||||
await contentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: false,
|
||||
MainProcess: true,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in content are correct."
|
||||
)
|
||||
);
|
||||
|
||||
Assert.deepEqual(JSON.parse(accService.getConsumers()), {
|
||||
XPCOM: true, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers in parent are correct.");
|
||||
Assert.deepEqual(
|
||||
JSON.parse(accService.getConsumers()),
|
||||
{
|
||||
XPCOM: true,
|
||||
MainProcess: false,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in parent are correct."
|
||||
);
|
||||
|
||||
info("Removing a service in parent and waiting for service to be shut " +
|
||||
"down in content");
|
||||
// Remove a11y service reference in the main process.
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
let contentA11yShutdown = shutdownPromise(browser);
|
||||
parentConsumersChanged = a11yConsumersChangedPromise();
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed in parent");
|
||||
// Force garbage collection that should trigger shutdown in both main and
|
||||
// content process.
|
||||
forceGC();
|
||||
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
|
||||
await parentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers are correct."));
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers are correct."));
|
||||
});
|
||||
info(
|
||||
"Removing a service in parent and waiting for service to be shut " +
|
||||
"down in content"
|
||||
);
|
||||
// Remove a11y service reference in the main process.
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
let contentA11yShutdown = shutdownPromise(browser);
|
||||
parentConsumersChanged = a11yConsumersChangedPromise();
|
||||
contentConsumersChanged = ContentTask.spawn(
|
||||
browser,
|
||||
{},
|
||||
a11yConsumersChangedPromise
|
||||
);
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed in parent");
|
||||
// Force garbage collection that should trigger shutdown in both main and
|
||||
// content process.
|
||||
forceGC();
|
||||
await Promise.all([parentA11yShutdown, contentA11yShutdown]);
|
||||
await parentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: false,
|
||||
MainProcess: false,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers are correct."
|
||||
)
|
||||
);
|
||||
await contentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: false,
|
||||
MainProcess: false,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers are correct."
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
|
|
|
@ -8,33 +8,42 @@ add_task(async function() {
|
|||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
await setE10sPrefs();
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
info("Creating a service in content");
|
||||
// Create a11y service in the content process.
|
||||
let a11yInit = initPromise(browser);
|
||||
loadFrameScripts(browser, `let accService = Components.classes[
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
info("Creating a service in content");
|
||||
// Create a11y service in the content process.
|
||||
let a11yInit = initPromise(browser);
|
||||
loadFrameScripts(
|
||||
browser,
|
||||
`let accService = Components.classes[
|
||||
'@mozilla.org/accessibilityService;1'].getService(
|
||||
Components.interfaces.nsIAccessibilityService);`);
|
||||
await a11yInit;
|
||||
Components.interfaces.nsIAccessibilityService);`
|
||||
);
|
||||
await a11yInit;
|
||||
|
||||
info("Removing a service in content");
|
||||
// Remove a11y service reference from the content process.
|
||||
let a11yShutdown = shutdownPromise(browser);
|
||||
// Force garbage collection that should trigger shutdown.
|
||||
loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
|
||||
await a11yShutdown;
|
||||
info("Removing a service in content");
|
||||
// Remove a11y service reference from the content process.
|
||||
let a11yShutdown = shutdownPromise(browser);
|
||||
// Force garbage collection that should trigger shutdown.
|
||||
loadFrameScripts(
|
||||
browser,
|
||||
`accService = null; Components.utils.forceGC();`
|
||||
);
|
||||
await a11yShutdown;
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
});
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -8,94 +8,165 @@ add_task(async function() {
|
|||
// Making sure that the e10s is enabled on Windows for testing.
|
||||
await setE10sPrefs();
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: `data:text/html,
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>`
|
||||
}, async function(browser) {
|
||||
info("Creating a service in parent and waiting for service to be created " +
|
||||
"in content");
|
||||
// Create a11y service in the main process. This will trigger creating of
|
||||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: true, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
</html>`,
|
||||
},
|
||||
async function(browser) {
|
||||
info(
|
||||
"Creating a service in parent and waiting for service to be created " +
|
||||
"in content"
|
||||
);
|
||||
// Create a11y service in the main process. This will trigger creating of
|
||||
// the a11y service in parent as well.
|
||||
let parentA11yInit = initPromise();
|
||||
let contentA11yInit = initPromise(browser);
|
||||
let contentConsumersChanged = ContentTask.spawn(
|
||||
browser,
|
||||
{},
|
||||
a11yConsumersChangedPromise
|
||||
);
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized in parent");
|
||||
await Promise.all([parentA11yInit, contentA11yInit]);
|
||||
await contentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: false,
|
||||
MainProcess: true,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in content are correct."
|
||||
)
|
||||
);
|
||||
|
||||
info("Adding additional reference to accessibility service in content " +
|
||||
"process");
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
// Add a new reference to the a11y service inside the content process.
|
||||
loadFrameScripts(browser, `var accService = Components.classes[
|
||||
info(
|
||||
"Adding additional reference to accessibility service in content " +
|
||||
"process"
|
||||
);
|
||||
contentConsumersChanged = ContentTask.spawn(
|
||||
browser,
|
||||
{},
|
||||
a11yConsumersChangedPromise
|
||||
);
|
||||
// Add a new reference to the a11y service inside the content process.
|
||||
loadFrameScripts(
|
||||
browser,
|
||||
`var accService = Components.classes[
|
||||
'@mozilla.org/accessibilityService;1'].getService(
|
||||
Components.interfaces.nsIAccessibilityService);`);
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: true, MainProcess: true, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
Components.interfaces.nsIAccessibilityService);`
|
||||
);
|
||||
await contentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: true,
|
||||
MainProcess: true,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in content are correct."
|
||||
)
|
||||
);
|
||||
|
||||
const contentConsumers = await ContentTask.spawn(browser, {}, () =>
|
||||
accService.getConsumers());
|
||||
Assert.deepEqual(JSON.parse(contentConsumers), {
|
||||
XPCOM: true, MainProcess: true, PlatformAPI: false
|
||||
}, "Accessibility service consumers in parent are correct.");
|
||||
const contentConsumers = await ContentTask.spawn(browser, {}, () =>
|
||||
accService.getConsumers()
|
||||
);
|
||||
Assert.deepEqual(
|
||||
JSON.parse(contentConsumers),
|
||||
{
|
||||
XPCOM: true,
|
||||
MainProcess: true,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in parent are correct."
|
||||
);
|
||||
|
||||
info("Shutting down a service in parent and making sure the one in " +
|
||||
"content stays alive");
|
||||
let contentCanShutdown = false;
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
// This promise will resolve only if contentCanShutdown flag is set to true.
|
||||
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
|
||||
// it can be shut down, the promise will reject.
|
||||
let contentA11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise(browser).then(flag => contentCanShutdown ?
|
||||
resolve() : reject("Accessible service was shut down incorrectly")));
|
||||
// Remove a11y service reference in the main process and force garbage
|
||||
// collection. This should not trigger shutdown in content since a11y
|
||||
// service is used by XPCOM.
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed in parent");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference in a content process.
|
||||
forceGC();
|
||||
loadFrameScripts(browser, `Components.utils.forceGC();`);
|
||||
await parentA11yShutdown;
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: true, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
info(
|
||||
"Shutting down a service in parent and making sure the one in " +
|
||||
"content stays alive"
|
||||
);
|
||||
let contentCanShutdown = false;
|
||||
let parentA11yShutdown = shutdownPromise();
|
||||
contentConsumersChanged = ContentTask.spawn(
|
||||
browser,
|
||||
{},
|
||||
a11yConsumersChangedPromise
|
||||
);
|
||||
// This promise will resolve only if contentCanShutdown flag is set to true.
|
||||
// If 'a11y-init-or-shutdown' event with '0' flag (in content) comes before
|
||||
// it can be shut down, the promise will reject.
|
||||
let contentA11yShutdown = new Promise((resolve, reject) =>
|
||||
shutdownPromise(browser).then(flag =>
|
||||
contentCanShutdown
|
||||
? resolve()
|
||||
: reject("Accessible service was shut down incorrectly")
|
||||
)
|
||||
);
|
||||
// Remove a11y service reference in the main process and force garbage
|
||||
// collection. This should not trigger shutdown in content since a11y
|
||||
// service is used by XPCOM.
|
||||
accService = null;
|
||||
ok(!accService, "Service is removed in parent");
|
||||
// Force garbage collection that should not trigger shutdown because there
|
||||
// is a reference in a content process.
|
||||
forceGC();
|
||||
loadFrameScripts(browser, `Components.utils.forceGC();`);
|
||||
await parentA11yShutdown;
|
||||
await contentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: true,
|
||||
MainProcess: false,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in content are correct."
|
||||
)
|
||||
);
|
||||
|
||||
// Have some breathing room between a11y service shutdowns.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
// Have some breathing room between a11y service shutdowns.
|
||||
await new Promise(resolve => executeSoon(resolve));
|
||||
|
||||
info("Removing a service in content");
|
||||
// Now allow a11y service to shutdown in content.
|
||||
contentCanShutdown = true;
|
||||
contentConsumersChanged =
|
||||
ContentTask.spawn(browser, {}, a11yConsumersChangedPromise);
|
||||
// Remove last reference to a11y service in content and force garbage
|
||||
// collection that should trigger shutdown.
|
||||
loadFrameScripts(browser, `accService = null; Components.utils.forceGC();`);
|
||||
await contentA11yShutdown;
|
||||
await contentConsumersChanged.then(data => Assert.deepEqual(data, {
|
||||
XPCOM: false, MainProcess: false, PlatformAPI: false
|
||||
}, "Accessibility service consumers in content are correct."));
|
||||
info("Removing a service in content");
|
||||
// Now allow a11y service to shutdown in content.
|
||||
contentCanShutdown = true;
|
||||
contentConsumersChanged = ContentTask.spawn(
|
||||
browser,
|
||||
{},
|
||||
a11yConsumersChangedPromise
|
||||
);
|
||||
// Remove last reference to a11y service in content and force garbage
|
||||
// collection that should trigger shutdown.
|
||||
loadFrameScripts(
|
||||
browser,
|
||||
`accService = null; Components.utils.forceGC();`
|
||||
);
|
||||
await contentA11yShutdown;
|
||||
await contentConsumersChanged.then(data =>
|
||||
Assert.deepEqual(
|
||||
data,
|
||||
{
|
||||
XPCOM: false,
|
||||
MainProcess: false,
|
||||
PlatformAPI: false,
|
||||
},
|
||||
"Accessibility service consumers in content are correct."
|
||||
)
|
||||
);
|
||||
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
});
|
||||
// Unsetting e10s related preferences.
|
||||
await unsetE10sPrefs();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -11,7 +11,8 @@ add_task(async function() {
|
|||
|
||||
(function() {
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
ok(accService, "Service initialized");
|
||||
})();
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ add_task(async function() {
|
|||
// Create a11y service.
|
||||
let a11yInit = initPromise();
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
await a11yInit;
|
||||
ok(accService, "Service initialized");
|
||||
|
||||
|
@ -26,7 +27,8 @@ add_task(async function() {
|
|||
// Re-create a11y service.
|
||||
a11yInit = initPromise();
|
||||
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
await a11yInit;
|
||||
ok(accService, "Service initialized again");
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@ const defaultAttributes = {
|
|||
"margin-left": "0px",
|
||||
"text-align": "start",
|
||||
"text-indent": "0px",
|
||||
"id": "textbox",
|
||||
"tag": "input",
|
||||
"display": "inline-block"
|
||||
id: "textbox",
|
||||
tag: "input",
|
||||
display: "inline-block",
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -35,64 +35,81 @@ const defaultAttributes = {
|
|||
* waitFor {?Number} an optional event to wait for
|
||||
* }
|
||||
*/
|
||||
const attributesTests = [{
|
||||
desc: "Initiall accessible attributes",
|
||||
expected: defaultAttributes,
|
||||
unexpected: {
|
||||
"line-number": "1",
|
||||
"explicit-name": "true",
|
||||
"container-live": "polite",
|
||||
"live": "polite"
|
||||
}
|
||||
}, {
|
||||
desc: "@line-number attribute is present when textbox is focused",
|
||||
async action(browser) {
|
||||
await invokeFocus(browser, "textbox");
|
||||
const attributesTests = [
|
||||
{
|
||||
desc: "Initiall accessible attributes",
|
||||
expected: defaultAttributes,
|
||||
unexpected: {
|
||||
"line-number": "1",
|
||||
"explicit-name": "true",
|
||||
"container-live": "polite",
|
||||
live: "polite",
|
||||
},
|
||||
},
|
||||
waitFor: EVENT_FOCUS,
|
||||
expected: Object.assign({}, defaultAttributes, { "line-number": "1" }),
|
||||
unexpected: {
|
||||
"explicit-name": "true",
|
||||
"container-live": "polite",
|
||||
"live": "polite"
|
||||
}
|
||||
}, {
|
||||
desc: "@aria-live sets container-live and live attributes",
|
||||
attrs: [{
|
||||
attr: "aria-live",
|
||||
value: "polite"
|
||||
}],
|
||||
expected: Object.assign({}, defaultAttributes, {
|
||||
"line-number": "1",
|
||||
"container-live": "polite",
|
||||
"live": "polite"
|
||||
}),
|
||||
unexpected: {
|
||||
"explicit-name": "true"
|
||||
}
|
||||
}, {
|
||||
desc: "@title attribute sets explicit-name attribute to true",
|
||||
attrs: [{
|
||||
attr: "title",
|
||||
value: "textbox"
|
||||
}],
|
||||
expected: Object.assign({}, defaultAttributes, {
|
||||
"line-number": "1",
|
||||
"explicit-name": "true",
|
||||
"container-live": "polite",
|
||||
"live": "polite"
|
||||
}),
|
||||
unexpected: {}
|
||||
}];
|
||||
{
|
||||
desc: "@line-number attribute is present when textbox is focused",
|
||||
async action(browser) {
|
||||
await invokeFocus(browser, "textbox");
|
||||
},
|
||||
waitFor: EVENT_FOCUS,
|
||||
expected: Object.assign({}, defaultAttributes, { "line-number": "1" }),
|
||||
unexpected: {
|
||||
"explicit-name": "true",
|
||||
"container-live": "polite",
|
||||
live: "polite",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "@aria-live sets container-live and live attributes",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-live",
|
||||
value: "polite",
|
||||
},
|
||||
],
|
||||
expected: Object.assign({}, defaultAttributes, {
|
||||
"line-number": "1",
|
||||
"container-live": "polite",
|
||||
live: "polite",
|
||||
}),
|
||||
unexpected: {
|
||||
"explicit-name": "true",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "@title attribute sets explicit-name attribute to true",
|
||||
attrs: [
|
||||
{
|
||||
attr: "title",
|
||||
value: "textbox",
|
||||
},
|
||||
],
|
||||
expected: Object.assign({}, defaultAttributes, {
|
||||
"line-number": "1",
|
||||
"explicit-name": "true",
|
||||
"container-live": "polite",
|
||||
live: "polite",
|
||||
}),
|
||||
unexpected: {},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Test caching of accessible object attributes
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<input id="textbox" value="hello">`,
|
||||
async function(browser, accDoc) {
|
||||
let textbox = findAccessibleChildByID(accDoc, "textbox");
|
||||
for (let { desc, action, attrs, expected, waitFor, unexpected } of attributesTests) {
|
||||
for (let {
|
||||
desc,
|
||||
action,
|
||||
attrs,
|
||||
expected,
|
||||
waitFor,
|
||||
unexpected,
|
||||
} of attributesTests) {
|
||||
info(desc);
|
||||
let onUpdate;
|
||||
|
||||
|
|
|
@ -17,123 +17,173 @@ loadScripts({ name: "name.js", dir: MOCHITESTS_DIR });
|
|||
* attributes are updated
|
||||
* }
|
||||
*/
|
||||
const tests = [{
|
||||
desc: "No description when there are no @alt, @title and @aria-describedby",
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "Description from @aria-describedby attribute",
|
||||
attrs: [{
|
||||
attr: "aria-describedby",
|
||||
value: "description"
|
||||
}],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "aria description"
|
||||
}, {
|
||||
desc: "No description from @aria-describedby since it is the same as the " +
|
||||
"@alt attribute which is used as the name",
|
||||
attrs: [{
|
||||
attr: "alt",
|
||||
value: "aria description"
|
||||
}],
|
||||
waitFor: [[EVENT_REORDER, "body"]],
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "Description from @aria-describedby attribute when @alt and " +
|
||||
"@aria-describedby are not the same",
|
||||
attrs: [{
|
||||
attr: "aria-describedby",
|
||||
value: "description2"
|
||||
}],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "another description"
|
||||
}, {
|
||||
desc: "Description from @aria-describedby attribute when @title (used for " +
|
||||
"name) and @aria-describedby are not the same",
|
||||
attrs: [{
|
||||
attr: "alt"
|
||||
}, {
|
||||
attr: "title",
|
||||
value: "title"
|
||||
}],
|
||||
waitFor: [[EVENT_REORDER, "body"]],
|
||||
expected: "another description"
|
||||
}, {
|
||||
desc: "No description from @aria-describedby since it is the same as the " +
|
||||
"@title attribute which is used as the name",
|
||||
attrs: [{
|
||||
attr: "title",
|
||||
value: "another description"
|
||||
}],
|
||||
waitFor: [[EVENT_NAME_CHANGE, "image"]],
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "No description with only @title attribute which is used as the name",
|
||||
attrs: [{
|
||||
attr: "aria-describedby"
|
||||
}],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "Description from @title attribute when @alt and @atitle are not the " +
|
||||
"same",
|
||||
attrs: [{
|
||||
attr: "alt",
|
||||
value: "aria description"
|
||||
}],
|
||||
waitFor: [[EVENT_REORDER, "body"]],
|
||||
expected: "another description"
|
||||
}, {
|
||||
desc: "No description from @title since it is the same as the @alt " +
|
||||
"attribute which is used as the name",
|
||||
attrs: [{
|
||||
attr: "alt",
|
||||
value: "another description"
|
||||
}],
|
||||
waitFor: [[EVENT_NAME_CHANGE, "image"]],
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "No description from @aria-describedby since it is the same as the " +
|
||||
"@alt (used for name) and @title attributes",
|
||||
attrs: [{
|
||||
attr: "aria-describedby",
|
||||
value: "description2"
|
||||
}],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "Description from @aria-describedby attribute when it is different " +
|
||||
"from @alt (used for name) and @title attributes",
|
||||
attrs: [{
|
||||
attr: "aria-describedby",
|
||||
value: "description"
|
||||
}],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "aria description"
|
||||
}, {
|
||||
desc: "No description from @aria-describedby since it is the same as the " +
|
||||
"@alt attribute (used for name) but different from title",
|
||||
attrs: [{
|
||||
attr: "alt",
|
||||
value: "aria description"
|
||||
}],
|
||||
waitFor: [[EVENT_NAME_CHANGE, "image"]],
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "Description from @aria-describedby attribute when @alt (used for " +
|
||||
"name) and @aria-describedby are not the same but @title and " +
|
||||
"aria-describedby are",
|
||||
attrs: [{
|
||||
attr: "aria-describedby",
|
||||
value: "description2"
|
||||
}],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "another description"
|
||||
}];
|
||||
const tests = [
|
||||
{
|
||||
desc: "No description when there are no @alt, @title and @aria-describedby",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "Description from @aria-describedby attribute",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-describedby",
|
||||
value: "description",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "aria description",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"No description from @aria-describedby since it is the same as the " +
|
||||
"@alt attribute which is used as the name",
|
||||
attrs: [
|
||||
{
|
||||
attr: "alt",
|
||||
value: "aria description",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_REORDER, "body"]],
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Description from @aria-describedby attribute when @alt and " +
|
||||
"@aria-describedby are not the same",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-describedby",
|
||||
value: "description2",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "another description",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Description from @aria-describedby attribute when @title (used for " +
|
||||
"name) and @aria-describedby are not the same",
|
||||
attrs: [
|
||||
{
|
||||
attr: "alt",
|
||||
},
|
||||
{
|
||||
attr: "title",
|
||||
value: "title",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_REORDER, "body"]],
|
||||
expected: "another description",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"No description from @aria-describedby since it is the same as the " +
|
||||
"@title attribute which is used as the name",
|
||||
attrs: [
|
||||
{
|
||||
attr: "title",
|
||||
value: "another description",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_NAME_CHANGE, "image"]],
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "No description with only @title attribute which is used as the name",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-describedby",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Description from @title attribute when @alt and @atitle are not the " +
|
||||
"same",
|
||||
attrs: [
|
||||
{
|
||||
attr: "alt",
|
||||
value: "aria description",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_REORDER, "body"]],
|
||||
expected: "another description",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"No description from @title since it is the same as the @alt " +
|
||||
"attribute which is used as the name",
|
||||
attrs: [
|
||||
{
|
||||
attr: "alt",
|
||||
value: "another description",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_NAME_CHANGE, "image"]],
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"No description from @aria-describedby since it is the same as the " +
|
||||
"@alt (used for name) and @title attributes",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-describedby",
|
||||
value: "description2",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Description from @aria-describedby attribute when it is different " +
|
||||
"from @alt (used for name) and @title attributes",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-describedby",
|
||||
value: "description",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "aria description",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"No description from @aria-describedby since it is the same as the " +
|
||||
"@alt attribute (used for name) but different from title",
|
||||
attrs: [
|
||||
{
|
||||
attr: "alt",
|
||||
value: "aria description",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_NAME_CHANGE, "image"]],
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Description from @aria-describedby attribute when @alt (used for " +
|
||||
"name) and @aria-describedby are not the same but @title and " +
|
||||
"aria-describedby are",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-describedby",
|
||||
value: "description2",
|
||||
},
|
||||
],
|
||||
waitFor: [[EVENT_DESCRIPTION_CHANGE, "image"]],
|
||||
expected: "another description",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Test caching of accessible object description
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id="description">aria description</p>
|
||||
<p id="description2">another description</p>
|
||||
<img id="image" />`,
|
||||
|
|
|
@ -31,33 +31,59 @@ const HTMLControlHeadRule = [...ARIARule, { elm: "label", isSibling: true }];
|
|||
const rules = {
|
||||
CSSContent: [{ elm: "style", isSibling: true }, { fromsubtree: true }],
|
||||
HTMLARIAGridCell: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
|
||||
HTMLControl: [...HTMLControlHeadRule, { fromsubtree: true },
|
||||
{ attr: "title" }],
|
||||
HTMLControl: [
|
||||
...HTMLControlHeadRule,
|
||||
{ fromsubtree: true },
|
||||
{ attr: "title" },
|
||||
],
|
||||
HTMLElm: [...ARIARule, { attr: "title" }],
|
||||
HTMLImg: [...ARIARule, { attr: "alt", recreated: true }, { attr: "title" }],
|
||||
HTMLImgEmptyAlt: [...ARIARule, { attr: "title" }, { attr: "alt" }],
|
||||
HTMLInputButton: [...HTMLControlHeadRule, { attr: "value" },
|
||||
{ attr: "title" }],
|
||||
HTMLInputImage: [...HTMLControlHeadRule, { attr: "alt", recreated: true },
|
||||
{ attr: "value", recreated: true }, { attr: "title" }],
|
||||
HTMLInputImageNoValidSrc: [...HTMLControlHeadRule,
|
||||
{ attr: "alt", recreated: true }, { attr: "value", recreated: true }],
|
||||
HTMLInputReset: [...HTMLControlHeadRule,
|
||||
{ attr: "value", textchanged: true }],
|
||||
HTMLInputSubmit: [...HTMLControlHeadRule,
|
||||
{ attr: "value", textchanged: true }],
|
||||
HTMLInputButton: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "value" },
|
||||
{ attr: "title" },
|
||||
],
|
||||
HTMLInputImage: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "alt", recreated: true },
|
||||
{ attr: "value", recreated: true },
|
||||
{ attr: "title" },
|
||||
],
|
||||
HTMLInputImageNoValidSrc: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "alt", recreated: true },
|
||||
{ attr: "value", recreated: true },
|
||||
],
|
||||
HTMLInputReset: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "value", textchanged: true },
|
||||
],
|
||||
HTMLInputSubmit: [
|
||||
...HTMLControlHeadRule,
|
||||
{ attr: "value", textchanged: true },
|
||||
],
|
||||
HTMLLink: [...ARIARule, { fromsubtree: true }, { attr: "title" }],
|
||||
HTMLLinkImage: [...ARIARule, { elm: "img" }, { attr: "title" }],
|
||||
HTMLOption: [...ARIARule, { attr: "label" }, { fromsubtree: true },
|
||||
{ attr: "title" }],
|
||||
HTMLTable: [...ARIARule, { elm: "caption" }, { attr: "summary" },
|
||||
{ attr: "title" }]
|
||||
HTMLOption: [
|
||||
...ARIARule,
|
||||
{ attr: "label" },
|
||||
{ fromsubtree: true },
|
||||
{ attr: "title" },
|
||||
],
|
||||
HTMLTable: [
|
||||
...ARIARule,
|
||||
{ elm: "caption" },
|
||||
{ attr: "summary" },
|
||||
{ attr: "title" },
|
||||
],
|
||||
};
|
||||
|
||||
const markupTests = [{
|
||||
id: "btn",
|
||||
ruleset: "HTMLControl",
|
||||
markup: `
|
||||
const markupTests = [
|
||||
{
|
||||
id: "btn",
|
||||
ruleset: "HTMLControl",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn">test4</label>
|
||||
|
@ -65,11 +91,12 @@ const markupTests = [{
|
|||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="test5">press me</button>`,
|
||||
expected: ["test2 test3", "test1", "test4", "press me", "test5"]
|
||||
}, {
|
||||
id: "btn",
|
||||
ruleset: "HTMLInputButton",
|
||||
markup: `
|
||||
expected: ["test2 test3", "test1", "test4", "press me", "test5"],
|
||||
},
|
||||
{
|
||||
id: "btn",
|
||||
ruleset: "HTMLInputButton",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn">test4</label>
|
||||
|
@ -82,12 +109,18 @@ const markupTests = [{
|
|||
src="no name from src"
|
||||
data="no name from data"
|
||||
title="name from title"/>`,
|
||||
expected: ["test2 test3", "test1", "test4", "name from value",
|
||||
"name from title"]
|
||||
}, {
|
||||
id: "btn-submit",
|
||||
ruleset: "HTMLInputSubmit",
|
||||
markup: `
|
||||
expected: [
|
||||
"test2 test3",
|
||||
"test1",
|
||||
"test4",
|
||||
"name from value",
|
||||
"name from title",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "btn-submit",
|
||||
ruleset: "HTMLInputSubmit",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-submit">test4</label>
|
||||
|
@ -100,11 +133,12 @@ const markupTests = [{
|
|||
src="no name from src"
|
||||
data="no name from data"
|
||||
title="no name from title"/>`,
|
||||
expected: ["test2 test3", "test1", "test4", "name from value"]
|
||||
}, {
|
||||
id: "btn-reset",
|
||||
ruleset: "HTMLInputReset",
|
||||
markup: `
|
||||
expected: ["test2 test3", "test1", "test4", "name from value"],
|
||||
},
|
||||
{
|
||||
id: "btn-reset",
|
||||
ruleset: "HTMLInputReset",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-reset">test4</label>
|
||||
|
@ -117,11 +151,12 @@ const markupTests = [{
|
|||
src="no name from src"
|
||||
data="no name from data"
|
||||
title="no name from title"/>`,
|
||||
expected: ["test2 test3", "test1", "test4", "name from value"]
|
||||
}, {
|
||||
id: "btn-image",
|
||||
ruleset: "HTMLInputImage",
|
||||
markup: `
|
||||
expected: ["test2 test3", "test1", "test4", "name from value"],
|
||||
},
|
||||
{
|
||||
id: "btn-image",
|
||||
ruleset: "HTMLInputImage",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-image">test4</label>
|
||||
|
@ -134,12 +169,19 @@ const markupTests = [{
|
|||
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"
|
||||
data="no name from data"
|
||||
title="name from title"/>`,
|
||||
expected: ["test2 test3", "test1", "test4", "name from alt",
|
||||
"name from value", "name from title"]
|
||||
}, {
|
||||
id: "btn-image",
|
||||
ruleset: "HTMLInputImageNoValidSrc",
|
||||
markup: `
|
||||
expected: [
|
||||
"test2 test3",
|
||||
"test1",
|
||||
"test4",
|
||||
"name from alt",
|
||||
"name from value",
|
||||
"name from title",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "btn-image",
|
||||
ruleset: "HTMLInputImageNoValidSrc",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="btn-image">test4</label>
|
||||
|
@ -151,12 +193,18 @@ const markupTests = [{
|
|||
value="name from value"
|
||||
data="no name from data"
|
||||
title="no name from title"/>`,
|
||||
expected: ["test2 test3", "test1", "test4", "name from alt",
|
||||
"name from value"]
|
||||
}, {
|
||||
id: "opt",
|
||||
ruleset: "HTMLOption",
|
||||
markup: `
|
||||
expected: [
|
||||
"test2 test3",
|
||||
"test1",
|
||||
"test4",
|
||||
"name from alt",
|
||||
"name from value",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "opt",
|
||||
ruleset: "HTMLOption",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<select>
|
||||
|
@ -167,11 +215,12 @@ const markupTests = [{
|
|||
title="test5">option1</option>
|
||||
<option>option2</option>
|
||||
</select>`,
|
||||
expected: ["test2 test3", "test1", "test4", "option1", "test5"]
|
||||
}, {
|
||||
id: "img",
|
||||
ruleset: "HTMLImg",
|
||||
markup: `
|
||||
expected: ["test2 test3", "test1", "test4", "option1", "test5"],
|
||||
},
|
||||
{
|
||||
id: "img",
|
||||
ruleset: "HTMLImg",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<img id="img"
|
||||
|
@ -180,11 +229,17 @@ const markupTests = [{
|
|||
alt="Mozilla logo"
|
||||
title="This is a logo"
|
||||
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"/>`,
|
||||
expected: ["test2 test3", "Logo of Mozilla", "Mozilla logo", "This is a logo"]
|
||||
}, {
|
||||
id: "imgemptyalt",
|
||||
ruleset: "HTMLImgEmptyAlt",
|
||||
markup: `
|
||||
expected: [
|
||||
"test2 test3",
|
||||
"Logo of Mozilla",
|
||||
"Mozilla logo",
|
||||
"This is a logo",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "imgemptyalt",
|
||||
ruleset: "HTMLImgEmptyAlt",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<img id="imgemptyalt"
|
||||
|
@ -193,11 +248,12 @@ const markupTests = [{
|
|||
title="This is a logo"
|
||||
alt=""
|
||||
src="http://example.com/a11y/accessible/tests/mochitest/moz.png"/>`,
|
||||
expected: ["test2 test3", "Logo of Mozilla", "This is a logo", ""]
|
||||
}, {
|
||||
id: "tc",
|
||||
ruleset: "HTMLElm",
|
||||
markup: `
|
||||
expected: ["test2 test3", "Logo of Mozilla", "This is a logo", ""],
|
||||
},
|
||||
{
|
||||
id: "tc",
|
||||
ruleset: "HTMLElm",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="tc">test4</label>
|
||||
|
@ -215,11 +271,12 @@ const markupTests = [{
|
|||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
expected: ["test2 test3", "test1", "test5"]
|
||||
}, {
|
||||
id: "gc",
|
||||
ruleset: "HTMLARIAGridCell",
|
||||
markup: `
|
||||
expected: ["test2 test3", "test1", "test5"],
|
||||
},
|
||||
{
|
||||
id: "gc",
|
||||
ruleset: "HTMLARIAGridCell",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<label for="gc">test4</label>
|
||||
|
@ -239,13 +296,17 @@ const markupTests = [{
|
|||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
expected: ["test2 test3", "test1",
|
||||
"This is a paragraph This is a link \u2022 Listitem1 \u2022 Listitem2",
|
||||
"This is a paragraph This is a link This is a list"]
|
||||
}, {
|
||||
id: "t",
|
||||
ruleset: "HTMLTable",
|
||||
markup: `
|
||||
expected: [
|
||||
"test2 test3",
|
||||
"test1",
|
||||
"This is a paragraph This is a link \u2022 Listitem1 \u2022 Listitem2",
|
||||
"This is a paragraph This is a link This is a list",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "t",
|
||||
ruleset: "HTMLTable",
|
||||
markup: `
|
||||
<span id="l1">lby_tst6_1</span>
|
||||
<span id="l2">lby_tst6_2</span>
|
||||
<label for="t">label_tst6</label>
|
||||
|
@ -260,56 +321,65 @@ const markupTests = [{
|
|||
<td>cell2</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
expected: ["lby_tst6_1 lby_tst6_2", "arialabel_tst6", "caption_tst6",
|
||||
"summary_tst6", "title_tst6"]
|
||||
}, {
|
||||
id: "btn",
|
||||
ruleset: "CSSContent",
|
||||
markup: `
|
||||
expected: [
|
||||
"lby_tst6_1 lby_tst6_2",
|
||||
"arialabel_tst6",
|
||||
"caption_tst6",
|
||||
"summary_tst6",
|
||||
"title_tst6",
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "btn",
|
||||
ruleset: "CSSContent",
|
||||
markup: `
|
||||
<style>
|
||||
button::before {
|
||||
content: "do not ";
|
||||
}
|
||||
</style>
|
||||
<button id="btn">press me</button>`,
|
||||
expected: ["do not press me", "press me"]
|
||||
}, {
|
||||
// TODO: uncomment when Bug-1256382 is resoved.
|
||||
// id: 'li',
|
||||
// ruleset: 'CSSContent',
|
||||
// markup: `
|
||||
// <style>
|
||||
// ul {
|
||||
// list-style-type: decimal;
|
||||
// }
|
||||
// </style>
|
||||
// <ul id="ul">
|
||||
// <li id="li">Listitem</li>
|
||||
// </ul>`,
|
||||
// expected: ['1. Listitem', `${String.fromCharCode(0x2022)} Listitem`]
|
||||
// }, {
|
||||
id: "a",
|
||||
ruleset: "HTMLLink",
|
||||
markup: `
|
||||
expected: ["do not press me", "press me"],
|
||||
},
|
||||
{
|
||||
// TODO: uncomment when Bug-1256382 is resoved.
|
||||
// id: 'li',
|
||||
// ruleset: 'CSSContent',
|
||||
// markup: `
|
||||
// <style>
|
||||
// ul {
|
||||
// list-style-type: decimal;
|
||||
// }
|
||||
// </style>
|
||||
// <ul id="ul">
|
||||
// <li id="li">Listitem</li>
|
||||
// </ul>`,
|
||||
// expected: ['1. Listitem', `${String.fromCharCode(0x2022)} Listitem`]
|
||||
// }, {
|
||||
id: "a",
|
||||
ruleset: "HTMLLink",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<a id="a"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="test4">test5</a>`,
|
||||
expected: ["test2 test3", "test1", "test5", "test4"]
|
||||
}, {
|
||||
id: "a-img",
|
||||
ruleset: "HTMLLinkImage",
|
||||
markup: `
|
||||
expected: ["test2 test3", "test1", "test5", "test4"],
|
||||
},
|
||||
{
|
||||
id: "a-img",
|
||||
ruleset: "HTMLLinkImage",
|
||||
markup: `
|
||||
<span id="l1">test2</span>
|
||||
<span id="l2">test3</span>
|
||||
<a id="a-img"
|
||||
aria-label="test1"
|
||||
aria-labelledby="l1 l2"
|
||||
title="test4"><img alt="test5"/></a>`,
|
||||
expected: ["test2 test3", "test1", "test5", "test4"]
|
||||
}];
|
||||
expected: ["test2 test3", "test1", "test5", "test4"],
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Test accessible name that is calculated from an attribute, remove the
|
||||
|
@ -325,16 +395,23 @@ const markupTests = [{
|
|||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
async function testAttrRule(browser, target, rule, expected) {
|
||||
let {id, parent, acc} = target;
|
||||
let {recreated, textchanged, attr} = rule;
|
||||
let { id, parent, acc } = target;
|
||||
let { recreated, textchanged, attr } = rule;
|
||||
|
||||
testName(acc, expected);
|
||||
|
||||
if (recreated || textchanged) {
|
||||
let [event] = await contentSpawnMutation(browser, {
|
||||
expected: [recreated ? [EVENT_REORDER, parent] : [EVENT_TEXT_INSERTED, id]]
|
||||
}, ([contentId, contentAttr]) =>
|
||||
content.document.getElementById(contentId).removeAttribute(contentAttr), [id, attr]);
|
||||
let [event] = await contentSpawnMutation(
|
||||
browser,
|
||||
{
|
||||
expected: [
|
||||
recreated ? [EVENT_REORDER, parent] : [EVENT_TEXT_INSERTED, id],
|
||||
],
|
||||
},
|
||||
([contentId, contentAttr]) =>
|
||||
content.document.getElementById(contentId).removeAttribute(contentAttr),
|
||||
[id, attr]
|
||||
);
|
||||
|
||||
// Update accessible just in case it is now defunct.
|
||||
target.acc = findAccessibleChildByID(event.accessible, id);
|
||||
|
@ -356,13 +433,18 @@ async function testAttrRule(browser, target, rule, expected) {
|
|||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
async function testElmRule(browser, target, rule, expected) {
|
||||
let {id, parent, acc} = target;
|
||||
let {isSibling, elm} = rule;
|
||||
let { id, parent, acc } = target;
|
||||
let { isSibling, elm } = rule;
|
||||
|
||||
testName(acc, expected);
|
||||
let [event] = await contentSpawnMutation(browser, {
|
||||
expected: [[EVENT_REORDER, isSibling ? parent : id]]
|
||||
}, contentElm => content.document.querySelector(`${contentElm}`).remove(), elm);
|
||||
let [event] = await contentSpawnMutation(
|
||||
browser,
|
||||
{
|
||||
expected: [[EVENT_REORDER, isSibling ? parent : id]],
|
||||
},
|
||||
contentElm => content.document.querySelector(`${contentElm}`).remove(),
|
||||
elm
|
||||
);
|
||||
|
||||
// Update accessible just in case it is now defunct.
|
||||
target.acc = findAccessibleChildByID(event.accessible, id);
|
||||
|
@ -381,17 +463,22 @@ async function testElmRule(browser, target, rule, expected) {
|
|||
* @param {[type]} expected expected name value
|
||||
*/
|
||||
async function testSubtreeRule(browser, target, rule, expected) {
|
||||
let {id, acc} = target;
|
||||
let { id, acc } = target;
|
||||
|
||||
testName(acc, expected);
|
||||
let [event] = await contentSpawnMutation(browser, {
|
||||
expected: [[EVENT_REORDER, id]]
|
||||
}, contentId => {
|
||||
let elm = content.document.getElementById(contentId);
|
||||
while (elm.firstChild) {
|
||||
elm.firstChild.remove();
|
||||
}
|
||||
}, id);
|
||||
let [event] = await contentSpawnMutation(
|
||||
browser,
|
||||
{
|
||||
expected: [[EVENT_REORDER, id]],
|
||||
},
|
||||
contentId => {
|
||||
let elm = content.document.getElementById(contentId);
|
||||
while (elm.firstChild) {
|
||||
elm.firstChild.remove();
|
||||
}
|
||||
},
|
||||
id
|
||||
);
|
||||
|
||||
// Update accessible just in case it is now defunct.
|
||||
target.acc = findAccessibleChildByID(event.accessible, id);
|
||||
|
@ -430,4 +517,5 @@ markupTests.forEach(({ id, ruleset, markup, expected }) =>
|
|||
let parent = getAccessibleDOMNodeID(acc.parent);
|
||||
let target = { id, parent, acc };
|
||||
await testNameRule(browser, target, rules[ruleset], expected);
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
|
|
@ -19,10 +19,16 @@ const attrRelationsSpec = [
|
|||
["aria-labelledby", RELATION_LABELLED_BY, RELATION_LABEL_FOR],
|
||||
["aria-describedby", RELATION_DESCRIBED_BY, RELATION_DESCRIPTION_FOR],
|
||||
["aria-controls", RELATION_CONTROLLER_FOR, RELATION_CONTROLLED_BY],
|
||||
["aria-flowto", RELATION_FLOWS_TO, RELATION_FLOWS_FROM]
|
||||
["aria-flowto", RELATION_FLOWS_TO, RELATION_FLOWS_FROM],
|
||||
];
|
||||
|
||||
async function testRelated(browser, accDoc, attr, hostRelation, dependantRelation) {
|
||||
async function testRelated(
|
||||
browser,
|
||||
accDoc,
|
||||
attr,
|
||||
hostRelation,
|
||||
dependantRelation
|
||||
) {
|
||||
let host = findAccessibleChildByID(accDoc, "host");
|
||||
let dependant1 = findAccessibleChildByID(accDoc, "dependant1");
|
||||
let dependant2 = findAccessibleChildByID(accDoc, "dependant2");
|
||||
|
@ -36,22 +42,27 @@ async function testRelated(browser, accDoc, attr, hostRelation, dependantRelatio
|
|||
* and host respectively.
|
||||
* }
|
||||
*/
|
||||
const tests = [{
|
||||
desc: "No attribute",
|
||||
expected: [ null, null, null ]
|
||||
}, {
|
||||
desc: "Set attribute",
|
||||
attrs: [{ key: attr, value: "dependant1" }],
|
||||
expected: [ host, null, dependant1 ]
|
||||
}, {
|
||||
desc: "Change attribute",
|
||||
attrs: [{ key: attr, value: "dependant2" }],
|
||||
expected: [ null, host, dependant2 ]
|
||||
}, {
|
||||
desc: "Remove attribute",
|
||||
attrs: [{ key: attr }],
|
||||
expected: [ null, null, null ]
|
||||
}];
|
||||
const tests = [
|
||||
{
|
||||
desc: "No attribute",
|
||||
expected: [null, null, null],
|
||||
},
|
||||
{
|
||||
desc: "Set attribute",
|
||||
attrs: [{ key: attr, value: "dependant1" }],
|
||||
expected: [host, null, dependant1],
|
||||
},
|
||||
{
|
||||
desc: "Change attribute",
|
||||
attrs: [{ key: attr, value: "dependant2" }],
|
||||
expected: [null, host, dependant2],
|
||||
},
|
||||
{
|
||||
desc: "Remove attribute",
|
||||
attrs: [{ key: attr }],
|
||||
expected: [null, null, null],
|
||||
},
|
||||
];
|
||||
|
||||
for (let { desc, attrs, expected } of tests) {
|
||||
info(desc);
|
||||
|
@ -71,7 +82,8 @@ async function testRelated(browser, accDoc, attr, hostRelation, dependantRelatio
|
|||
/**
|
||||
* Test caching of relations between accessible objects.
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="dependant1">label</div>
|
||||
<div id="dependant2">label2</div>
|
||||
<div role="checkbox" id="host"></div>`,
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
/* import-globals-from ../../mochitest/states.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR });
|
||||
loadScripts(
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
/**
|
||||
* Test data has the format of:
|
||||
|
@ -26,70 +28,101 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
|
|||
*/
|
||||
|
||||
// State caching tests for attribute changes
|
||||
const attributeTests = [{
|
||||
desc: "Checkbox with @checked attribute set to true should have checked " +
|
||||
"state",
|
||||
attrs: [{
|
||||
attr: "checked",
|
||||
value: "true"
|
||||
}],
|
||||
expected: [STATE_CHECKED, 0]
|
||||
}, {
|
||||
desc: "Checkbox with no @checked attribute should not have checked state",
|
||||
attrs: [{
|
||||
attr: "checked"
|
||||
}],
|
||||
expected: [0, 0, STATE_CHECKED]
|
||||
}];
|
||||
const attributeTests = [
|
||||
{
|
||||
desc:
|
||||
"Checkbox with @checked attribute set to true should have checked " +
|
||||
"state",
|
||||
attrs: [
|
||||
{
|
||||
attr: "checked",
|
||||
value: "true",
|
||||
},
|
||||
],
|
||||
expected: [STATE_CHECKED, 0],
|
||||
},
|
||||
{
|
||||
desc: "Checkbox with no @checked attribute should not have checked state",
|
||||
attrs: [
|
||||
{
|
||||
attr: "checked",
|
||||
},
|
||||
],
|
||||
expected: [0, 0, STATE_CHECKED],
|
||||
},
|
||||
];
|
||||
|
||||
// State caching tests for ARIA changes
|
||||
const ariaTests = [{
|
||||
desc: "File input has busy state when @aria-busy attribute is set to true",
|
||||
attrs: [{
|
||||
attr: "aria-busy",
|
||||
value: "true"
|
||||
}],
|
||||
expected: [STATE_BUSY, 0, STATE_REQUIRED | STATE_INVALID]
|
||||
}, {
|
||||
desc: "File input has required state when @aria-required attribute is set " +
|
||||
"to true",
|
||||
attrs: [{
|
||||
attr: "aria-required",
|
||||
value: "true"
|
||||
}],
|
||||
expected: [STATE_REQUIRED, 0, STATE_INVALID]
|
||||
}, {
|
||||
desc: "File input has invalid state when @aria-invalid attribute is set to " +
|
||||
"true",
|
||||
attrs: [{
|
||||
attr: "aria-invalid",
|
||||
value: "true"
|
||||
}],
|
||||
expected: [STATE_INVALID, 0]
|
||||
}];
|
||||
const ariaTests = [
|
||||
{
|
||||
desc: "File input has busy state when @aria-busy attribute is set to true",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-busy",
|
||||
value: "true",
|
||||
},
|
||||
],
|
||||
expected: [STATE_BUSY, 0, STATE_REQUIRED | STATE_INVALID],
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"File input has required state when @aria-required attribute is set " +
|
||||
"to true",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-required",
|
||||
value: "true",
|
||||
},
|
||||
],
|
||||
expected: [STATE_REQUIRED, 0, STATE_INVALID],
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"File input has invalid state when @aria-invalid attribute is set to " +
|
||||
"true",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-invalid",
|
||||
value: "true",
|
||||
},
|
||||
],
|
||||
expected: [STATE_INVALID, 0],
|
||||
},
|
||||
];
|
||||
|
||||
// Extra state caching tests
|
||||
const extraStateTests = [{
|
||||
desc: "Input has no extra enabled state when aria and native disabled " +
|
||||
"attributes are set at once",
|
||||
attrs: [{
|
||||
attr: "aria-disabled",
|
||||
value: "true"
|
||||
}, {
|
||||
attr: "disabled",
|
||||
value: "true"
|
||||
}],
|
||||
expected: [0, 0, 0, EXT_STATE_ENABLED]
|
||||
}, {
|
||||
desc: "Input has an extra enabled state when aria and native disabled " +
|
||||
"attributes are unset at once",
|
||||
attrs: [{
|
||||
attr: "aria-disabled"
|
||||
}, {
|
||||
attr: "disabled"
|
||||
}],
|
||||
expected: [0, EXT_STATE_ENABLED]
|
||||
}];
|
||||
const extraStateTests = [
|
||||
{
|
||||
desc:
|
||||
"Input has no extra enabled state when aria and native disabled " +
|
||||
"attributes are set at once",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-disabled",
|
||||
value: "true",
|
||||
},
|
||||
{
|
||||
attr: "disabled",
|
||||
value: "true",
|
||||
},
|
||||
],
|
||||
expected: [0, 0, 0, EXT_STATE_ENABLED],
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Input has an extra enabled state when aria and native disabled " +
|
||||
"attributes are unset at once",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-disabled",
|
||||
},
|
||||
{
|
||||
attr: "disabled",
|
||||
},
|
||||
],
|
||||
expected: [0, EXT_STATE_ENABLED],
|
||||
},
|
||||
];
|
||||
|
||||
async function runStateTests(browser, accDoc, id, tests) {
|
||||
let acc = findAccessibleChildByID(accDoc, id);
|
||||
|
@ -107,7 +140,8 @@ async function runStateTests(browser, accDoc, id, tests) {
|
|||
/**
|
||||
* Test caching of accessible object states
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<input id="checkbox" type="checkbox">
|
||||
<input id="file" type="file">
|
||||
<input id="text">`,
|
||||
|
|
|
@ -18,102 +18,130 @@ loadScripts({ name: "value.js", dir: MOCHITESTS_DIR });
|
|||
* waitFor {?Number} an optional value change event to wait for
|
||||
* }
|
||||
*/
|
||||
const valueTests = [{
|
||||
desc: "Initially value is set to 1st element of select",
|
||||
id: "select",
|
||||
expected: "1st"
|
||||
}, {
|
||||
desc: "Value should update to 3rd when 3 is pressed",
|
||||
id: "select",
|
||||
async action(browser) {
|
||||
await invokeFocus(browser, "select");
|
||||
await BrowserTestUtils.synthesizeKey("3", {}, browser);
|
||||
const valueTests = [
|
||||
{
|
||||
desc: "Initially value is set to 1st element of select",
|
||||
id: "select",
|
||||
expected: "1st",
|
||||
},
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: "3rd"
|
||||
}, {
|
||||
desc: "Initially value is set to @aria-valuenow for slider",
|
||||
id: "slider",
|
||||
expected: ["5", 5, 0, 7, 0]
|
||||
}, {
|
||||
desc: "Value should change when @aria-valuenow is updated",
|
||||
id: "slider",
|
||||
attrs: [{
|
||||
attr: "aria-valuenow",
|
||||
value: "6"
|
||||
}],
|
||||
waitFor: EVENT_VALUE_CHANGE,
|
||||
expected: ["6", 6, 0, 7, 0]
|
||||
}, {
|
||||
desc: "Value should change when @aria-valuetext is set",
|
||||
id: "slider",
|
||||
attrs: [{
|
||||
attr: "aria-valuetext",
|
||||
value: "plain"
|
||||
}],
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: ["plain", 6, 0, 7, 0]
|
||||
}, {
|
||||
desc: "Value should change when @aria-valuetext is updated",
|
||||
id: "slider",
|
||||
attrs: [{
|
||||
attr: "aria-valuetext",
|
||||
value: "hey!"
|
||||
}],
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: ["hey!", 6, 0, 7, 0]
|
||||
}, {
|
||||
desc: "Value should change to @aria-valuetext when @aria-valuenow is removed",
|
||||
id: "slider",
|
||||
attrs: [{
|
||||
attr: "aria-valuenow"
|
||||
}],
|
||||
expected: ["hey!", 0, 0, 7, 0]
|
||||
}, {
|
||||
desc: "Initially value is not set for combobox",
|
||||
id: "combobox",
|
||||
expected: ""
|
||||
}, {
|
||||
desc: "Value should change when @value attribute is updated",
|
||||
id: "combobox",
|
||||
attrs: [{
|
||||
attr: "value",
|
||||
value: "hello"
|
||||
}],
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: "hello"
|
||||
}, {
|
||||
desc: "Initially value corresponds to @value attribute for progress",
|
||||
id: "progress",
|
||||
expected: "22%"
|
||||
}, {
|
||||
desc: "Value should change when @value attribute is updated",
|
||||
id: "progress",
|
||||
attrs: [{
|
||||
attr: "value",
|
||||
value: "50"
|
||||
}],
|
||||
waitFor: EVENT_VALUE_CHANGE,
|
||||
expected: "50%"
|
||||
}, {
|
||||
desc: "Initially value corresponds to @value attribute for range",
|
||||
id: "range",
|
||||
expected: "6"
|
||||
}, {
|
||||
desc: "Value should change when slider is moved",
|
||||
id: "range",
|
||||
async action(browser) {
|
||||
await invokeFocus(browser, "range");
|
||||
await BrowserTestUtils.synthesizeKey("VK_LEFT", {}, browser);
|
||||
{
|
||||
desc: "Value should update to 3rd when 3 is pressed",
|
||||
id: "select",
|
||||
async action(browser) {
|
||||
await invokeFocus(browser, "select");
|
||||
await BrowserTestUtils.synthesizeKey("3", {}, browser);
|
||||
},
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: "3rd",
|
||||
},
|
||||
waitFor: EVENT_VALUE_CHANGE,
|
||||
expected: "5"
|
||||
}];
|
||||
{
|
||||
desc: "Initially value is set to @aria-valuenow for slider",
|
||||
id: "slider",
|
||||
expected: ["5", 5, 0, 7, 0],
|
||||
},
|
||||
{
|
||||
desc: "Value should change when @aria-valuenow is updated",
|
||||
id: "slider",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-valuenow",
|
||||
value: "6",
|
||||
},
|
||||
],
|
||||
waitFor: EVENT_VALUE_CHANGE,
|
||||
expected: ["6", 6, 0, 7, 0],
|
||||
},
|
||||
{
|
||||
desc: "Value should change when @aria-valuetext is set",
|
||||
id: "slider",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-valuetext",
|
||||
value: "plain",
|
||||
},
|
||||
],
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: ["plain", 6, 0, 7, 0],
|
||||
},
|
||||
{
|
||||
desc: "Value should change when @aria-valuetext is updated",
|
||||
id: "slider",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-valuetext",
|
||||
value: "hey!",
|
||||
},
|
||||
],
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: ["hey!", 6, 0, 7, 0],
|
||||
},
|
||||
{
|
||||
desc:
|
||||
"Value should change to @aria-valuetext when @aria-valuenow is removed",
|
||||
id: "slider",
|
||||
attrs: [
|
||||
{
|
||||
attr: "aria-valuenow",
|
||||
},
|
||||
],
|
||||
expected: ["hey!", 0, 0, 7, 0],
|
||||
},
|
||||
{
|
||||
desc: "Initially value is not set for combobox",
|
||||
id: "combobox",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "Value should change when @value attribute is updated",
|
||||
id: "combobox",
|
||||
attrs: [
|
||||
{
|
||||
attr: "value",
|
||||
value: "hello",
|
||||
},
|
||||
],
|
||||
waitFor: EVENT_TEXT_VALUE_CHANGE,
|
||||
expected: "hello",
|
||||
},
|
||||
{
|
||||
desc: "Initially value corresponds to @value attribute for progress",
|
||||
id: "progress",
|
||||
expected: "22%",
|
||||
},
|
||||
{
|
||||
desc: "Value should change when @value attribute is updated",
|
||||
id: "progress",
|
||||
attrs: [
|
||||
{
|
||||
attr: "value",
|
||||
value: "50",
|
||||
},
|
||||
],
|
||||
waitFor: EVENT_VALUE_CHANGE,
|
||||
expected: "50%",
|
||||
},
|
||||
{
|
||||
desc: "Initially value corresponds to @value attribute for range",
|
||||
id: "range",
|
||||
expected: "6",
|
||||
},
|
||||
{
|
||||
desc: "Value should change when slider is moved",
|
||||
id: "range",
|
||||
async action(browser) {
|
||||
await invokeFocus(browser, "range");
|
||||
await BrowserTestUtils.synthesizeKey("VK_LEFT", {}, browser);
|
||||
},
|
||||
waitFor: EVENT_VALUE_CHANGE,
|
||||
expected: "5",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Test caching of accessible object values
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="slider" role="slider" aria-valuenow="5"
|
||||
aria-valuemin="0" aria-valuemax="7">slider</div>
|
||||
<select id="select">
|
||||
|
|
|
@ -4,20 +4,23 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
addAccessibleTask(`<p id="p">abc</p>`,
|
||||
async function(browser, accDoc) {
|
||||
let acc = findAccessibleChildByID(accDoc, "p");
|
||||
let onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
|
||||
acc.announce("please", nsIAccessibleAnnouncementEvent.POLITE);
|
||||
let evt = await onAnnounce;
|
||||
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
|
||||
is(evt.announcement, "please", "announcement matches.");
|
||||
is(evt.priority, nsIAccessibleAnnouncementEvent.POLITE, "priority matches");
|
||||
addAccessibleTask(`<p id="p">abc</p>`, async function(browser, accDoc) {
|
||||
let acc = findAccessibleChildByID(accDoc, "p");
|
||||
let onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
|
||||
acc.announce("please", nsIAccessibleAnnouncementEvent.POLITE);
|
||||
let evt = await onAnnounce;
|
||||
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
|
||||
is(evt.announcement, "please", "announcement matches.");
|
||||
is(evt.priority, nsIAccessibleAnnouncementEvent.POLITE, "priority matches");
|
||||
|
||||
onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
|
||||
acc.announce("do it", nsIAccessibleAnnouncementEvent.ASSERTIVE);
|
||||
evt = await onAnnounce;
|
||||
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
|
||||
is(evt.announcement, "do it", "announcement matches.");
|
||||
is(evt.priority, nsIAccessibleAnnouncementEvent.ASSERTIVE, "priority matches");
|
||||
});
|
||||
onAnnounce = waitForEvent(EVENT_ANNOUNCEMENT, acc);
|
||||
acc.announce("do it", nsIAccessibleAnnouncementEvent.ASSERTIVE);
|
||||
evt = await onAnnounce;
|
||||
evt.QueryInterface(nsIAccessibleAnnouncementEvent);
|
||||
is(evt.announcement, "do it", "announcement matches.");
|
||||
is(
|
||||
evt.priority,
|
||||
nsIAccessibleAnnouncementEvent.ASSERTIVE,
|
||||
"priority matches"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
* Test caret move event and its interface:
|
||||
* - caretOffset
|
||||
*/
|
||||
addAccessibleTask('<input id="textbox" value="hello"/>', async function(browser) {
|
||||
addAccessibleTask('<input id="textbox" value="hello"/>', async function(
|
||||
browser
|
||||
) {
|
||||
let onCaretMoved = waitForEvent(EVENT_TEXT_CARET_MOVED, "textbox");
|
||||
await invokeFocus(browser, "textbox");
|
||||
let event = await onCaretMoved;
|
||||
|
||||
let caretMovedEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
is(caretMovedEvent.caretOffset, 5,
|
||||
"Correct caret offset.");
|
||||
is(caretMovedEvent.caretOffset, 5, "Correct caret offset.");
|
||||
});
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
* - targetNextSibling
|
||||
* - targetPrevSibling
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="parent">
|
||||
<div id="previous"></div>
|
||||
<div id="to-hide"></div>
|
||||
|
@ -23,11 +24,20 @@ addAccessibleTask(`
|
|||
let event = await onHide;
|
||||
let hideEvent = event.QueryInterface(Ci.nsIAccessibleHideEvent);
|
||||
|
||||
is(getAccessibleDOMNodeID(hideEvent.targetParent), "parent",
|
||||
"Correct target parent.");
|
||||
is(getAccessibleDOMNodeID(hideEvent.targetNextSibling), "next",
|
||||
"Correct target next sibling.");
|
||||
is(getAccessibleDOMNodeID(hideEvent.targetPrevSibling), "previous",
|
||||
"Correct target previous sibling.");
|
||||
is(
|
||||
getAccessibleDOMNodeID(hideEvent.targetParent),
|
||||
"parent",
|
||||
"Correct target parent."
|
||||
);
|
||||
is(
|
||||
getAccessibleDOMNodeID(hideEvent.targetNextSibling),
|
||||
"next",
|
||||
"Correct target next sibling."
|
||||
);
|
||||
is(
|
||||
getAccessibleDOMNodeID(hideEvent.targetPrevSibling),
|
||||
"previous",
|
||||
"Correct target previous sibling."
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -7,11 +7,15 @@
|
|||
/**
|
||||
* Test show event
|
||||
*/
|
||||
addAccessibleTask('<div id="div" style="visibility: hidden;"></div>',
|
||||
addAccessibleTask(
|
||||
'<div id="div" style="visibility: hidden;"></div>',
|
||||
async function(browser) {
|
||||
let onShow = waitForEvent(EVENT_SHOW, "div");
|
||||
await invokeSetStyle(browser, "div", "visibility", "visible");
|
||||
let showEvent = await onShow;
|
||||
ok(showEvent.accessibleDocument instanceof nsIAccessibleDocument,
|
||||
"Accessible document not present.");
|
||||
});
|
||||
ok(
|
||||
showEvent.accessibleDocument instanceof nsIAccessibleDocument,
|
||||
"Accessible document not present."
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -6,14 +6,19 @@
|
|||
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
/* import-globals-from ../../mochitest/states.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR });
|
||||
loadScripts(
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
function checkStateChangeEvent(event, state, isExtraState, isEnabled) {
|
||||
let scEvent = event.QueryInterface(nsIAccessibleStateChangeEvent);
|
||||
is(scEvent.state, state, "Correct state of the statechange event.");
|
||||
is(scEvent.isExtraState, isExtraState,
|
||||
"Correct extra state bit of the statechange event.");
|
||||
is(
|
||||
scEvent.isExtraState,
|
||||
isExtraState,
|
||||
"Correct extra state bit of the statechange event."
|
||||
);
|
||||
is(scEvent.isEnabled, isEnabled, "Correct state of statechange event state");
|
||||
}
|
||||
|
||||
|
@ -34,28 +39,32 @@ let iframeSrc = `data:text/html,
|
|||
* - isExtraState
|
||||
* - isEnabled
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<iframe id="iframe" src="${iframeSrc}"></iframe>
|
||||
<input id="checkbox" type="checkbox" />`, async function(browser) {
|
||||
// Test state change
|
||||
let onStateChange = waitForEvent(EVENT_STATE_CHANGE, "checkbox");
|
||||
// Set checked for a checkbox.
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
content.document.getElementById("checkbox").checked = true;
|
||||
});
|
||||
let event = await onStateChange;
|
||||
<input id="checkbox" type="checkbox" />`,
|
||||
async function(browser) {
|
||||
// Test state change
|
||||
let onStateChange = waitForEvent(EVENT_STATE_CHANGE, "checkbox");
|
||||
// Set checked for a checkbox.
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
content.document.getElementById("checkbox").checked = true;
|
||||
});
|
||||
let event = await onStateChange;
|
||||
|
||||
checkStateChangeEvent(event, STATE_CHECKED, false, true);
|
||||
testStates(event.accessible, STATE_CHECKED, 0);
|
||||
checkStateChangeEvent(event, STATE_CHECKED, false, true);
|
||||
testStates(event.accessible, STATE_CHECKED, 0);
|
||||
|
||||
// Test extra state
|
||||
onStateChange = waitForEvent(EVENT_STATE_CHANGE, "iframe");
|
||||
// Set design mode on.
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
content.document.getElementById("iframe").contentDocument.designMode = "on";
|
||||
});
|
||||
event = await onStateChange;
|
||||
// Test extra state
|
||||
onStateChange = waitForEvent(EVENT_STATE_CHANGE, "iframe");
|
||||
// Set design mode on.
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
content.document.getElementById("iframe").contentDocument.designMode =
|
||||
"on";
|
||||
});
|
||||
event = await onStateChange;
|
||||
|
||||
checkStateChangeEvent(event, EXT_STATE_EDITABLE, true, true);
|
||||
testStates(event.accessible, 0, EXT_STATE_EDITABLE);
|
||||
});
|
||||
checkStateChangeEvent(event, EXT_STATE_EDITABLE, true, true);
|
||||
testStates(event.accessible, 0, EXT_STATE_EDITABLE);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -4,44 +4,75 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
function checkTextChangeEvent(event, id, text, start, end, isInserted, isFromUserInput) {
|
||||
function checkTextChangeEvent(
|
||||
event,
|
||||
id,
|
||||
text,
|
||||
start,
|
||||
end,
|
||||
isInserted,
|
||||
isFromUserInput
|
||||
) {
|
||||
let tcEvent = event.QueryInterface(nsIAccessibleTextChangeEvent);
|
||||
is(tcEvent.start, start, `Correct start offset for ${prettyName(id)}`);
|
||||
is(tcEvent.length, end - start, `Correct length for ${prettyName(id)}`);
|
||||
is(tcEvent.isInserted, isInserted,
|
||||
`Correct isInserted flag for ${prettyName(id)}`);
|
||||
is(
|
||||
tcEvent.isInserted,
|
||||
isInserted,
|
||||
`Correct isInserted flag for ${prettyName(id)}`
|
||||
);
|
||||
is(tcEvent.modifiedText, text, `Correct text for ${prettyName(id)}`);
|
||||
is(tcEvent.isFromUserInput, isFromUserInput,
|
||||
`Correct value of isFromUserInput for ${prettyName(id)}`);
|
||||
ok(tcEvent.accessibleDocument instanceof nsIAccessibleDocument,
|
||||
"Accessible document not present.");
|
||||
is(
|
||||
tcEvent.isFromUserInput,
|
||||
isFromUserInput,
|
||||
`Correct value of isFromUserInput for ${prettyName(id)}`
|
||||
);
|
||||
ok(
|
||||
tcEvent.accessibleDocument instanceof nsIAccessibleDocument,
|
||||
"Accessible document not present."
|
||||
);
|
||||
}
|
||||
|
||||
async function changeText(browser, id, value, events) {
|
||||
let onEvents = waitForOrderedEvents(events.map(({ isInserted }) => {
|
||||
let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
|
||||
return [ eventType, id ];
|
||||
}));
|
||||
let onEvents = waitForOrderedEvents(
|
||||
events.map(({ isInserted }) => {
|
||||
let eventType = isInserted ? EVENT_TEXT_INSERTED : EVENT_TEXT_REMOVED;
|
||||
return [eventType, id];
|
||||
})
|
||||
);
|
||||
// Change text in the subtree.
|
||||
await ContentTask.spawn(browser, [id, value], ([contentId, contentValue]) => {
|
||||
content.document.getElementById(contentId).firstChild.textContent =
|
||||
contentValue;
|
||||
content.document.getElementById(
|
||||
contentId
|
||||
).firstChild.textContent = contentValue;
|
||||
});
|
||||
let resolvedEvents = await onEvents;
|
||||
|
||||
events.forEach(({ isInserted, str, offset }, idx) =>
|
||||
checkTextChangeEvent(resolvedEvents[idx],
|
||||
id, str, offset, offset + str.length, isInserted, false));
|
||||
checkTextChangeEvent(
|
||||
resolvedEvents[idx],
|
||||
id,
|
||||
str,
|
||||
offset,
|
||||
offset + str.length,
|
||||
isInserted,
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async function removeTextFromInput(browser, id, value, start, end) {
|
||||
let onTextRemoved = waitForEvent(EVENT_TEXT_REMOVED, id);
|
||||
// Select text and delete it.
|
||||
await ContentTask.spawn(browser, [id, start, end], ([contentId, contentStart, contentEnd]) => {
|
||||
let el = content.document.getElementById(contentId);
|
||||
el.focus();
|
||||
el.setSelectionRange(contentStart, contentEnd);
|
||||
});
|
||||
await ContentTask.spawn(
|
||||
browser,
|
||||
[id, start, end],
|
||||
([contentId, contentStart, contentEnd]) => {
|
||||
let el = content.document.getElementById(contentId);
|
||||
el.focus();
|
||||
el.setSelectionRange(contentStart, contentEnd);
|
||||
}
|
||||
);
|
||||
await BrowserTestUtils.sendChar("VK_DELETE", browser);
|
||||
|
||||
let event = await onTextRemoved;
|
||||
|
@ -56,18 +87,21 @@ async function removeTextFromInput(browser, id, value, start, end) {
|
|||
* - modifiedText
|
||||
* - isFromUserInput
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id="p">abc</p>
|
||||
<input id="input" value="input" />`, async function(browser) {
|
||||
let events = [
|
||||
{ isInserted: false, str: "abc", offset: 0 },
|
||||
{ isInserted: true, str: "def", offset: 0 }
|
||||
];
|
||||
await changeText(browser, "p", "def", events);
|
||||
<input id="input" value="input" />`,
|
||||
async function(browser) {
|
||||
let events = [
|
||||
{ isInserted: false, str: "abc", offset: 0 },
|
||||
{ isInserted: true, str: "def", offset: 0 },
|
||||
];
|
||||
await changeText(browser, "p", "def", events);
|
||||
|
||||
events = [{ isInserted: true, str: "DEF", offset: 2 }];
|
||||
await changeText(browser, "p", "deDEFf", events);
|
||||
events = [{ isInserted: true, str: "DEF", offset: 2 }];
|
||||
await changeText(browser, "p", "deDEFf", events);
|
||||
|
||||
// Test isFromUserInput property.
|
||||
await removeTextFromInput(browser, "input", "n", 1, 2);
|
||||
});
|
||||
// Test isFromUserInput property.
|
||||
await removeTextFromInput(browser, "input", "n", 1, 2);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -4,18 +4,21 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id="p1">abc</p>
|
||||
<input id="input1" value="input" />`,
|
||||
async function(browser, accDoc) {
|
||||
let onVCChanged = waitForEvent(EVENT_VIRTUALCURSOR_CHANGED, accDoc);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument).virtualCursor;
|
||||
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument)
|
||||
.virtualCursor;
|
||||
vc.position = getAccessible("p1");
|
||||
});
|
||||
|
||||
let vccEvent = (await onVCChanged).QueryInterface(
|
||||
nsIAccessibleVirtualCursorChangeEvent);
|
||||
nsIAccessibleVirtualCursorChangeEvent
|
||||
);
|
||||
is(vccEvent.newAccessible.id, "p1", "New position is correct");
|
||||
is(vccEvent.newStartOffset, -1, "New start offset is correct");
|
||||
is(vccEvent.newEndOffset, -1, "New end offset is correct");
|
||||
|
@ -23,11 +26,13 @@ addAccessibleTask(`
|
|||
|
||||
onVCChanged = waitForEvent(EVENT_VIRTUALCURSOR_CHANGED, accDoc);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument).virtualCursor;
|
||||
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument)
|
||||
.virtualCursor;
|
||||
vc.moveNextByText(Ci.nsIAccessiblePivot.CHAR_BOUNDARY);
|
||||
});
|
||||
vccEvent = (await onVCChanged).QueryInterface(
|
||||
nsIAccessibleVirtualCursorChangeEvent);
|
||||
nsIAccessibleVirtualCursorChangeEvent
|
||||
);
|
||||
is(vccEvent.newAccessible.id, vccEvent.oldAccessible.id, "Same position");
|
||||
is(vccEvent.newStartOffset, 0, "New start offset is correct");
|
||||
is(vccEvent.newEndOffset, 1, "New end offset is correct");
|
||||
|
@ -35,15 +40,18 @@ addAccessibleTask(`
|
|||
|
||||
onVCChanged = waitForEvent(EVENT_VIRTUALCURSOR_CHANGED, accDoc);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument).virtualCursor;
|
||||
let vc = getAccessible(content.document, Ci.nsIAccessibleDocument)
|
||||
.virtualCursor;
|
||||
vc.position = getAccessible("input1");
|
||||
});
|
||||
vccEvent = (await onVCChanged).QueryInterface(
|
||||
nsIAccessibleVirtualCursorChangeEvent);
|
||||
nsIAccessibleVirtualCursorChangeEvent
|
||||
);
|
||||
isnot(vccEvent.oldAccessible, vccEvent.newAccessible, "positions differ");
|
||||
is(vccEvent.oldAccessible.id, "p1", "Old position is correct");
|
||||
is(vccEvent.newAccessible.id, "input1", "New position is correct");
|
||||
is(vccEvent.newStartOffset, -1, "New start offset is correct");
|
||||
is(vccEvent.newEndOffset, -1, "New end offset is correct");
|
||||
ok(!vccEvent.isFromUserInput, "not user initiated");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -8,10 +8,13 @@
|
|||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
// Test ARIA Dialog
|
||||
addAccessibleTask("doc_treeupdate_ariadialog.html", async function(browser, accDoc) {
|
||||
addAccessibleTask("doc_treeupdate_ariadialog.html", async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
testAccessibleTree(accDoc, {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
children: [],
|
||||
});
|
||||
|
||||
// Make dialog visible and update its inner content.
|
||||
|
@ -29,13 +32,13 @@ addAccessibleTask("doc_treeupdate_ariadialog.html", async function(browser, accD
|
|||
children: [
|
||||
{
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [ { role: ROLE_TEXT_LEAF } ]
|
||||
children: [{ role: ROLE_TEXT_LEAF }],
|
||||
},
|
||||
{
|
||||
role: ROLE_ENTRY
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
role: ROLE_ENTRY,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,12 +15,7 @@ async function testContainer1(browser, accDoc) {
|
|||
/* ================= Initial tree test ==================================== */
|
||||
// children are swapped by ARIA owns
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [
|
||||
{ SECTION: [] }
|
||||
] },
|
||||
{ PUSHBUTTON: [ ] }
|
||||
]
|
||||
SECTION: [{ CHECKBUTTON: [{ SECTION: [] }] }, { PUSHBUTTON: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -33,10 +28,10 @@ async function testContainer1(browser, accDoc) {
|
|||
// the children.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // checkbox, native order
|
||||
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
|
||||
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
|
||||
]
|
||||
{ CHECKBUTTON: [] }, // checkbox, native order
|
||||
{ PUSHBUTTON: [] }, // button, rearranged by ARIA own
|
||||
{ SECTION: [] }, // subdiv from the subtree, ARIA owned
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -47,12 +42,7 @@ async function testContainer1(browser, accDoc) {
|
|||
|
||||
// children follow the DOM order
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ PUSHBUTTON: [ ] },
|
||||
{ CHECKBUTTON: [
|
||||
{ SECTION: [] }
|
||||
] }
|
||||
]
|
||||
SECTION: [{ PUSHBUTTON: [] }, { CHECKBUTTON: [{ SECTION: [] }] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -65,28 +55,32 @@ async function testContainer1(browser, accDoc) {
|
|||
// the children.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // checkbox
|
||||
{ PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
|
||||
{ SECTION: [ ] } // subdiv from the subtree, ARIA owned
|
||||
]
|
||||
{ CHECKBUTTON: [] }, // checkbox
|
||||
{ PUSHBUTTON: [] }, // button, rearranged by ARIA own
|
||||
{ SECTION: [] }, // subdiv from the subtree, ARIA owned
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Add ID to ARIA owns =================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, docID);
|
||||
await invokeSetAttribute(browser, id, "aria-owns",
|
||||
"t1_button t1_subdiv t1_group");
|
||||
await invokeSetAttribute(
|
||||
browser,
|
||||
id,
|
||||
"aria-owns",
|
||||
"t1_button t1_subdiv t1_group"
|
||||
);
|
||||
await onReorder;
|
||||
|
||||
// children are swapped again, button and subdiv are appended to
|
||||
// the children.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // t1_checkbox
|
||||
{ PUSHBUTTON: [ ] }, // button, t1_button
|
||||
{ SECTION: [ ] }, // subdiv from the subtree, t1_subdiv
|
||||
{ GROUPING: [ ] } // group from outside, t1_group
|
||||
]
|
||||
{ CHECKBUTTON: [] }, // t1_checkbox
|
||||
{ PUSHBUTTON: [] }, // button, t1_button
|
||||
{ SECTION: [] }, // subdiv from the subtree, t1_subdiv
|
||||
{ GROUPING: [] }, // group from outside, t1_group
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -104,29 +98,30 @@ async function testContainer1(browser, accDoc) {
|
|||
// newly inserted child.
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox
|
||||
{ RADIOBUTTON: [ ] }, // new explicit, t1_child3
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ SECTION: [ ] }, // ARIA owned, t1_subdiv
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group
|
||||
]
|
||||
{ CHECKBUTTON: [] }, // existing explicit, t1_checkbox
|
||||
{ RADIOBUTTON: [] }, // new explicit, t1_child3
|
||||
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
|
||||
{ SECTION: [] }, // ARIA owned, t1_subdiv
|
||||
{ GROUPING: [] }, // ARIA owned, t1_group
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
/* ================ Remove element ======================================== */
|
||||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, {}, () =>
|
||||
content.document.getElementById("t1_span").remove());
|
||||
content.document.getElementById("t1_span").remove()
|
||||
);
|
||||
await onReorder;
|
||||
|
||||
// subdiv should go away
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] }, // explicit, t1_checkbox
|
||||
{ RADIOBUTTON: [ ] }, // explicit, t1_child3
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group
|
||||
]
|
||||
{ CHECKBUTTON: [] }, // explicit, t1_checkbox
|
||||
{ RADIOBUTTON: [] }, // explicit, t1_child3
|
||||
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [] }, // ARIA owned, t1_group
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -137,10 +132,10 @@ async function testContainer1(browser, accDoc) {
|
|||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] } // ARIA owned, t1_button
|
||||
]
|
||||
{ CHECKBUTTON: [] },
|
||||
{ RADIOBUTTON: [] },
|
||||
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -151,11 +146,11 @@ async function testContainer1(browser, accDoc) {
|
|||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] },
|
||||
{ RADIOBUTTON: [ ] },
|
||||
{ PUSHBUTTON: [ ] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [ ] } // ARIA owned, t1_group, previously t1_grouptmp
|
||||
]
|
||||
{ CHECKBUTTON: [] },
|
||||
{ RADIOBUTTON: [] },
|
||||
{ PUSHBUTTON: [] }, // ARIA owned, t1_button
|
||||
{ GROUPING: [] }, // ARIA owned, t1_group, previously t1_grouptmp
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
@ -166,19 +161,21 @@ async function removeContainer(browser, accDoc) {
|
|||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] } // ARIA owned, 't2_owned'
|
||||
]
|
||||
{ CHECKBUTTON: [] }, // ARIA owned, 't2_owned'
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, {}, () =>
|
||||
content.document.getElementById("t2_container2").removeChild(
|
||||
content.document.getElementById("t2_container3")));
|
||||
content.document
|
||||
.getElementById("t2_container2")
|
||||
.removeChild(content.document.getElementById("t2_container3"))
|
||||
);
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ ]
|
||||
SECTION: [],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
@ -201,15 +198,13 @@ async function stealAndRecacheChildren(browser, accDoc) {
|
|||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [ ] } // ARIA owned
|
||||
]
|
||||
{ CHECKBUTTON: [] }, // ARIA owned
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc1, tree);
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ RADIOBUTTON: [ ] }
|
||||
]
|
||||
SECTION: [{ RADIOBUTTON: [] }],
|
||||
};
|
||||
testAccessibleTree(acc2, tree);
|
||||
}
|
||||
|
@ -219,9 +214,7 @@ async function showHiddenElement(browser, accDoc) {
|
|||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ RADIOBUTTON: [] }
|
||||
]
|
||||
SECTION: [{ RADIOBUTTON: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -230,10 +223,7 @@ async function showHiddenElement(browser, accDoc) {
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ CHECKBUTTON: [] },
|
||||
{ RADIOBUTTON: [] }
|
||||
]
|
||||
SECTION: [{ CHECKBUTTON: [] }, { RADIOBUTTON: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
@ -241,20 +231,23 @@ async function showHiddenElement(browser, accDoc) {
|
|||
async function rearrangeARIAOwns(browser, accDoc) {
|
||||
const id = "t5_container";
|
||||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
const tests = [{
|
||||
val: "t5_checkbox t5_radio t5_button",
|
||||
roleList: [ "CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON" ]
|
||||
}, {
|
||||
val: "t5_radio t5_button t5_checkbox",
|
||||
roleList: [ "RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON" ]
|
||||
}];
|
||||
const tests = [
|
||||
{
|
||||
val: "t5_checkbox t5_radio t5_button",
|
||||
roleList: ["CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON"],
|
||||
},
|
||||
{
|
||||
val: "t5_radio t5_button t5_checkbox",
|
||||
roleList: ["RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON"],
|
||||
},
|
||||
];
|
||||
|
||||
for (let { val, roleList } of tests) {
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
await invokeSetAttribute(browser, id, "aria-owns", val);
|
||||
await onReorder;
|
||||
|
||||
let tree = { SECTION: [ ] };
|
||||
let tree = { SECTION: [] };
|
||||
for (let role of roleList) {
|
||||
let ch = {};
|
||||
ch[role] = [];
|
||||
|
@ -269,29 +262,28 @@ async function removeNotARIAOwnedEl(browser, accDoc) {
|
|||
const acc = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ TEXT_LEAF: [ ] },
|
||||
{ GROUPING: [ ] }
|
||||
]
|
||||
SECTION: [{ TEXT_LEAF: [] }, { GROUPING: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
content.document.getElementById(contentId).removeChild(
|
||||
content.document.getElementById("t6_span"));
|
||||
content.document
|
||||
.getElementById(contentId)
|
||||
.removeChild(content.document.getElementById("t6_span"));
|
||||
});
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ GROUPING: [ ] }
|
||||
]
|
||||
SECTION: [{ GROUPING: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
||||
addAccessibleTask("doc_treeupdate_ariaowns.html", async function(browser, accDoc) {
|
||||
addAccessibleTask("doc_treeupdate_ariaowns.html", async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
await testContainer1(browser, accDoc);
|
||||
await removeContainer(browser, accDoc);
|
||||
await stealAndRecacheChildren(browser, accDoc);
|
||||
|
|
|
@ -7,18 +7,21 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<canvas id="canvas">
|
||||
<div id="dialog" role="dialog" style="display: none;"></div>
|
||||
</canvas>`, async function(browser, accDoc) {
|
||||
let canvas = findAccessibleChildByID(accDoc, "canvas");
|
||||
let dialog = findAccessibleChildByID(accDoc, "dialog");
|
||||
</canvas>`,
|
||||
async function(browser, accDoc) {
|
||||
let canvas = findAccessibleChildByID(accDoc, "canvas");
|
||||
let dialog = findAccessibleChildByID(accDoc, "dialog");
|
||||
|
||||
testAccessibleTree(canvas, { CANVAS: [] });
|
||||
testAccessibleTree(canvas, { CANVAS: [] });
|
||||
|
||||
let onShow = waitForEvent(EVENT_SHOW, "dialog");
|
||||
await invokeSetStyle(browser, "dialog", "display", "block");
|
||||
await onShow;
|
||||
let onShow = waitForEvent(EVENT_SHOW, "dialog");
|
||||
await invokeSetStyle(browser, "dialog", "display", "block");
|
||||
await onShow;
|
||||
|
||||
testAccessibleTree(dialog, { DIALOG: [] });
|
||||
});
|
||||
testAccessibleTree(dialog, { DIALOG: [] });
|
||||
}
|
||||
);
|
||||
|
|
|
@ -7,61 +7,79 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="container"><div id="scrollarea" style="overflow:auto;"><input>
|
||||
</div></div>
|
||||
<div id="container2"><div id="scrollarea2" style="overflow:hidden;">
|
||||
</div></div>`, async function(browser, accDoc) {
|
||||
const id1 = "container";
|
||||
const id2 = "container2";
|
||||
const container = findAccessibleChildByID(accDoc, id1);
|
||||
const container2 = findAccessibleChildByID(accDoc, id2);
|
||||
</div></div>`,
|
||||
async function(browser, accDoc) {
|
||||
const id1 = "container";
|
||||
const id2 = "container2";
|
||||
const container = findAccessibleChildByID(accDoc, id1);
|
||||
const container2 = findAccessibleChildByID(accDoc, id2);
|
||||
|
||||
/* ================= Change scroll range ================================== */
|
||||
let tree = {
|
||||
SECTION: [ {// container
|
||||
SECTION: [ {// scroll area
|
||||
ENTRY: [ ] // child content
|
||||
} ]
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(container, tree);
|
||||
/* ================= Change scroll range ================================== */
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// scroll area
|
||||
ENTRY: [], // child content
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id1);
|
||||
await ContentTask.spawn(browser, id1, id => {
|
||||
let doc = content.document;
|
||||
doc.getElementById("scrollarea").style.width = "20px";
|
||||
doc.getElementById(id).appendChild(doc.createElement("input"));
|
||||
});
|
||||
await onReorder;
|
||||
let onReorder = waitForEvent(EVENT_REORDER, id1);
|
||||
await ContentTask.spawn(browser, id1, id => {
|
||||
let doc = content.document;
|
||||
doc.getElementById("scrollarea").style.width = "20px";
|
||||
doc.getElementById(id).appendChild(doc.createElement("input"));
|
||||
});
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ {// container
|
||||
SECTION: [ {// scroll area
|
||||
ENTRY: [ ] // child content
|
||||
} ]
|
||||
}, {
|
||||
ENTRY: [ ] // inserted input
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(container, tree);
|
||||
tree = {
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// scroll area
|
||||
ENTRY: [], // child content
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
ENTRY: [], // inserted input
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container, tree);
|
||||
|
||||
/* ================= Change scrollbar styles ============================== */
|
||||
tree = {
|
||||
SECTION: [ // container2
|
||||
{ SECTION: [] } // scroll area because of its ID
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
/* ================= Change scrollbar styles ============================== */
|
||||
tree = {
|
||||
SECTION: [
|
||||
// container2
|
||||
{ SECTION: [] }, // scroll area because of its ID
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
|
||||
onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
await invokeSetStyle(browser, "scrollarea2", "overflow", "auto");
|
||||
await onReorder;
|
||||
onReorder = waitForEvent(EVENT_REORDER, id2);
|
||||
await invokeSetStyle(browser, "scrollarea2", "overflow", "auto");
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [] } // scroll area
|
||||
]
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
});
|
||||
tree = {
|
||||
SECTION: [
|
||||
// container
|
||||
{ SECTION: [] }, // scroll area
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -16,102 +16,104 @@ const iframeSrc = `data:text/html,
|
|||
<body id='inner-iframe'></body>
|
||||
</html>`;
|
||||
|
||||
addAccessibleTask(`
|
||||
<iframe id="iframe" src="${iframeSrc}"></iframe>`, async function(browser, accDoc) {
|
||||
// ID of the iframe that is being tested
|
||||
const id = "inner-iframe";
|
||||
addAccessibleTask(
|
||||
`
|
||||
<iframe id="iframe" src="${iframeSrc}"></iframe>`,
|
||||
async function(browser, accDoc) {
|
||||
// ID of the iframe that is being tested
|
||||
const id = "inner-iframe";
|
||||
|
||||
let iframe = findAccessibleChildByID(accDoc, id);
|
||||
let iframe = findAccessibleChildByID(accDoc, id);
|
||||
|
||||
/* ================= Initial tree check =================================== */
|
||||
let tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
/* ================= Initial tree check =================================== */
|
||||
let tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Write iframe document ================================ */
|
||||
let reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let newHTMLNode = docNode.createElement("html");
|
||||
let newBodyNode = docNode.createElement("body");
|
||||
let newTextNode = docNode.createTextNode("New Wave");
|
||||
newBodyNode.id = contentId;
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newHTMLNode.appendChild(newBodyNode);
|
||||
docNode.replaceChild(newHTMLNode, docNode.documentElement);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
/* ================= Write iframe document ================================ */
|
||||
let reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let newHTMLNode = docNode.createElement("html");
|
||||
let newBodyNode = docNode.createElement("body");
|
||||
let newTextNode = docNode.createTextNode("New Wave");
|
||||
newBodyNode.id = contentId;
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newHTMLNode.appendChild(newBodyNode);
|
||||
docNode.replaceChild(newHTMLNode, docNode.documentElement);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "New Wave"
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "New Wave",
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Replace iframe HTML element ========================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
// We can't use open/write/close outside of iframe document because of
|
||||
// security error.
|
||||
let script = docNode.createElement("script");
|
||||
script.textContent = `
|
||||
/* ================= Replace iframe HTML element ========================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
// We can't use open/write/close outside of iframe document because of
|
||||
// security error.
|
||||
let script = docNode.createElement("script");
|
||||
script.textContent = `
|
||||
document.open();
|
||||
document.write('<body id="${contentId}">hello</body>');
|
||||
document.close();`;
|
||||
docNode.body.appendChild(script);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
docNode.body.appendChild(script);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "hello"
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "hello",
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Replace iframe body ================================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let newBodyNode = docNode.createElement("body");
|
||||
let newTextNode = docNode.createTextNode("New Hello");
|
||||
newBodyNode.id = contentId;
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newBodyNode.setAttribute("role", "button");
|
||||
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
/* ================= Replace iframe body ================================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let newBodyNode = docNode.createElement("body");
|
||||
let newTextNode = docNode.createTextNode("New Hello");
|
||||
newBodyNode.id = contentId;
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newBodyNode.setAttribute("role", "button");
|
||||
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "New Hello"
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
tree = {
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "New Hello",
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Open iframe document ================================= */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
// Open document.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let script = docNode.createElement("script");
|
||||
script.textContent = `
|
||||
/* ================= Open iframe document ================================= */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
// Open document.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let script = docNode.createElement("script");
|
||||
script.textContent = `
|
||||
function closeMe() {
|
||||
document.write('Works?');
|
||||
document.close();
|
||||
|
@ -119,192 +121,199 @@ addAccessibleTask(`
|
|||
window.closeMe = closeMe;
|
||||
document.open();
|
||||
document.write('<body id="${contentId}"></body>');`;
|
||||
docNode.body.appendChild(script);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
docNode.body.appendChild(script);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Close iframe document ================================ */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// Write and close document.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
docNode.write("Works?");
|
||||
docNode.close();
|
||||
});
|
||||
await reorderEventPromise;
|
||||
/* ================= Close iframe document ================================ */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// Write and close document.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
docNode.write("Works?");
|
||||
docNode.close();
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "Works?"
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "Works?",
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Remove HTML from iframe document ===================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// Remove HTML element.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
docNode.firstChild.remove();
|
||||
});
|
||||
let event = await reorderEventPromise;
|
||||
/* ================= Remove HTML from iframe document ===================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// Remove HTML element.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
docNode.firstChild.remove();
|
||||
});
|
||||
let event = await reorderEventPromise;
|
||||
|
||||
ok(event.accessible instanceof nsIAccessibleDocument,
|
||||
"Reorder should happen on the document");
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
ok(
|
||||
event.accessible instanceof nsIAccessibleDocument,
|
||||
"Reorder should happen on the document"
|
||||
);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Insert HTML to iframe document ======================= */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
// Insert HTML element.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let html = docNode.createElement("html");
|
||||
let body = docNode.createElement("body");
|
||||
let text = docNode.createTextNode("Haha");
|
||||
body.appendChild(text);
|
||||
body.id = contentId;
|
||||
html.appendChild(body);
|
||||
docNode.appendChild(html);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
/* ================= Insert HTML to iframe document ======================= */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
// Insert HTML element.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let html = docNode.createElement("html");
|
||||
let body = docNode.createElement("body");
|
||||
let text = docNode.createTextNode("Haha");
|
||||
body.appendChild(text);
|
||||
body.id = contentId;
|
||||
html.appendChild(body);
|
||||
docNode.appendChild(html);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "Haha"
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "Haha",
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Remove body from iframe document ===================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// Remove body element.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
docNode.documentElement.removeChild(docNode.body);
|
||||
});
|
||||
event = await reorderEventPromise;
|
||||
/* ================= Remove body from iframe document ===================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// Remove body element.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
docNode.documentElement.removeChild(docNode.body);
|
||||
});
|
||||
event = await reorderEventPromise;
|
||||
|
||||
ok(event.accessible instanceof nsIAccessibleDocument,
|
||||
"Reorder should happen on the document");
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
ok(
|
||||
event.accessible instanceof nsIAccessibleDocument,
|
||||
"Reorder should happen on the document"
|
||||
);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================ Insert element under document element while body missed */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let inputNode = content.window.inputNode = docNode.createElement("input");
|
||||
docNode.documentElement.appendChild(inputNode);
|
||||
});
|
||||
event = await reorderEventPromise;
|
||||
/* ================ Insert element under document element while body missed */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let inputNode = (content.window.inputNode = docNode.createElement(
|
||||
"input"
|
||||
));
|
||||
docNode.documentElement.appendChild(inputNode);
|
||||
});
|
||||
event = await reorderEventPromise;
|
||||
|
||||
ok(event.accessible instanceof nsIAccessibleDocument,
|
||||
"Reorder should happen on the document");
|
||||
tree = {
|
||||
DOCUMENT: [
|
||||
{ ENTRY: [ ] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
ok(
|
||||
event.accessible instanceof nsIAccessibleDocument,
|
||||
"Reorder should happen on the document"
|
||||
);
|
||||
tree = {
|
||||
DOCUMENT: [{ ENTRY: [] }],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
let docEl =
|
||||
content.document.getElementById("iframe").contentDocument.documentElement;
|
||||
// Remove aftermath of this test before next test starts.
|
||||
docEl.firstChild.remove();
|
||||
});
|
||||
// Make sure reorder event was fired and that the input was removed.
|
||||
await reorderEventPromise;
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [ ]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, iframe);
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
let docEl = content.document.getElementById("iframe").contentDocument
|
||||
.documentElement;
|
||||
// Remove aftermath of this test before next test starts.
|
||||
docEl.firstChild.remove();
|
||||
});
|
||||
// Make sure reorder event was fired and that the input was removed.
|
||||
await reorderEventPromise;
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Insert body to iframe document ======================= */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
// Write and close document.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
// Insert body element.
|
||||
let body = docNode.createElement("body");
|
||||
let text = docNode.createTextNode("Yo ho ho i butylka roma!");
|
||||
body.appendChild(text);
|
||||
body.id = contentId;
|
||||
docNode.documentElement.appendChild(body);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
/* ================= Insert body to iframe document ======================= */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
// Write and close document.
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
// Insert body element.
|
||||
let body = docNode.createElement("body");
|
||||
let text = docNode.createTextNode("Yo ho ho i butylka roma!");
|
||||
body.appendChild(text);
|
||||
body.id = contentId;
|
||||
docNode.documentElement.appendChild(body);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "Yo ho ho i butylka roma!"
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
tree = {
|
||||
role: ROLE_DOCUMENT,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "Yo ho ho i butylka roma!",
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
|
||||
/* ================= Change source ======================================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, "iframe");
|
||||
await invokeSetAttribute(browser, "iframe", "src",
|
||||
`data:text/html,<html><body id="${id}"><input></body></html>`);
|
||||
event = await reorderEventPromise;
|
||||
/* ================= Change source ======================================== */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, "iframe");
|
||||
await invokeSetAttribute(
|
||||
browser,
|
||||
"iframe",
|
||||
"src",
|
||||
`data:text/html,<html><body id="${id}"><input></body></html>`
|
||||
);
|
||||
event = await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
INTERNAL_FRAME: [
|
||||
{ DOCUMENT: [
|
||||
{ ENTRY: [ ] }
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(event.accessible, tree);
|
||||
iframe = findAccessibleChildByID(event.accessible, id);
|
||||
tree = {
|
||||
INTERNAL_FRAME: [{ DOCUMENT: [{ ENTRY: [] }] }],
|
||||
};
|
||||
testAccessibleTree(event.accessible, tree);
|
||||
iframe = findAccessibleChildByID(event.accessible, id);
|
||||
|
||||
/* ================= Replace iframe body on ARIA role body ================ */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let newBodyNode = docNode.createElement("body");
|
||||
let newTextNode = docNode.createTextNode("New Hello");
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newBodyNode.setAttribute("role", "button");
|
||||
newBodyNode.id = contentId;
|
||||
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
/* ================= Replace iframe body on ARIA role body ================ */
|
||||
reorderEventPromise = waitForEvent(EVENT_REORDER, id);
|
||||
await ContentTask.spawn(browser, id, contentId => {
|
||||
let docNode = content.document.getElementById("iframe").contentDocument;
|
||||
let newBodyNode = docNode.createElement("body");
|
||||
let newTextNode = docNode.createTextNode("New Hello");
|
||||
newBodyNode.appendChild(newTextNode);
|
||||
newBodyNode.setAttribute("role", "button");
|
||||
newBodyNode.id = contentId;
|
||||
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
|
||||
});
|
||||
await reorderEventPromise;
|
||||
|
||||
tree = {
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "New Hello"
|
||||
}
|
||||
]
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
});
|
||||
tree = {
|
||||
role: ROLE_PUSHBUTTON,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
name: "New Hello",
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(iframe, tree);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<style>
|
||||
.gentext:before {
|
||||
content: "START"
|
||||
|
@ -25,16 +26,22 @@ addAccessibleTask(`
|
|||
let container2 = findAccessibleChildByID(accDoc, id2);
|
||||
|
||||
let tree = {
|
||||
SECTION: [ ] // container
|
||||
SECTION: [], // container
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
tree = {
|
||||
SECTION: [ { // container2
|
||||
SECTION: [ { // container2 child
|
||||
TEXT_LEAF: [ ] // primary text
|
||||
} ]
|
||||
} ]
|
||||
SECTION: [
|
||||
{
|
||||
// container2
|
||||
SECTION: [
|
||||
{
|
||||
// container2 child
|
||||
TEXT_LEAF: [], // primary text
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
|
||||
|
@ -49,13 +56,17 @@ addAccessibleTask(`
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [ // inserted node
|
||||
{ STATICTEXT: [] }, // :before
|
||||
{ TEXT_LEAF: [] }, // primary text
|
||||
{ STATICTEXT: [] } // :after
|
||||
] }
|
||||
]
|
||||
SECTION: [
|
||||
// container
|
||||
{
|
||||
SECTION: [
|
||||
// inserted node
|
||||
{ STATICTEXT: [] }, // :before
|
||||
{ TEXT_LEAF: [] }, // primary text
|
||||
{ STATICTEXT: [] }, // :after
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
|
@ -65,13 +76,18 @@ addAccessibleTask(`
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container2
|
||||
{ SECTION: [ // container2 child
|
||||
{ STATICTEXT: [] }, // :before
|
||||
{ TEXT_LEAF: [] }, // primary text
|
||||
{ STATICTEXT: [] } // :after
|
||||
] }
|
||||
]
|
||||
SECTION: [
|
||||
// container2
|
||||
{
|
||||
SECTION: [
|
||||
// container2 child
|
||||
{ STATICTEXT: [] }, // :before
|
||||
{ TEXT_LEAF: [] }, // primary text
|
||||
{ STATICTEXT: [] }, // :after
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container2, tree);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -13,17 +13,19 @@ async function setHidden(browser, value) {
|
|||
await onReorder;
|
||||
}
|
||||
|
||||
addAccessibleTask('<div id="container"><input id="child"></div>',
|
||||
addAccessibleTask(
|
||||
'<div id="container"><input id="child"></div>',
|
||||
async function(browser, accDoc) {
|
||||
let container = findAccessibleChildByID(accDoc, "container");
|
||||
|
||||
testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] });
|
||||
testAccessibleTree(container, { SECTION: [{ ENTRY: [] }] });
|
||||
|
||||
// Set @hidden attribute
|
||||
await setHidden(browser, "true");
|
||||
testAccessibleTree(container, { SECTION: [ ] });
|
||||
testAccessibleTree(container, { SECTION: [] });
|
||||
|
||||
// Remove @hidden attribute
|
||||
await setHidden(browser);
|
||||
testAccessibleTree(container, { SECTION: [ { ENTRY: [ ] } ] });
|
||||
});
|
||||
testAccessibleTree(container, { SECTION: [{ ENTRY: [] }] });
|
||||
}
|
||||
);
|
||||
|
|
|
@ -13,9 +13,7 @@ async function testImageMap(browser, accDoc) {
|
|||
|
||||
/* ================= Initial tree test ==================================== */
|
||||
let tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: "b", children: [ ] }
|
||||
]
|
||||
IMAGE_MAP: [{ role: ROLE_LINK, name: "b", children: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -24,8 +22,10 @@ async function testImageMap(browser, accDoc) {
|
|||
await ContentTask.spawn(browser, {}, () => {
|
||||
let areaElm = content.document.createElement("area");
|
||||
let mapNode = content.document.getElementById("map");
|
||||
areaElm.setAttribute("href",
|
||||
"http://www.bbc.co.uk/radio4/atoz/index.shtml#a");
|
||||
areaElm.setAttribute(
|
||||
"href",
|
||||
"http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
|
||||
);
|
||||
areaElm.setAttribute("coords", "0,0,13,14");
|
||||
areaElm.setAttribute("alt", "a");
|
||||
areaElm.setAttribute("shape", "rect");
|
||||
|
@ -35,9 +35,9 @@ async function testImageMap(browser, accDoc) {
|
|||
|
||||
tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: "a", children: [ ] },
|
||||
{ role: ROLE_LINK, name: "b", children: [ ] }
|
||||
]
|
||||
{ role: ROLE_LINK, name: "a", children: [] },
|
||||
{ role: ROLE_LINK, name: "b", children: [] },
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -46,8 +46,10 @@ async function testImageMap(browser, accDoc) {
|
|||
await ContentTask.spawn(browser, {}, () => {
|
||||
let areaElm = content.document.createElement("area");
|
||||
let mapNode = content.document.getElementById("map");
|
||||
areaElm.setAttribute("href",
|
||||
"http://www.bbc.co.uk/radio4/atoz/index.shtml#c");
|
||||
areaElm.setAttribute(
|
||||
"href",
|
||||
"http://www.bbc.co.uk/radio4/atoz/index.shtml#c"
|
||||
);
|
||||
areaElm.setAttribute("coords", "34,0,47,14");
|
||||
areaElm.setAttribute("alt", "c");
|
||||
areaElm.setAttribute("shape", "rect");
|
||||
|
@ -57,10 +59,10 @@ async function testImageMap(browser, accDoc) {
|
|||
|
||||
tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: "a", children: [ ] },
|
||||
{ role: ROLE_LINK, name: "b", children: [ ] },
|
||||
{ role: ROLE_LINK, name: "c", children: [ ] }
|
||||
]
|
||||
{ role: ROLE_LINK, name: "a", children: [] },
|
||||
{ role: ROLE_LINK, name: "b", children: [] },
|
||||
{ role: ROLE_LINK, name: "c", children: [] },
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -74,9 +76,9 @@ async function testImageMap(browser, accDoc) {
|
|||
|
||||
tree = {
|
||||
IMAGE_MAP: [
|
||||
{ role: ROLE_LINK, name: "b", children: [ ] },
|
||||
{ role: ROLE_LINK, name: "c", children: [ ] }
|
||||
]
|
||||
{ role: ROLE_LINK, name: "b", children: [] },
|
||||
{ role: ROLE_LINK, name: "c", children: [] },
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
@ -90,9 +92,7 @@ async function testContainer(browser) {
|
|||
const acc = event.accessible;
|
||||
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [ ] }
|
||||
]
|
||||
SECTION: [{ GRAPHIC: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -100,17 +100,21 @@ async function testContainer(browser) {
|
|||
onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
await invokeSetAttribute(browser, "map", "name", "atoz_map");
|
||||
// XXX: force repainting of the image (see bug 745788 for details).
|
||||
await BrowserTestUtils.synthesizeMouse("#imgmap", 10, 10,
|
||||
{ type: "mousemove" }, browser);
|
||||
await BrowserTestUtils.synthesizeMouse(
|
||||
"#imgmap",
|
||||
10,
|
||||
10,
|
||||
{ type: "mousemove" },
|
||||
browser
|
||||
);
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ {
|
||||
IMAGE_MAP: [
|
||||
{ LINK: [ ] },
|
||||
{ LINK: [ ] }
|
||||
]
|
||||
} ]
|
||||
SECTION: [
|
||||
{
|
||||
IMAGE_MAP: [{ LINK: [] }, { LINK: [] }],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -123,9 +127,7 @@ async function testContainer(browser) {
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [ ] }
|
||||
]
|
||||
SECTION: [{ GRAPHIC: [] }],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -138,8 +140,7 @@ async function testContainer(browser) {
|
|||
map.setAttribute("name", "atoz_map");
|
||||
map.setAttribute("id", "map");
|
||||
|
||||
area.setAttribute("href",
|
||||
"http://www.bbc.co.uk/radio4/atoz/index.shtml#b");
|
||||
area.setAttribute("href", "http://www.bbc.co.uk/radio4/atoz/index.shtml#b");
|
||||
area.setAttribute("coords", "17,0,30,14");
|
||||
area.setAttribute("alt", "b");
|
||||
area.setAttribute("shape", "rect");
|
||||
|
@ -150,11 +151,11 @@ async function testContainer(browser) {
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ {
|
||||
IMAGE_MAP: [
|
||||
{ LINK: [ ] }
|
||||
]
|
||||
} ]
|
||||
SECTION: [
|
||||
{
|
||||
IMAGE_MAP: [{ LINK: [] }],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
|
||||
|
@ -164,7 +165,7 @@ async function testContainer(browser) {
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ ]
|
||||
SECTION: [],
|
||||
};
|
||||
testAccessibleTree(acc, tree);
|
||||
}
|
||||
|
@ -178,12 +179,20 @@ async function waitForImageMap(browser, accDoc) {
|
|||
|
||||
const onReorder = waitForEvent(EVENT_REORDER, id);
|
||||
// Wave over image map
|
||||
await BrowserTestUtils.synthesizeMouse(`#${id}`, 10, 10,
|
||||
{ type: "mousemove" }, browser);
|
||||
await BrowserTestUtils.synthesizeMouse(
|
||||
`#${id}`,
|
||||
10,
|
||||
10,
|
||||
{ type: "mousemove" },
|
||||
browser
|
||||
);
|
||||
await onReorder;
|
||||
}
|
||||
|
||||
addAccessibleTask("doc_treeupdate_imagemap.html", async function(browser, accDoc) {
|
||||
addAccessibleTask("doc_treeupdate_imagemap.html", async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
await waitForImageMap(browser, accDoc);
|
||||
await testImageMap(browser, accDoc);
|
||||
await testContainer(browser);
|
||||
|
|
|
@ -13,30 +13,39 @@ async function setDisplayAndWaitForReorder(browser, value) {
|
|||
return onReorder;
|
||||
}
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<ul id="ul">
|
||||
<li id="li">item1</li>
|
||||
</ul>`, async function(browser, accDoc) {
|
||||
let li = findAccessibleChildByID(accDoc, "li");
|
||||
let bullet = li.firstChild;
|
||||
let accTree = {
|
||||
role: ROLE_LISTITEM,
|
||||
children: [ {
|
||||
role: ROLE_STATICTEXT,
|
||||
children: []
|
||||
}, {
|
||||
role: ROLE_TEXT_LEAF,
|
||||
children: []
|
||||
} ]
|
||||
};
|
||||
testAccessibleTree(li, accTree);
|
||||
</ul>`,
|
||||
async function(browser, accDoc) {
|
||||
let li = findAccessibleChildByID(accDoc, "li");
|
||||
let bullet = li.firstChild;
|
||||
let accTree = {
|
||||
role: ROLE_LISTITEM,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_STATICTEXT,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
role: ROLE_TEXT_LEAF,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(li, accTree);
|
||||
|
||||
await setDisplayAndWaitForReorder(browser, "none");
|
||||
await setDisplayAndWaitForReorder(browser, "none");
|
||||
|
||||
ok(isDefunct(li), "Check that li is defunct.");
|
||||
ok(isDefunct(bullet), "Check that bullet is defunct.");
|
||||
ok(isDefunct(li), "Check that li is defunct.");
|
||||
ok(isDefunct(bullet), "Check that bullet is defunct.");
|
||||
|
||||
let event = await setDisplayAndWaitForReorder(browser, "list-item");
|
||||
let event = await setDisplayAndWaitForReorder(browser, "list-item");
|
||||
|
||||
testAccessibleTree(findAccessibleChildByID(event.accessible, "li"), accTree);
|
||||
});
|
||||
testAccessibleTree(
|
||||
findAccessibleChildByID(event.accessible, "li"),
|
||||
accTree
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -12,7 +12,7 @@ addAccessibleTask('<ol id="list"></ol>', async function(browser, accDoc) {
|
|||
|
||||
testAccessibleTree(list, {
|
||||
role: ROLE_LIST,
|
||||
children: [ ]
|
||||
children: [],
|
||||
});
|
||||
|
||||
await invokeSetAttribute(browser, "body", "contentEditable", "true");
|
||||
|
@ -26,12 +26,14 @@ addAccessibleTask('<ol id="list"></ol>', async function(browser, accDoc) {
|
|||
|
||||
testAccessibleTree(list, {
|
||||
role: ROLE_LIST,
|
||||
children: [ {
|
||||
role: ROLE_LISTITEM,
|
||||
children: [
|
||||
{ role: ROLE_STATICTEXT, name: "1. ", children: [] },
|
||||
{ role: ROLE_TEXT_LEAF, children: [] }
|
||||
]
|
||||
} ]
|
||||
children: [
|
||||
{
|
||||
role: ROLE_LISTITEM,
|
||||
children: [
|
||||
{ role: ROLE_STATICTEXT, name: "1. ", children: [] },
|
||||
{ role: ROLE_TEXT_LEAF, children: [] },
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,22 +7,31 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask('<span id="parent"><span id="child"></span></span>',
|
||||
addAccessibleTask(
|
||||
'<span id="parent"><span id="child"></span></span>',
|
||||
async function(browser, accDoc) {
|
||||
is(findAccessibleChildByID(accDoc, "parent"), null,
|
||||
"Check that parent is not accessible.");
|
||||
is(findAccessibleChildByID(accDoc, "child"), null,
|
||||
"Check that child is not accessible.");
|
||||
is(
|
||||
findAccessibleChildByID(accDoc, "parent"),
|
||||
null,
|
||||
"Check that parent is not accessible."
|
||||
);
|
||||
is(
|
||||
findAccessibleChildByID(accDoc, "child"),
|
||||
null,
|
||||
"Check that child is not accessible."
|
||||
);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, "body");
|
||||
// Add an event listener to parent.
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
content.window.dummyListener = () => {};
|
||||
content.document.getElementById("parent").addEventListener(
|
||||
"click", content.window.dummyListener);
|
||||
content.document
|
||||
.getElementById("parent")
|
||||
.addEventListener("click", content.window.dummyListener);
|
||||
});
|
||||
await onReorder;
|
||||
|
||||
let tree = { TEXT: [] };
|
||||
testAccessibleTree(findAccessibleChildByID(accDoc, "parent"), tree);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask('<select id="select"></select>', async function(browser, accDoc) {
|
||||
addAccessibleTask('<select id="select"></select>', async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
let select = findAccessibleChildByID(accDoc, "select");
|
||||
|
||||
let onEvent = waitForEvent(EVENT_REORDER, "select");
|
||||
|
@ -35,18 +38,24 @@ addAccessibleTask('<select id="select"></select>', async function(browser, accDo
|
|||
let option1Node = findAccessibleChildByID(event.accessible, "option1Node");
|
||||
|
||||
let tree = {
|
||||
COMBOBOX: [ {
|
||||
COMBOBOX_LIST: [ {
|
||||
GROUPING: [
|
||||
{ COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] },
|
||||
{ COMBOBOX_OPTION: [ { TEXT_LEAF: [] } ] }
|
||||
]
|
||||
}, {
|
||||
COMBOBOX_OPTION: []
|
||||
}, {
|
||||
COMBOBOX_OPTION: []
|
||||
} ]
|
||||
} ]
|
||||
COMBOBOX: [
|
||||
{
|
||||
COMBOBOX_LIST: [
|
||||
{
|
||||
GROUPING: [
|
||||
{ COMBOBOX_OPTION: [{ TEXT_LEAF: [] }] },
|
||||
{ COMBOBOX_OPTION: [{ TEXT_LEAF: [] }] },
|
||||
],
|
||||
},
|
||||
{
|
||||
COMBOBOX_OPTION: [],
|
||||
},
|
||||
{
|
||||
COMBOBOX_OPTION: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(select, tree);
|
||||
ok(!isDefunct(option1Node), "option shouldn't be defunct");
|
||||
|
@ -60,16 +69,14 @@ addAccessibleTask('<select id="select"></select>', async function(browser, accDo
|
|||
await onEvent;
|
||||
|
||||
tree = {
|
||||
COMBOBOX: [ {
|
||||
COMBOBOX_LIST: [
|
||||
{ COMBOBOX_OPTION: [] },
|
||||
{ COMBOBOX_OPTION: [] }
|
||||
]
|
||||
} ]
|
||||
COMBOBOX: [
|
||||
{
|
||||
COMBOBOX_LIST: [{ COMBOBOX_OPTION: [] }, { COMBOBOX_OPTION: [] }],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(select, tree);
|
||||
ok(isDefunct(option1Node),
|
||||
"removed option shouldn't be accessible anymore!");
|
||||
ok(isDefunct(option1Node), "removed option shouldn't be accessible anymore!");
|
||||
|
||||
onEvent = waitForEvent(EVENT_REORDER, "select");
|
||||
// Remove all options from combobox
|
||||
|
@ -82,9 +89,11 @@ addAccessibleTask('<select id="select"></select>', async function(browser, accDo
|
|||
await onEvent;
|
||||
|
||||
tree = {
|
||||
COMBOBOX: [ {
|
||||
COMBOBOX_LIST: [ ]
|
||||
} ]
|
||||
COMBOBOX: [
|
||||
{
|
||||
COMBOBOX_LIST: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(select, tree);
|
||||
});
|
||||
|
|
|
@ -7,32 +7,51 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask("doc_treeupdate_removal.xhtml", async function(browser, accDoc) {
|
||||
ok(isAccessible(findAccessibleChildByID(accDoc, "the_table")),
|
||||
"table should be accessible");
|
||||
addAccessibleTask("doc_treeupdate_removal.xhtml", async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
ok(
|
||||
isAccessible(findAccessibleChildByID(accDoc, "the_table")),
|
||||
"table should be accessible"
|
||||
);
|
||||
|
||||
// Move the_table element into hidden subtree.
|
||||
let onReorder = waitForEvent(EVENT_REORDER, "body");
|
||||
await ContentTask.spawn(browser, {}, () => content.document.getElementById(
|
||||
"the_displaynone").appendChild(content.document.getElementById(
|
||||
"the_table")));
|
||||
await ContentTask.spawn(browser, {}, () =>
|
||||
content.document
|
||||
.getElementById("the_displaynone")
|
||||
.appendChild(content.document.getElementById("the_table"))
|
||||
);
|
||||
await onReorder;
|
||||
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
|
||||
"table in display none tree shouldn't be accessible");
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
|
||||
"row shouldn't be accessible");
|
||||
ok(
|
||||
!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
|
||||
"table in display none tree shouldn't be accessible"
|
||||
);
|
||||
ok(
|
||||
!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
|
||||
"row shouldn't be accessible"
|
||||
);
|
||||
|
||||
// Remove the_row element (since it did not have accessible, no event needed).
|
||||
await ContentTask.spawn(browser, {}, () =>
|
||||
content.document.body.removeChild(
|
||||
content.document.getElementById("the_row")));
|
||||
content.document.getElementById("the_row")
|
||||
)
|
||||
);
|
||||
|
||||
// make sure no accessibles have stuck around.
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
|
||||
"row shouldn't be accessible");
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
|
||||
"table shouldn't be accessible");
|
||||
ok(!isAccessible(findAccessibleChildByID(accDoc, "the_displayNone")),
|
||||
"display none things shouldn't be accessible");
|
||||
ok(
|
||||
!isAccessible(findAccessibleChildByID(accDoc, "the_row")),
|
||||
"row shouldn't be accessible"
|
||||
);
|
||||
ok(
|
||||
!isAccessible(findAccessibleChildByID(accDoc, "the_table")),
|
||||
"table shouldn't be accessible"
|
||||
);
|
||||
ok(
|
||||
!isAccessible(findAccessibleChildByID(accDoc, "the_displayNone")),
|
||||
"display none things shouldn't be accessible"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -7,44 +7,41 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<table id="table">
|
||||
<tr>
|
||||
<td>cell1</td>
|
||||
<td>cell2</td>
|
||||
</tr>
|
||||
</table>`, async function(browser, accDoc) {
|
||||
let table = findAccessibleChildByID(accDoc, "table");
|
||||
</table>`,
|
||||
async function(browser, accDoc) {
|
||||
let table = findAccessibleChildByID(accDoc, "table");
|
||||
|
||||
let tree = {
|
||||
TABLE: [
|
||||
{ ROW: [
|
||||
{ CELL: [ {TEXT_LEAF: [] }]},
|
||||
{ CELL: [ {TEXT_LEAF: [] }]}
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(table, tree);
|
||||
let tree = {
|
||||
TABLE: [
|
||||
{ ROW: [{ CELL: [{ TEXT_LEAF: [] }] }, { CELL: [{ TEXT_LEAF: [] }] }] },
|
||||
],
|
||||
};
|
||||
testAccessibleTree(table, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, "table");
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// append a caption, it should appear as a first element in the
|
||||
// accessible tree.
|
||||
let doc = content.document;
|
||||
let caption = doc.createElement("caption");
|
||||
caption.textContent = "table caption";
|
||||
doc.getElementById("table").appendChild(caption);
|
||||
});
|
||||
await onReorder;
|
||||
let onReorder = waitForEvent(EVENT_REORDER, "table");
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
// append a caption, it should appear as a first element in the
|
||||
// accessible tree.
|
||||
let doc = content.document;
|
||||
let caption = doc.createElement("caption");
|
||||
caption.textContent = "table caption";
|
||||
doc.getElementById("table").appendChild(caption);
|
||||
});
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
TABLE: [
|
||||
{ CAPTION: [ { TEXT_LEAF: [] } ] },
|
||||
{ ROW: [
|
||||
{ CELL: [ {TEXT_LEAF: [] }]},
|
||||
{ CELL: [ {TEXT_LEAF: [] }]}
|
||||
] }
|
||||
]
|
||||
};
|
||||
testAccessibleTree(table, tree);
|
||||
});
|
||||
tree = {
|
||||
TABLE: [
|
||||
{ CAPTION: [{ TEXT_LEAF: [] }] },
|
||||
{ ROW: [{ CELL: [{ TEXT_LEAF: [] }] }, { CELL: [{ TEXT_LEAF: [] }] }] },
|
||||
],
|
||||
};
|
||||
testAccessibleTree(table, tree);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -10,7 +10,7 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
|||
async function removeTextData(browser, accessible, id, role) {
|
||||
let tree = {
|
||||
role,
|
||||
children: [ { role: ROLE_TEXT_LEAF, name: "text" } ]
|
||||
children: [{ role: ROLE_TEXT_LEAF, name: "text" }],
|
||||
};
|
||||
testAccessibleTree(accessible, tree);
|
||||
|
||||
|
@ -24,11 +24,14 @@ async function removeTextData(browser, accessible, id, role) {
|
|||
testAccessibleTree(accessible, tree);
|
||||
}
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<p id="p">text</p>
|
||||
<pre id="pre">text</pre>`, async function(browser, accDoc) {
|
||||
let p = findAccessibleChildByID(accDoc, "p");
|
||||
let pre = findAccessibleChildByID(accDoc, "pre");
|
||||
await removeTextData(browser, p, "p", ROLE_PARAGRAPH);
|
||||
await removeTextData(browser, pre, "pre", ROLE_TEXT_CONTAINER);
|
||||
});
|
||||
<pre id="pre">text</pre>`,
|
||||
async function(browser, accDoc) {
|
||||
let p = findAccessibleChildByID(accDoc, "p");
|
||||
let pre = findAccessibleChildByID(accDoc, "pre");
|
||||
await removeTextData(browser, p, "p", ROLE_PARAGRAPH);
|
||||
await removeTextData(browser, pre, "pre", ROLE_TEXT_CONTAINER);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -20,18 +20,32 @@ async function testTreeOnHide(browser, accDoc, containerID, id, before, after) {
|
|||
|
||||
async function test3(browser, accessible) {
|
||||
let tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [ // parent
|
||||
{ SECTION: [ // child
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] },
|
||||
{ SECTION: [ // parent2
|
||||
{ SECTION: [ // child2
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
SECTION: [
|
||||
// container
|
||||
{
|
||||
SECTION: [
|
||||
// parent
|
||||
{
|
||||
SECTION: [
|
||||
// child
|
||||
{ TEXT_LEAF: [] },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
// parent2
|
||||
{
|
||||
SECTION: [
|
||||
// child2
|
||||
{ TEXT_LEAF: [] },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(accessible, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, "t3_container");
|
||||
|
@ -44,26 +58,29 @@ async function test3(browser, accessible) {
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [ // container
|
||||
{ SECTION: [ // child
|
||||
{ TEXT_LEAF: [] }
|
||||
] },
|
||||
{ SECTION: [ // child2
|
||||
{ TEXT_LEAF: [] }
|
||||
] }
|
||||
] };
|
||||
SECTION: [
|
||||
// container
|
||||
{
|
||||
SECTION: [
|
||||
// child
|
||||
{ TEXT_LEAF: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
// child2
|
||||
{ TEXT_LEAF: [] },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(accessible, tree);
|
||||
}
|
||||
|
||||
async function test4(browser, accessible) {
|
||||
let tree = {
|
||||
SECTION: [
|
||||
{ TABLE: [
|
||||
{ ROW: [
|
||||
{ CELL: [ ] }
|
||||
] }
|
||||
] }
|
||||
] };
|
||||
SECTION: [{ TABLE: [{ ROW: [{ CELL: [] }] }] }],
|
||||
};
|
||||
testAccessibleTree(accessible, tree);
|
||||
|
||||
let onReorder = waitForEvent(EVENT_REORDER, "t4_parent");
|
||||
|
@ -75,121 +92,250 @@ async function test4(browser, accessible) {
|
|||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [{
|
||||
TABLE: [{
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
SECTION: [{
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
SECTION: [
|
||||
{
|
||||
TABLE: [
|
||||
{
|
||||
ROW: [
|
||||
{
|
||||
CELL: [
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
testAccessibleTree(accessible, tree);
|
||||
}
|
||||
|
||||
addAccessibleTask("doc_treeupdate_visibility.html", async function(browser, accDoc) {
|
||||
addAccessibleTask("doc_treeupdate_visibility.html", async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
let t3Container = findAccessibleChildByID(accDoc, "t3_container");
|
||||
let t4Container = findAccessibleChildByID(accDoc, "t4_container");
|
||||
|
||||
await testTreeOnHide(browser, accDoc, "t1_container", "t1_parent", {
|
||||
SECTION: [{
|
||||
SECTION: [{
|
||||
SECTION: [ { TEXT_LEAF: [] } ]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [ {
|
||||
SECTION: [ { TEXT_LEAF: [] } ]
|
||||
} ]
|
||||
});
|
||||
await testTreeOnHide(
|
||||
browser,
|
||||
accDoc,
|
||||
"t1_container",
|
||||
"t1_parent",
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
SECTION: [{ TEXT_LEAF: [] }],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
SECTION: [{ TEXT_LEAF: [] }],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
await testTreeOnHide(browser, accDoc, "t2_container", "t2_grandparent", {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // grand parent
|
||||
SECTION: [{
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
});
|
||||
await testTreeOnHide(
|
||||
browser,
|
||||
accDoc,
|
||||
"t2_container",
|
||||
"t2_grandparent",
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// grand parent
|
||||
SECTION: [
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// child
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// child2
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// child
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// child2
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
await test3(browser, t3Container);
|
||||
await test4(browser, t4Container);
|
||||
|
||||
await testTreeOnHide(browser, accDoc, "t5_container", "t5_subcontainer", {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // subcontainer
|
||||
TABLE: [{
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
});
|
||||
await testTreeOnHide(
|
||||
browser,
|
||||
accDoc,
|
||||
"t5_container",
|
||||
"t5_subcontainer",
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// subcontainer
|
||||
TABLE: [
|
||||
{
|
||||
ROW: [
|
||||
{
|
||||
CELL: [
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// child
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// child
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
await testTreeOnHide(browser, accDoc, "t6_container", "t6_subcontainer", {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // subcontainer
|
||||
TABLE: [{
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
TABLE: [{ // nested table
|
||||
ROW: [{
|
||||
CELL: [{
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // container
|
||||
SECTION: [{ // child
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}, {
|
||||
SECTION: [{ // child2
|
||||
TEXT_LEAF: []
|
||||
}]
|
||||
}]
|
||||
});
|
||||
await testTreeOnHide(
|
||||
browser,
|
||||
accDoc,
|
||||
"t6_container",
|
||||
"t6_subcontainer",
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// subcontainer
|
||||
TABLE: [
|
||||
{
|
||||
ROW: [
|
||||
{
|
||||
CELL: [
|
||||
{
|
||||
TABLE: [
|
||||
{
|
||||
// nested table
|
||||
ROW: [
|
||||
{
|
||||
CELL: [
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// child
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// child2
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// container
|
||||
SECTION: [
|
||||
{
|
||||
// child
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
SECTION: [
|
||||
{
|
||||
// child2
|
||||
TEXT_LEAF: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accDoc) {
|
||||
addAccessibleTask("doc_treeupdate_whitespace.html", async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
let container1 = findAccessibleChildByID(accDoc, "container1");
|
||||
let container2Parent = findAccessibleChildByID(accDoc, "container2-parent");
|
||||
|
||||
|
@ -17,8 +20,8 @@ addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accD
|
|||
{ TEXT_LEAF: [] },
|
||||
{ GRAPHIC: [] },
|
||||
{ TEXT_LEAF: [] },
|
||||
{ GRAPHIC: [] }
|
||||
]
|
||||
{ GRAPHIC: [] },
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
|
@ -26,25 +29,17 @@ addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accD
|
|||
// Remove img1 from container1
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
let doc = content.document;
|
||||
doc.getElementById("container1").removeChild(
|
||||
doc.getElementById("img1"));
|
||||
doc.getElementById("container1").removeChild(doc.getElementById("img1"));
|
||||
});
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ GRAPHIC: [] },
|
||||
{ TEXT_LEAF: [] },
|
||||
{ GRAPHIC: [] }
|
||||
]
|
||||
SECTION: [{ GRAPHIC: [] }, { TEXT_LEAF: [] }, { GRAPHIC: [] }],
|
||||
};
|
||||
testAccessibleTree(container1, tree);
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ LINK: [] },
|
||||
{ LINK: [ { GRAPHIC: [] } ] }
|
||||
]
|
||||
SECTION: [{ LINK: [] }, { LINK: [{ GRAPHIC: [] }] }],
|
||||
};
|
||||
testAccessibleTree(container2Parent, tree);
|
||||
|
||||
|
@ -53,18 +48,20 @@ addAccessibleTask("doc_treeupdate_whitespace.html", async function(browser, accD
|
|||
await ContentTask.spawn(browser, {}, () => {
|
||||
let doc = content.document;
|
||||
let img = doc.createElement("img");
|
||||
img.setAttribute("src",
|
||||
"http://example.com/a11y/accessible/tests/mochitest/moz.png");
|
||||
img.setAttribute(
|
||||
"src",
|
||||
"http://example.com/a11y/accessible/tests/mochitest/moz.png"
|
||||
);
|
||||
doc.getElementById("container2").appendChild(img);
|
||||
});
|
||||
await onReorder;
|
||||
|
||||
tree = {
|
||||
SECTION: [
|
||||
{ LINK: [ { GRAPHIC: [ ] } ] },
|
||||
{ TEXT_LEAF: [ ] },
|
||||
{ LINK: [ { GRAPHIC: [ ] } ] }
|
||||
]
|
||||
{ LINK: [{ GRAPHIC: [] }] },
|
||||
{ TEXT_LEAF: [] },
|
||||
{ LINK: [{ GRAPHIC: [] }] },
|
||||
],
|
||||
};
|
||||
testAccessibleTree(container2Parent, tree);
|
||||
});
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
/* import-globals-from ../shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
waitForOrderedEvents */
|
||||
|
||||
const EVENT_ANNOUNCEMENT = nsIAccessibleEvent.EVENT_ANNOUNCEMENT;
|
||||
const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
|
||||
const EVENT_DOCUMENT_LOAD_COMPLETE =
|
||||
nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
|
||||
const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
|
||||
const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
|
||||
const EVENT_SCROLLING = nsIAccessibleEvent.EVENT_SCROLLING;
|
||||
|
@ -35,7 +36,8 @@ const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE;
|
|||
const EVENT_TEXT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_TEXT_VALUE_CHANGE;
|
||||
const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
|
||||
const EVENT_DOCUMENT_RELOAD = nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD;
|
||||
const EVENT_VIRTUALCURSOR_CHANGED = nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED;
|
||||
const EVENT_VIRTUALCURSOR_CHANGED =
|
||||
nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED;
|
||||
|
||||
/**
|
||||
* Describe an event in string format.
|
||||
|
@ -46,12 +48,16 @@ function eventToString(event) {
|
|||
let info = `Event type: ${type}`;
|
||||
|
||||
if (event instanceof nsIAccessibleStateChangeEvent) {
|
||||
let stateStr = statesToString(event.isExtraState ? 0 : event.state,
|
||||
event.isExtraState ? event.state : 0);
|
||||
let stateStr = statesToString(
|
||||
event.isExtraState ? 0 : event.state,
|
||||
event.isExtraState ? event.state : 0
|
||||
);
|
||||
info += `, state: ${stateStr}, is enabled: ${event.isEnabled}`;
|
||||
} else if (event instanceof nsIAccessibleTextChangeEvent) {
|
||||
let tcType = event.isInserted ? "inserted" : "removed";
|
||||
info += `, start: ${event.start}, length: ${event.length}, ${tcType} text: ${event.modifiedText}`;
|
||||
info += `, start: ${event.start}, length: ${
|
||||
event.length
|
||||
}, ${tcType} text: ${event.modifiedText}`;
|
||||
}
|
||||
|
||||
info += `. Target: ${prettyName(event.accessible)}`;
|
||||
|
@ -121,7 +127,7 @@ function waitForEvent(eventType, matchCriteria) {
|
|||
Services.obs.removeObserver(this, "accessible-event");
|
||||
resolve(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(eventObserver, "accessible-event");
|
||||
});
|
||||
|
@ -142,8 +148,10 @@ class UnexpectedEvents {
|
|||
|
||||
let event = subject.QueryInterface(nsIAccessibleEvent);
|
||||
|
||||
let unexpectedEvent = this.unexpected.find(([etype, criteria]) =>
|
||||
etype === event.eventType && matchEvent(event, criteria));
|
||||
let unexpectedEvent = this.unexpected.find(
|
||||
([etype, criteria]) =>
|
||||
etype === event.eventType && matchEvent(event, criteria)
|
||||
);
|
||||
|
||||
if (unexpectedEvent) {
|
||||
ok(false, `Got unexpected event: ${eventToString(event)}`);
|
||||
|
@ -171,16 +179,17 @@ function waitForEvents(events, ordered = false) {
|
|||
|
||||
let unexpectedListener = new UnexpectedEvents(unexpected);
|
||||
|
||||
return Promise.all(expected.map((evt, idx) => {
|
||||
let promise = evt instanceof Array ? waitForEvent(...evt) : evt;
|
||||
return promise.then(result => {
|
||||
if (ordered) {
|
||||
is(idx, currentIdx++,
|
||||
`Unexpected event order: ${result}`);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
})).then(results => {
|
||||
return Promise.all(
|
||||
expected.map((evt, idx) => {
|
||||
let promise = evt instanceof Array ? waitForEvent(...evt) : evt;
|
||||
return promise.then(result => {
|
||||
if (ordered) {
|
||||
is(idx, currentIdx++, `Unexpected event order: ${result}`);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
})
|
||||
).then(results => {
|
||||
unexpectedListener.stop();
|
||||
return results;
|
||||
});
|
||||
|
|
|
@ -35,23 +35,28 @@ async function runTests(browser, accDoc) {
|
|||
expected: [
|
||||
[EVENT_REORDER, getAccessible(browser)],
|
||||
[EVENT_DOCUMENT_LOAD_COMPLETE, "body2"],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)]],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
],
|
||||
unexpected: [
|
||||
[EVENT_DOCUMENT_LOAD_COMPLETE, inIframeChecker("iframe1")],
|
||||
[EVENT_STATE_CHANGE, inIframeChecker("iframe1")]]
|
||||
[EVENT_STATE_CHANGE, inIframeChecker("iframe1")],
|
||||
],
|
||||
});
|
||||
|
||||
BrowserTestUtils.loadURI(browser, `data:text/html;charset=utf-8,
|
||||
BrowserTestUtils.loadURI(
|
||||
browser,
|
||||
`data:text/html;charset=utf-8,
|
||||
<html><body id="body2">
|
||||
<iframe id="iframe1" src="http://example.com"></iframe>
|
||||
</body></html>`);
|
||||
</body></html>`
|
||||
);
|
||||
|
||||
await onLoadEvents;
|
||||
|
||||
onLoadEvents = waitForEvents([
|
||||
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("about:about")],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
[EVENT_REORDER, getAccessible(browser)]
|
||||
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("about:about")],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
[EVENT_REORDER, getAccessible(browser)],
|
||||
]);
|
||||
|
||||
BrowserTestUtils.loadURI(browser, "about:about");
|
||||
|
@ -61,7 +66,7 @@ async function runTests(browser, accDoc) {
|
|||
onLoadEvents = waitForEvents([
|
||||
[EVENT_DOCUMENT_RELOAD, evt => evt.isFromUserInput],
|
||||
[EVENT_REORDER, getAccessible(browser)],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)]
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
]);
|
||||
|
||||
EventUtils.synthesizeKey("VK_F5", {}, browser.ownerGlobal);
|
||||
|
@ -71,7 +76,7 @@ async function runTests(browser, accDoc) {
|
|||
onLoadEvents = waitForEvents([
|
||||
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("about:mozilla")],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
[EVENT_REORDER, getAccessible(browser)]
|
||||
[EVENT_REORDER, getAccessible(browser)],
|
||||
]);
|
||||
|
||||
BrowserTestUtils.loadURI(browser, "about:mozilla");
|
||||
|
@ -81,7 +86,7 @@ async function runTests(browser, accDoc) {
|
|||
onLoadEvents = waitForEvents([
|
||||
[EVENT_DOCUMENT_RELOAD, evt => !evt.isFromUserInput],
|
||||
[EVENT_REORDER, getAccessible(browser)],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)]
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
]);
|
||||
|
||||
browser.reload();
|
||||
|
@ -91,7 +96,7 @@ async function runTests(browser, accDoc) {
|
|||
onLoadEvents = waitForEvents([
|
||||
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("http://www.wronguri.wronguri/")],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
[EVENT_REORDER, getAccessible(browser)]
|
||||
[EVENT_REORDER, getAccessible(browser)],
|
||||
]);
|
||||
|
||||
BrowserTestUtils.loadURI(browser, "http://www.wronguri.wronguri/");
|
||||
|
@ -101,7 +106,7 @@ async function runTests(browser, accDoc) {
|
|||
onLoadEvents = waitForEvents([
|
||||
[EVENT_DOCUMENT_LOAD_COMPLETE, urlChecker("https://nocert.example.com/")],
|
||||
[EVENT_STATE_CHANGE, busyChecker(false)],
|
||||
[EVENT_REORDER, getAccessible(browser)]
|
||||
[EVENT_REORDER, getAccessible(browser)],
|
||||
]);
|
||||
|
||||
BrowserTestUtils.loadURI(browser, "https://nocert.example.com:443/");
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
/* import-globals-from ../../mochitest/states.js */
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "states.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
loadScripts(
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
async function runTests(browser, accDoc) {
|
||||
let onFocus = waitForEvent(EVENT_FOCUS, "input");
|
||||
|
@ -16,9 +18,11 @@ async function runTests(browser, accDoc) {
|
|||
testStates(evt.accessible, STATE_FOCUSED);
|
||||
|
||||
onFocus = waitForEvent(EVENT_FOCUS, "buttonInputDoc");
|
||||
let url = snippetToURL(`<input id="input" type="button" value="button">`, { id: "buttonInputDoc" });
|
||||
let url = snippetToURL(`<input id="input" type="button" value="button">`, {
|
||||
id: "buttonInputDoc",
|
||||
});
|
||||
browser.loadURI(url, {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
});
|
||||
evt = await onFocus;
|
||||
testStates(evt.accessible, STATE_FOCUSED);
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
/* import-globals-from ../../mochitest/states.js */
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "states.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
loadScripts(
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
async function runTests(browser, accDoc) {
|
||||
let onFocus = waitForEvent(EVENT_FOCUS, "button");
|
||||
|
@ -32,7 +34,9 @@ async function runTests(browser, accDoc) {
|
|||
|
||||
onFocus = waitForEvent(EVENT_FOCUS, "body2");
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
content.document.getElementById("editabledoc").contentWindow.document.body.focus();
|
||||
content.document
|
||||
.getElementById("editabledoc")
|
||||
.contentWindow.document.body.focus();
|
||||
});
|
||||
testStates((await onFocus).accessible, STATE_FOCUSED);
|
||||
|
||||
|
@ -55,13 +59,16 @@ async function runTests(browser, accDoc) {
|
|||
/**
|
||||
* Accessible dialog focus testing
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<button id="button">button</button>
|
||||
<iframe id="editabledoc"
|
||||
src="${snippetToURL("", { id: "body2", contentEditable: "true"})}">
|
||||
src="${snippetToURL("", { id: "body2", contentEditable: "true" })}">
|
||||
</iframe>
|
||||
<div id="alertdialog" style="display: none" tabindex="-1" role="alertdialog" aria-labelledby="title2" aria-describedby="desc2">
|
||||
<div id="title2">Blah blah</div>
|
||||
<div id="desc2">Woof woof woof.</div>
|
||||
<button>Close</button>
|
||||
</div>`, runTests);
|
||||
</div>`,
|
||||
runTests
|
||||
);
|
||||
|
|
|
@ -5,12 +5,20 @@
|
|||
|
||||
/* import-globals-from ../../mochitest/states.js */
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts({ name: "states.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR });
|
||||
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
|
||||
"resource://testing-common/PlacesTestUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
loadScripts(
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"PlacesTestUtils",
|
||||
"resource://testing-common/PlacesTestUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm"
|
||||
);
|
||||
|
||||
function isEventForAutocompleteItem(event) {
|
||||
return event.accessible.role == ROLE_COMBOBOX_OPTION;
|
||||
|
@ -26,13 +34,16 @@ function waitForSearchFinish() {
|
|||
if (UrlbarPrefs.get("quantumbar")) {
|
||||
return Promise.all([
|
||||
gURLBar.lastQueryContextPromise,
|
||||
BrowserTestUtils.waitForCondition(() => gURLBar.view.isOpen)
|
||||
BrowserTestUtils.waitForCondition(() => gURLBar.view.isOpen),
|
||||
]);
|
||||
}
|
||||
return BrowserTestUtils.waitForCondition(() =>
|
||||
(gURLBar.popupOpen && gURLBar.controller.searchStatus >=
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH),
|
||||
"Waiting for search to complete");
|
||||
return BrowserTestUtils.waitForCondition(
|
||||
() =>
|
||||
gURLBar.popupOpen &&
|
||||
gURLBar.controller.searchStatus >=
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH,
|
||||
"Waiting for search to complete"
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the URL bar manages accessibility focus appropriately.
|
||||
|
@ -42,14 +53,16 @@ async function runTests() {
|
|||
});
|
||||
|
||||
await PlacesTestUtils.addVisits([
|
||||
{uri: makeURI("http://example1.com/blah")},
|
||||
{uri: makeURI("http://example2.com/blah")},
|
||||
{uri: makeURI("http://example1.com/")},
|
||||
{uri: makeURI("http://example2.com/")}
|
||||
{ uri: makeURI("http://example1.com/blah") },
|
||||
{ uri: makeURI("http://example2.com/blah") },
|
||||
{ uri: makeURI("http://example1.com/") },
|
||||
{ uri: makeURI("http://example2.com/") },
|
||||
]);
|
||||
|
||||
let focused = waitForEvent(EVENT_FOCUS,
|
||||
event => event.accessible.role == ROLE_ENTRY);
|
||||
let focused = waitForEvent(
|
||||
EVENT_FOCUS,
|
||||
event => event.accessible.role == ROLE_ENTRY
|
||||
);
|
||||
gURLBar.focus();
|
||||
let event = await focused;
|
||||
let textBox = event.accessible;
|
||||
|
@ -75,7 +88,7 @@ async function runTests() {
|
|||
testStates(textBox, STATE_FOCUSED);
|
||||
|
||||
info("Ensuring no focus change on text selection and delete");
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {shiftKey: true});
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", { shiftKey: true });
|
||||
EventUtils.synthesizeKey("KEY_Delete");
|
||||
await waitForSearchFinish();
|
||||
// Wait a tick for a11y events to fire.
|
||||
|
@ -97,13 +110,13 @@ async function runTests() {
|
|||
if (AppConstants.platform == "macosx") {
|
||||
info("Ensuring focus of another autocomplete item on ctrl-n");
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
|
||||
EventUtils.synthesizeKey("n", {ctrlKey: true});
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
|
||||
info("Ensuring focus of another autocomplete item on ctrl-p");
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
|
||||
EventUtils.synthesizeKey("p", {ctrlKey: true});
|
||||
EventUtils.synthesizeKey("p", { ctrlKey: true });
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
}
|
||||
|
@ -164,7 +177,7 @@ async function runTests() {
|
|||
|
||||
info("Ensuring text box focus on text selection");
|
||||
focused = waitForEvent(EVENT_FOCUS, textBox);
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", {shiftKey: true});
|
||||
EventUtils.synthesizeKey("KEY_ArrowLeft", { shiftKey: true });
|
||||
await focused;
|
||||
testStates(textBox, STATE_FOCUSED);
|
||||
|
||||
|
@ -175,7 +188,7 @@ async function runTests() {
|
|||
|
||||
info("Ensuring autocomplete focus on ctrl-n");
|
||||
focused = waitForEvent(EVENT_FOCUS, isEventForAutocompleteItem);
|
||||
EventUtils.synthesizeKey("n", {ctrlKey: true});
|
||||
EventUtils.synthesizeKey("n", { ctrlKey: true });
|
||||
event = await focused;
|
||||
testStates(event.accessible, STATE_FOCUSED);
|
||||
}
|
||||
|
|
|
@ -4,47 +4,71 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div style="height: 100vh" id="one">one</div>
|
||||
<div style="height: 100vh" id="two">two</div>
|
||||
<div style="height: 100vh; width: 200vw" id="three">three</div>`,
|
||||
async function(browser, accDoc) {
|
||||
let onScrolling = waitForEvents([
|
||||
[EVENT_SCROLLING, accDoc], [EVENT_SCROLLING_END, accDoc]]);
|
||||
[EVENT_SCROLLING, accDoc],
|
||||
[EVENT_SCROLLING_END, accDoc],
|
||||
]);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
content.location.hash = "#two";
|
||||
});
|
||||
let [scrollEvent1, scrollEndEvent1] = await onScrolling;
|
||||
scrollEvent1.QueryInterface(nsIAccessibleScrollingEvent);
|
||||
ok(scrollEvent1.maxScrollY >= scrollEvent1.scrollY, "scrollY is within max");
|
||||
ok(
|
||||
scrollEvent1.maxScrollY >= scrollEvent1.scrollY,
|
||||
"scrollY is within max"
|
||||
);
|
||||
scrollEndEvent1.QueryInterface(nsIAccessibleScrollingEvent);
|
||||
ok(scrollEndEvent1.maxScrollY >= scrollEndEvent1.scrollY,
|
||||
"scrollY is within max");
|
||||
ok(
|
||||
scrollEndEvent1.maxScrollY >= scrollEndEvent1.scrollY,
|
||||
"scrollY is within max"
|
||||
);
|
||||
|
||||
onScrolling = waitForEvents([
|
||||
[EVENT_SCROLLING, accDoc], [EVENT_SCROLLING_END, accDoc]]);
|
||||
[EVENT_SCROLLING, accDoc],
|
||||
[EVENT_SCROLLING_END, accDoc],
|
||||
]);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
content.location.hash = "#three";
|
||||
});
|
||||
let [scrollEvent2, scrollEndEvent2] = await onScrolling;
|
||||
scrollEvent2.QueryInterface(nsIAccessibleScrollingEvent);
|
||||
ok(scrollEvent2.scrollY > scrollEvent1.scrollY,
|
||||
`${scrollEvent2.scrollY} > ${scrollEvent1.scrollY}`);
|
||||
ok(
|
||||
scrollEvent2.scrollY > scrollEvent1.scrollY,
|
||||
`${scrollEvent2.scrollY} > ${scrollEvent1.scrollY}`
|
||||
);
|
||||
scrollEndEvent2.QueryInterface(nsIAccessibleScrollingEvent);
|
||||
ok(scrollEndEvent2.maxScrollY >= scrollEndEvent2.scrollY,
|
||||
"scrollY is within max");
|
||||
ok(
|
||||
scrollEndEvent2.maxScrollY >= scrollEndEvent2.scrollY,
|
||||
"scrollY is within max"
|
||||
);
|
||||
|
||||
onScrolling = waitForEvents([
|
||||
[EVENT_SCROLLING, accDoc], [EVENT_SCROLLING_END, accDoc]]);
|
||||
[EVENT_SCROLLING, accDoc],
|
||||
[EVENT_SCROLLING_END, accDoc],
|
||||
]);
|
||||
await ContentTask.spawn(browser, null, () => {
|
||||
content.scrollTo(10, 0);
|
||||
});
|
||||
let [scrollEvent3, scrollEndEvent3] = await onScrolling;
|
||||
scrollEvent3.QueryInterface(nsIAccessibleScrollingEvent);
|
||||
ok(scrollEvent3.maxScrollX >= scrollEvent3.scrollX, "scrollX is within max");
|
||||
ok(
|
||||
scrollEvent3.maxScrollX >= scrollEvent3.scrollX,
|
||||
"scrollX is within max"
|
||||
);
|
||||
scrollEndEvent3.QueryInterface(nsIAccessibleScrollingEvent);
|
||||
ok(scrollEndEvent3.maxScrollX >= scrollEndEvent3.scrollX,
|
||||
"scrollY is within max");
|
||||
ok(scrollEvent3.scrollX > scrollEvent2.scrollX,
|
||||
`${scrollEvent3.scrollX} > ${scrollEvent2.scrollX}`);
|
||||
});
|
||||
ok(
|
||||
scrollEndEvent3.maxScrollX >= scrollEndEvent3.scrollX,
|
||||
"scrollY is within max"
|
||||
);
|
||||
ok(
|
||||
scrollEvent3.scrollX > scrollEvent2.scrollX,
|
||||
`${scrollEvent3.scrollX} > ${scrollEvent2.scrollX}`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
function caretMoveChecker(target, caretOffset) {
|
||||
return function(event) {
|
||||
let cmEvent = event.QueryInterface(nsIAccessibleCaretMoveEvent);
|
||||
return cmEvent.accessible == getAccessible(target) && cmEvent.caretOffset == caretOffset;
|
||||
return (
|
||||
cmEvent.accessible == getAccessible(target) &&
|
||||
cmEvent.caretOffset == caretOffset
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -18,24 +21,21 @@ async function checkURLBarCaretEvents() {
|
|||
let newWin = await BrowserTestUtils.openNewBrowserWindow();
|
||||
BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, kURL);
|
||||
|
||||
await waitForEvent(
|
||||
EVENT_DOCUMENT_LOAD_COMPLETE,
|
||||
event => {
|
||||
try {
|
||||
return event.accessible.QueryInterface(nsIAccessibleDocument).URL == kURL;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
await waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, event => {
|
||||
try {
|
||||
return event.accessible.QueryInterface(nsIAccessibleDocument).URL == kURL;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
);
|
||||
});
|
||||
info("Loaded " + kURL);
|
||||
|
||||
let urlbarInputEl = newWin.document.getElementById("urlbar").inputField;
|
||||
let urlbarInput = getAccessible(urlbarInputEl, [ nsIAccessibleText ]);
|
||||
let urlbarInput = getAccessible(urlbarInputEl, [nsIAccessibleText]);
|
||||
|
||||
let onCaretMove = waitForEvents([
|
||||
[ EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, kURL.length) ],
|
||||
[ EVENT_FOCUS, urlbarInput ]
|
||||
[EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, kURL.length)],
|
||||
[EVENT_FOCUS, urlbarInput],
|
||||
]);
|
||||
|
||||
urlbarInput.caretOffset = -1;
|
||||
|
@ -43,7 +43,8 @@ async function checkURLBarCaretEvents() {
|
|||
ok(true, "Caret move in URL bar #1");
|
||||
|
||||
onCaretMove = waitForEvent(
|
||||
EVENT_TEXT_CARET_MOVED, caretMoveChecker(urlbarInput, 0)
|
||||
EVENT_TEXT_CARET_MOVED,
|
||||
caretMoveChecker(urlbarInput, 0)
|
||||
);
|
||||
|
||||
urlbarInput.caretOffset = 0;
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
/* import-globals-from ../shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
|
|
|
@ -37,11 +37,13 @@ add_task(async function testDocumentCreation() {
|
|||
info("Verifying that each tab content document is in accessible cache.");
|
||||
for (const browser of [...gBrowser.browsers]) {
|
||||
await ContentTask.spawn(browser, null, async () => {
|
||||
let accServiceContent =
|
||||
Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
ok(!!accServiceContent.getAccessibleFromCache(content.document),
|
||||
"Document accessible is in cache.");
|
||||
let accServiceContent = Cc[
|
||||
"@mozilla.org/accessibilityService;1"
|
||||
].getService(Ci.nsIAccessibilityService);
|
||||
ok(
|
||||
!!accServiceContent.getAccessibleFromCache(content.document),
|
||||
"Document accessible is in cache."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {UrlbarTestUtils} = ChromeUtils.import("resource://testing-common/UrlbarTestUtils.jsm");
|
||||
const { UrlbarTestUtils } = ChromeUtils.import(
|
||||
"resource://testing-common/UrlbarTestUtils.jsm"
|
||||
);
|
||||
|
||||
// Checking that the awesomebar popup gets COMBOBOX_LIST role instead of
|
||||
// LISTBOX, since its parent is a <panel> (see Bug 1422465)
|
||||
|
@ -12,22 +14,32 @@ add_task(async function testAutocompleteRichResult() {
|
|||
let tab = await openNewTab("data:text/html;charset=utf-8,");
|
||||
let accService = await initAccessibilityService();
|
||||
|
||||
info("Opening the URL bar and entering a key to show the PopupAutoCompleteRichResult panel");
|
||||
info(
|
||||
"Opening the URL bar and entering a key to show the PopupAutoCompleteRichResult panel"
|
||||
);
|
||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||
window,
|
||||
waitForFocus,
|
||||
value: "a"
|
||||
value: "a",
|
||||
});
|
||||
|
||||
info("Waiting for accessibility to be created for the richlistbox");
|
||||
let resultsView;
|
||||
if (UrlbarPrefs.get("quantumbar")) {
|
||||
resultsView = gURLBar.view.panel.querySelector("#urlbarView-results");
|
||||
await BrowserTestUtils.waitForCondition(() => accService.getAccessibleFor(resultsView));
|
||||
await BrowserTestUtils.waitForCondition(() =>
|
||||
accService.getAccessibleFor(resultsView)
|
||||
);
|
||||
} else {
|
||||
let urlbarPopup = document.getElementById("PopupAutoCompleteRichResult");
|
||||
resultsView = document.getAnonymousElementByAttribute(urlbarPopup, "anonid", "richlistbox");
|
||||
await BrowserTestUtils.waitForCondition(() => accService.getAccessibleFor(resultsView));
|
||||
resultsView = document.getAnonymousElementByAttribute(
|
||||
urlbarPopup,
|
||||
"anonid",
|
||||
"richlistbox"
|
||||
);
|
||||
await BrowserTestUtils.waitForCondition(() =>
|
||||
accService.getAccessibleFor(resultsView)
|
||||
);
|
||||
}
|
||||
|
||||
info("Confirming that the special case is handled in XULListboxAccessible");
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
/* import-globals-from ../shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
const nsIAccessibleRole = Ci.nsIAccessibleRole; // eslint-disable-line no-unused-vars
|
||||
|
||||
|
@ -20,14 +21,18 @@ loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
|
|||
async function openNewTab(url) {
|
||||
const forceNewProcess = true;
|
||||
|
||||
return BrowserTestUtils.openNewForegroundTab(
|
||||
{ gBrowser, url, forceNewProcess });
|
||||
return BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url,
|
||||
forceNewProcess,
|
||||
});
|
||||
}
|
||||
|
||||
async function initAccessibilityService() {
|
||||
info("Create accessibility service.");
|
||||
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService);
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
|
||||
await new Promise(resolve => {
|
||||
if (Services.appinfo.accessibilityEnabled) {
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
*/
|
||||
function setE10sPrefs() {
|
||||
return new Promise(resolve =>
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.tabs.remote.autostart", true]
|
||||
]
|
||||
}, resolve));
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{
|
||||
set: [["browser.tabs.remote.autostart", true]],
|
||||
},
|
||||
resolve
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,7 +36,8 @@ function unsetE10sPrefs() {
|
|||
/* import-globals-from shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns a promise that resolves when 'a11y-consumers-changed' event is fired.
|
||||
|
@ -81,7 +84,8 @@ function contentA11yInitOrShutdownPromise(browser) {
|
|||
*/
|
||||
function promiseOK(promise, expected) {
|
||||
return promise.then(flag =>
|
||||
flag === expected ? Promise.resolve() : Promise.reject());
|
||||
flag === expected ? Promise.resolve() : Promise.reject()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,12 +98,13 @@ function promiseOK(promise, expected) {
|
|||
* service initialized correctly.
|
||||
*/
|
||||
function initPromise(contentBrowser) {
|
||||
let a11yInitPromise = contentBrowser ?
|
||||
contentA11yInitOrShutdownPromise(contentBrowser) :
|
||||
a11yInitOrShutdownPromise();
|
||||
let a11yInitPromise = contentBrowser
|
||||
? contentA11yInitOrShutdownPromise(contentBrowser)
|
||||
: a11yInitOrShutdownPromise();
|
||||
return promiseOK(a11yInitPromise, "1").then(
|
||||
() => ok(true, "Service initialized correctly"),
|
||||
() => ok(false, "Service shutdown incorrectly"));
|
||||
() => ok(false, "Service shutdown incorrectly")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,12 +117,13 @@ function initPromise(contentBrowser) {
|
|||
* service shuts down correctly.
|
||||
*/
|
||||
function shutdownPromise(contentBrowser) {
|
||||
let a11yShutdownPromise = contentBrowser ?
|
||||
contentA11yInitOrShutdownPromise(contentBrowser) :
|
||||
a11yInitOrShutdownPromise();
|
||||
let a11yShutdownPromise = contentBrowser
|
||||
? contentA11yInitOrShutdownPromise(contentBrowser)
|
||||
: a11yInitOrShutdownPromise();
|
||||
return promiseOK(a11yShutdownPromise, "0").then(
|
||||
() => ok(true, "Service shutdown correctly"),
|
||||
() => ok(false, "Service initialized incorrectly"));
|
||||
() => ok(false, "Service initialized incorrectly")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,12 +141,11 @@ function waitForEvent(eventType, expectedId) {
|
|||
} catch (e) {
|
||||
// This can throw NS_ERROR_FAILURE.
|
||||
}
|
||||
if (event.eventType === eventType &&
|
||||
id === expectedId) {
|
||||
if (event.eventType === eventType && id === expectedId) {
|
||||
Services.obs.removeObserver(this, "accessible-event");
|
||||
resolve(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(eventObserver, "accessible-event");
|
||||
});
|
||||
|
|
|
@ -10,32 +10,47 @@ loadScripts({ name: "layout.js", dir: MOCHITESTS_DIR });
|
|||
async function runTests(browser, accDoc) {
|
||||
loadFrameScripts(browser, { name: "layout.js", dir: MOCHITESTS_DIR });
|
||||
|
||||
let paragraph = findAccessibleChildByID(accDoc, "paragraph", [nsIAccessibleText]);
|
||||
let paragraph = findAccessibleChildByID(accDoc, "paragraph", [
|
||||
nsIAccessibleText,
|
||||
]);
|
||||
let offset = 64; // beginning of 4th stanza
|
||||
|
||||
let [x /* ,y*/] = getPos(paragraph);
|
||||
let [docX, docY] = getPos(accDoc);
|
||||
|
||||
paragraph.scrollSubstringToPoint(offset, offset,
|
||||
COORDTYPE_SCREEN_RELATIVE, docX, docY);
|
||||
paragraph.scrollSubstringToPoint(
|
||||
offset,
|
||||
offset,
|
||||
COORDTYPE_SCREEN_RELATIVE,
|
||||
docX,
|
||||
docY
|
||||
);
|
||||
testTextPos(paragraph, offset, [x, docY], COORDTYPE_SCREEN_RELATIVE);
|
||||
|
||||
await ContentTask.spawn(browser, {}, () => {
|
||||
zoomDocument(content.document, 2.0);
|
||||
});
|
||||
|
||||
paragraph = findAccessibleChildByID(accDoc, "paragraph2", [nsIAccessibleText]);
|
||||
paragraph = findAccessibleChildByID(accDoc, "paragraph2", [
|
||||
nsIAccessibleText,
|
||||
]);
|
||||
offset = 52; // // beginning of 4th stanza
|
||||
[x /* ,y*/] = getPos(paragraph);
|
||||
paragraph.scrollSubstringToPoint(offset, offset,
|
||||
COORDTYPE_SCREEN_RELATIVE, docX, docY);
|
||||
paragraph.scrollSubstringToPoint(
|
||||
offset,
|
||||
offset,
|
||||
COORDTYPE_SCREEN_RELATIVE,
|
||||
docX,
|
||||
docY
|
||||
);
|
||||
testTextPos(paragraph, offset, [x, docY], COORDTYPE_SCREEN_RELATIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test caching of accessible object states
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<br><br><br><br><br><br><br><br><br><br>
|
||||
<br><br><br><br><br><br><br><br><br><br>
|
||||
<br><br><br><br><br><br><br><br><br><br>
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
/* import-globals-from ../shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
|
|
|
@ -79,7 +79,7 @@ let Logger = {
|
|||
if (this.dumpToAppConsole) {
|
||||
Services.console.logStringMessage(`${msg}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -98,7 +98,9 @@ function invokeSetAttribute(browser, id, attr, value) {
|
|||
} else {
|
||||
Logger.log(`Removing ${attr} attribute from node with id: ${id}`);
|
||||
}
|
||||
return ContentTask.spawn(browser, [id, attr, value],
|
||||
return ContentTask.spawn(
|
||||
browser,
|
||||
[id, attr, value],
|
||||
([contentId, contentAttr, contentValue]) => {
|
||||
let elm = content.document.getElementById(contentId);
|
||||
if (contentValue) {
|
||||
|
@ -106,7 +108,8 @@ function invokeSetAttribute(browser, id, attr, value) {
|
|||
} else {
|
||||
elm.removeAttribute(contentAttr);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +128,9 @@ function invokeSetStyle(browser, id, style, value) {
|
|||
} else {
|
||||
Logger.log(`Removing ${style} style from node with id: ${id}`);
|
||||
}
|
||||
return ContentTask.spawn(browser, [id, style, value],
|
||||
return ContentTask.spawn(
|
||||
browser,
|
||||
[id, style, value],
|
||||
([contentId, contentStyle, contentValue]) => {
|
||||
let elm = content.document.getElementById(contentId);
|
||||
if (contentValue) {
|
||||
|
@ -133,7 +138,8 @@ function invokeSetStyle(browser, id, style, value) {
|
|||
} else {
|
||||
delete elm.style[contentStyle];
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,8 +166,10 @@ function invokeFocus(browser, id) {
|
|||
*/
|
||||
function loadScripts(...scripts) {
|
||||
for (let script of scripts) {
|
||||
let path = typeof script === "string" ? `${CURRENT_DIR}${script}` :
|
||||
`${script.dir}${script.name}`;
|
||||
let path =
|
||||
typeof script === "string"
|
||||
? `${CURRENT_DIR}${script}`
|
||||
: `${script.dir}${script.name}`;
|
||||
Services.scriptloader.loadSubScript(path, this);
|
||||
}
|
||||
}
|
||||
|
@ -213,8 +221,9 @@ function loadFrameScripts(browser, ...scripts) {
|
|||
**/
|
||||
function snippetToURL(snippet, bodyAttrs = {}) {
|
||||
let attrs = Object.assign({}, { id: "body" }, bodyAttrs);
|
||||
let attrsString = Object.entries(attrs).map(
|
||||
([attr, value]) => `${attr}=${JSON.stringify(value)}`).join(" ");
|
||||
let attrsString = Object.entries(attrs)
|
||||
.map(([attr, value]) => `${attr}=${JSON.stringify(value)}`)
|
||||
.join(" ");
|
||||
let encodedDoc = encodeURIComponent(
|
||||
`<html>
|
||||
<head>
|
||||
|
@ -222,7 +231,8 @@ function snippetToURL(snippet, bodyAttrs = {}) {
|
|||
<title>Accessibility Test</title>
|
||||
</head>
|
||||
<body ${attrsString}>${snippet}</body>
|
||||
</html>`);
|
||||
</html>`
|
||||
);
|
||||
|
||||
return `data:text/html;charset=utf-8,${encodedDoc}`;
|
||||
}
|
||||
|
@ -246,39 +256,47 @@ function addAccessibleTask(doc, task) {
|
|||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
for (let observer of Services.obs.enumerateObservers("accessible-event")) {
|
||||
for (let observer of Services.obs.enumerateObservers(
|
||||
"accessible-event"
|
||||
)) {
|
||||
Services.obs.removeObserver(observer, "accessible-event");
|
||||
}
|
||||
});
|
||||
|
||||
let onDocLoad = waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, "body");
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url
|
||||
}, async function(browser) {
|
||||
registerCleanupFunction(() => {
|
||||
if (browser) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (tab && !tab.closing && tab.linkedBrowser) {
|
||||
gBrowser.removeTab(tab);
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url,
|
||||
},
|
||||
async function(browser) {
|
||||
registerCleanupFunction(() => {
|
||||
if (browser) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (tab && !tab.closing && tab.linkedBrowser) {
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await SimpleTest.promiseFocus(browser);
|
||||
await SimpleTest.promiseFocus(browser);
|
||||
|
||||
loadFrameScripts(browser,
|
||||
"let { document, window, navigator } = content;",
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR });
|
||||
loadFrameScripts(
|
||||
browser,
|
||||
"let { document, window, navigator } = content;",
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
Logger.log(
|
||||
`e10s enabled: ${Services.appinfo.browserTabsRemoteAutostart}`);
|
||||
Logger.log(`Actually remote browser: ${browser.isRemoteBrowser}`);
|
||||
Logger.log(
|
||||
`e10s enabled: ${Services.appinfo.browserTabsRemoteAutostart}`
|
||||
);
|
||||
Logger.log(`Actually remote browser: ${browser.isRemoteBrowser}`);
|
||||
|
||||
let event = await onDocLoad;
|
||||
await task(browser, event.accessible);
|
||||
});
|
||||
let event = await onDocLoad;
|
||||
await task(browser, event.accessible);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -356,7 +374,8 @@ function queryInterfaces(accessible, interfaces) {
|
|||
|
||||
function arrayFromChildren(accessible) {
|
||||
return Array.from({ length: accessible.childCount }, (c, i) =>
|
||||
accessible.getChildAt(i));
|
||||
accessible.getChildAt(i)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
/* import-globals-from ../../mochitest/states.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR });
|
||||
loadScripts(
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
async function runTests(browser, accDoc) {
|
||||
let getAcc = id => findAccessibleChildByID(accDoc, id);
|
||||
|
@ -18,8 +20,13 @@ async function runTests(browser, accDoc) {
|
|||
let onStateChanged = waitForEvent(EVENT_STATE_CHANGE, "link_traversed");
|
||||
let newWinOpened = BrowserTestUtils.waitForNewWindow();
|
||||
|
||||
await BrowserTestUtils.synthesizeMouse("#link_traversed",
|
||||
1, 1, { shiftKey: true }, browser);
|
||||
await BrowserTestUtils.synthesizeMouse(
|
||||
"#link_traversed",
|
||||
1,
|
||||
1,
|
||||
{ shiftKey: true },
|
||||
browser
|
||||
);
|
||||
|
||||
await onStateChanged;
|
||||
testStates(getAcc("link_traversed"), STATE_TRAVERSED);
|
||||
|
@ -31,8 +38,10 @@ async function runTests(browser, accDoc) {
|
|||
/**
|
||||
* Test caching of accessible object states
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<a id="link_traversed" href="http://www.example.com" target="_top">
|
||||
example.com
|
||||
</a>`, runTests
|
||||
</a>`,
|
||||
runTests
|
||||
);
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
/* import-globals-from ../../mochitest/states.js */
|
||||
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR });
|
||||
loadScripts(
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "states.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
|
||||
async function runTest(browser, accDoc) {
|
||||
let getAcc = id => findAccessibleChildByID(accDoc, id);
|
||||
|
@ -38,11 +40,13 @@ async function runTest(browser, accDoc) {
|
|||
BrowserTestUtils.removeTab(newTab);
|
||||
}
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="div" style="border:2px solid blue; width: 500px; height: 110vh;"></div>
|
||||
<input id="input_scrolledoff">
|
||||
<ul style="border:2px solid red; width: 100px; height: 50px; overflow: auto;">
|
||||
<li id="li_first">item1</li><li>item2</li><li>item3</li>
|
||||
<li>item4</li><li>item5</li><li id="li_last">item6</li>
|
||||
</ul>`, runTest
|
||||
</ul>`,
|
||||
runTest
|
||||
);
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
/* import-globals-from ../shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
|
|
|
@ -8,7 +8,8 @@ let NO_MOVE = { unexpected: [[EVENT_REORDER, "container"]] };
|
|||
let MOVE = { expected: [[EVENT_REORDER, "container"]] };
|
||||
|
||||
// Set last ordinal child as aria-owned, should produce no reorder.
|
||||
addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
|
||||
addAccessibleTask(
|
||||
`<ul id="container"><li id="a">Test</li></ul>`,
|
||||
async function(browser, accDoc) {
|
||||
let containerAcc = findAccessibleChildByID(accDoc, "container");
|
||||
|
||||
|
@ -16,7 +17,9 @@ addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
|
|||
|
||||
await contentSpawnMutation(browser, NO_MOVE, function() {
|
||||
// aria-own ordinal child in place, should be a no-op.
|
||||
content.document.getElementById("container").setAttribute("aria-owns", "a");
|
||||
content.document
|
||||
.getElementById("container")
|
||||
.setAttribute("aria-owns", "a");
|
||||
});
|
||||
|
||||
testChildrenIds(containerAcc, ["a"]);
|
||||
|
@ -25,7 +28,8 @@ addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
|
|||
|
||||
// Add a new ordinal child to a container with an aria-owned child.
|
||||
// Order should respect aria-owns.
|
||||
addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
|
||||
addAccessibleTask(
|
||||
`<ul id="container"><li id="a">Test</li></ul>`,
|
||||
async function(browser, accDoc) {
|
||||
let containerAcc = findAccessibleChildByID(accDoc, "container");
|
||||
|
||||
|
@ -51,7 +55,8 @@ addAccessibleTask(`<ul id="container"><li id="a">Test</li></ul>`,
|
|||
);
|
||||
|
||||
// Remove a no-move aria-owns attribute, should result in a no-move.
|
||||
addAccessibleTask(`<ul id="container" aria-owns="a"><li id="a">Test</li></ul>`,
|
||||
addAccessibleTask(
|
||||
`<ul id="container" aria-owns="a"><li id="a">Test</li></ul>`,
|
||||
async function(browser, accDoc) {
|
||||
let containerAcc = findAccessibleChildByID(accDoc, "container");
|
||||
|
||||
|
@ -67,7 +72,8 @@ addAccessibleTask(`<ul id="container" aria-owns="a"><li id="a">Test</li></ul>`,
|
|||
);
|
||||
|
||||
// Attempt to steal an aria-owned child. The attempt should fail.
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<ul>
|
||||
<li id="a">Test</li>
|
||||
</ul>
|
||||
|
@ -79,7 +85,9 @@ addAccessibleTask(`
|
|||
testChildrenIds(containerAcc, []);
|
||||
|
||||
await contentSpawnMutation(browser, NO_MOVE, function() {
|
||||
content.document.getElementById("container").setAttribute("aria-owns", "a");
|
||||
content.document
|
||||
.getElementById("container")
|
||||
.setAttribute("aria-owns", "a");
|
||||
});
|
||||
|
||||
testChildrenIds(containerAcc, []);
|
||||
|
@ -87,7 +95,8 @@ addAccessibleTask(`
|
|||
);
|
||||
|
||||
// Don't aria-own children of <select>
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="container" role="group" aria-owns="b"></div>
|
||||
<select id="select">
|
||||
<option id="a"></option>
|
||||
|
@ -103,7 +112,8 @@ addAccessibleTask(`
|
|||
);
|
||||
|
||||
// Don't allow <select> to aria-own
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="container" role="group">
|
||||
<div id="a"></div>
|
||||
<div id="b"></div>
|
||||
|
@ -121,7 +131,8 @@ addAccessibleTask(`
|
|||
);
|
||||
|
||||
// Don't allow one <select> to aria-own an <option> from another <select>.
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<select id="select1" aria-owns="c">
|
||||
<option id="a"></option>
|
||||
<option id="b"></option>
|
||||
|
@ -139,7 +150,8 @@ addAccessibleTask(`
|
|||
);
|
||||
|
||||
// Don't allow a <select> to reorder its children with aria-owns.
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<select id="container" aria-owns="c b a">
|
||||
<option id="a"></option>
|
||||
<option id="b"></option>
|
||||
|
@ -151,7 +163,9 @@ addAccessibleTask(`
|
|||
testChildrenIds(containerAcc.firstChild, ["a", "b", "c"]);
|
||||
|
||||
await contentSpawnMutation(browser, NO_MOVE, function() {
|
||||
content.document.getElementById("container").setAttribute("aria-owns", "a c b");
|
||||
content.document
|
||||
.getElementById("container")
|
||||
.setAttribute("aria-owns", "a c b");
|
||||
});
|
||||
|
||||
testChildrenIds(containerAcc.firstChild, ["a", "b", "c"]);
|
||||
|
@ -159,14 +173,16 @@ addAccessibleTask(`
|
|||
);
|
||||
|
||||
// Don't crash if ID in aria-owns does not exist
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<select id="container" aria-owns="boom" multiple></select>`,
|
||||
async function(browser, accDoc) {
|
||||
ok(true, "Did not crash");
|
||||
}
|
||||
);
|
||||
|
||||
addAccessibleTask(`
|
||||
addAccessibleTask(
|
||||
`
|
||||
<ul id="one">
|
||||
<li id="a">Test</li>
|
||||
<li id="b">Test 2</li>
|
||||
|
@ -177,9 +193,9 @@ addAccessibleTask(`
|
|||
let one = findAccessibleChildByID(accDoc, "one");
|
||||
let two = findAccessibleChildByID(accDoc, "two");
|
||||
|
||||
let waitfor = { expected: [
|
||||
[EVENT_REORDER, "one"],
|
||||
[EVENT_REORDER, "two"]] };
|
||||
let waitfor = {
|
||||
expected: [[EVENT_REORDER, "one"], [EVENT_REORDER, "two"]],
|
||||
};
|
||||
|
||||
await contentSpawnMutation(browser, waitfor, function() {
|
||||
// Put same id twice in aria-owns
|
||||
|
@ -200,27 +216,29 @@ addAccessibleTask(`
|
|||
}
|
||||
);
|
||||
|
||||
addAccessibleTask(`<div id="a"></div><div id="b"></div>`,
|
||||
async function(browser, accDoc) {
|
||||
testChildrenIds(accDoc, ["a", "b"]);
|
||||
addAccessibleTask(`<div id="a"></div><div id="b"></div>`, async function(
|
||||
browser,
|
||||
accDoc
|
||||
) {
|
||||
testChildrenIds(accDoc, ["a", "b"]);
|
||||
|
||||
let waitFor = {
|
||||
expected: [[ EVENT_REORDER, e => e.accessible == accDoc ]]
|
||||
};
|
||||
let waitFor = {
|
||||
expected: [[EVENT_REORDER, e => e.accessible == accDoc]],
|
||||
};
|
||||
|
||||
await contentSpawnMutation(browser, waitFor, function() {
|
||||
content.document.documentElement.style.display = "none";
|
||||
content.document.documentElement.getBoundingClientRect();
|
||||
content.document.body.setAttribute("aria-owns", "b a");
|
||||
content.document.documentElement.remove();
|
||||
});
|
||||
await contentSpawnMutation(browser, waitFor, function() {
|
||||
content.document.documentElement.style.display = "none";
|
||||
content.document.documentElement.getBoundingClientRect();
|
||||
content.document.body.setAttribute("aria-owns", "b a");
|
||||
content.document.documentElement.remove();
|
||||
});
|
||||
|
||||
testChildrenIds(accDoc, []);
|
||||
}
|
||||
);
|
||||
testChildrenIds(accDoc, []);
|
||||
});
|
||||
|
||||
// Don't allow ordinal child to be placed after aria-owned child (bug 1405796)
|
||||
addAccessibleTask(`<div id="container"><div id="a">Hello</div></div>
|
||||
addAccessibleTask(
|
||||
`<div id="container"><div id="a">Hello</div></div>
|
||||
<div><div id="c">There</div><div id="d">There</div></div>`,
|
||||
async function(browser, accDoc) {
|
||||
let containerAcc = findAccessibleChildByID(accDoc, "container");
|
||||
|
@ -228,7 +246,9 @@ addAccessibleTask(`<div id="container"><div id="a">Hello</div></div>
|
|||
testChildrenIds(containerAcc, ["a"]);
|
||||
|
||||
await contentSpawnMutation(browser, MOVE, function() {
|
||||
content.document.getElementById("container").setAttribute("aria-owns", "c");
|
||||
content.document
|
||||
.getElementById("container")
|
||||
.setAttribute("aria-owns", "c");
|
||||
});
|
||||
|
||||
testChildrenIds(containerAcc, ["a", "c"]);
|
||||
|
@ -245,7 +265,9 @@ addAccessibleTask(`<div id="container"><div id="a">Hello</div></div>
|
|||
testChildrenIds(containerAcc, ["a", "b", "c"]);
|
||||
|
||||
await contentSpawnMutation(browser, MOVE, function() {
|
||||
content.document.getElementById("container").setAttribute("aria-owns", "c d");
|
||||
content.document
|
||||
.getElementById("container")
|
||||
.setAttribute("aria-owns", "c d");
|
||||
});
|
||||
|
||||
testChildrenIds(containerAcc, ["a", "b", "c", "d"]);
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
/* import-globals-from ../shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this);
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
|
@ -22,6 +23,9 @@ loadScripts({ name: "common.js", dir: MOCHITESTS_DIR }, "events.js");
|
|||
*/
|
||||
function testChildrenIds(acc, expectedIds) {
|
||||
let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
|
||||
Assert.deepEqual(ids, expectedIds,
|
||||
`Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
|
||||
Assert.deepEqual(
|
||||
ids,
|
||||
expectedIds,
|
||||
`Children for ${getAccessibleDOMNodeID(acc)} are wrong.`
|
||||
);
|
||||
}
|
||||
|
|
|
@ -56,33 +56,44 @@ function testActions(aArray) {
|
|||
var actionIndex = actionObj.actionIndex;
|
||||
var actionName = actionObj.actionName;
|
||||
var events = actionObj.events;
|
||||
var accOrElmOrIDOfTarget = actionObj.targetID ?
|
||||
actionObj.targetID : accOrElmOrID;
|
||||
var accOrElmOrIDOfTarget = actionObj.targetID
|
||||
? actionObj.targetID
|
||||
: accOrElmOrID;
|
||||
|
||||
var eventSeq = [];
|
||||
if (events) {
|
||||
var elm = getNode(accOrElmOrIDOfTarget);
|
||||
if (events & MOUSEDOWN_EVENT)
|
||||
if (events & MOUSEDOWN_EVENT) {
|
||||
eventSeq.push(new checkerOfActionInvoker("mousedown", elm, actionObj));
|
||||
}
|
||||
|
||||
if (events & MOUSEUP_EVENT)
|
||||
if (events & MOUSEUP_EVENT) {
|
||||
eventSeq.push(new checkerOfActionInvoker("mouseup", elm, actionObj));
|
||||
}
|
||||
|
||||
if (events & CLICK_EVENT)
|
||||
if (events & CLICK_EVENT) {
|
||||
eventSeq.push(new checkerOfActionInvoker("click", elm, actionObj));
|
||||
}
|
||||
|
||||
if (events & COMMAND_EVENT)
|
||||
if (events & COMMAND_EVENT) {
|
||||
eventSeq.push(new checkerOfActionInvoker("command", elm, actionObj));
|
||||
}
|
||||
|
||||
if (events & FOCUS_EVENT)
|
||||
if (events & FOCUS_EVENT) {
|
||||
eventSeq.push(new focusChecker(elm));
|
||||
}
|
||||
}
|
||||
|
||||
if (actionObj.eventSeq)
|
||||
if (actionObj.eventSeq) {
|
||||
eventSeq = eventSeq.concat(actionObj.eventSeq);
|
||||
}
|
||||
|
||||
var invoker = new actionInvoker(accOrElmOrID, actionIndex, actionName,
|
||||
eventSeq);
|
||||
var invoker = new actionInvoker(
|
||||
accOrElmOrID,
|
||||
actionIndex,
|
||||
actionName,
|
||||
eventSeq
|
||||
);
|
||||
gActionsQueue.push(invoker);
|
||||
}
|
||||
|
||||
|
@ -93,15 +104,21 @@ function testActions(aArray) {
|
|||
* Test action names and descriptions.
|
||||
*/
|
||||
function testActionNames(aID, aActions) {
|
||||
var actions = (typeof aActions == "string") ?
|
||||
[ aActions ] : (aActions || []);
|
||||
var actions = typeof aActions == "string" ? [aActions] : aActions || [];
|
||||
|
||||
var acc = getAccessible(aID);
|
||||
is(acc.actionCount, actions.length, "Wong number of actions.");
|
||||
for (var i = 0; i < actions.length; i++ ) {
|
||||
is(acc.getActionName(i), actions[i], "Wrong action name at " + i + " index.");
|
||||
is(acc.getActionDescription(0), gActionDescrMap[actions[i]],
|
||||
"Wrong action description at " + i + "index.");
|
||||
for (var i = 0; i < actions.length; i++) {
|
||||
is(
|
||||
acc.getActionName(i),
|
||||
actions[i],
|
||||
"Wrong action name at " + i + " index."
|
||||
);
|
||||
is(
|
||||
acc.getActionDescription(0),
|
||||
gActionDescrMap[actions[i]],
|
||||
"Wrong action description at " + i + "index."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,18 +130,25 @@ var gActionsQueue = null;
|
|||
function actionInvoker(aAccOrElmOrId, aActionIndex, aActionName, aEventSeq) {
|
||||
this.invoke = function actionInvoker_invoke() {
|
||||
var acc = getAccessible(aAccOrElmOrId);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return INVOKER_ACTION_FAILED;
|
||||
}
|
||||
|
||||
var isThereActions = acc.actionCount > 0;
|
||||
ok(isThereActions,
|
||||
"No actions on the accessible for " + prettyName(aAccOrElmOrId));
|
||||
ok(
|
||||
isThereActions,
|
||||
"No actions on the accessible for " + prettyName(aAccOrElmOrId)
|
||||
);
|
||||
|
||||
if (!isThereActions)
|
||||
if (!isThereActions) {
|
||||
return INVOKER_ACTION_FAILED;
|
||||
}
|
||||
|
||||
is(acc.getActionName(aActionIndex), aActionName,
|
||||
"Wrong action name of the accessible for " + prettyName(aAccOrElmOrId));
|
||||
is(
|
||||
acc.getActionName(aActionIndex),
|
||||
aActionName,
|
||||
"Wrong action name of the accessible for " + prettyName(aAccOrElmOrId)
|
||||
);
|
||||
|
||||
try {
|
||||
acc.doAction(aActionIndex);
|
||||
|
@ -138,8 +162,14 @@ function actionInvoker(aAccOrElmOrId, aActionIndex, aActionName, aEventSeq) {
|
|||
this.eventSeq = aEventSeq;
|
||||
|
||||
this.getID = function actionInvoker_getID() {
|
||||
return "invoke an action " + aActionName + " at index " + aActionIndex +
|
||||
" on " + prettyName(aAccOrElmOrId);
|
||||
return (
|
||||
"invoke an action " +
|
||||
aActionName +
|
||||
" at index " +
|
||||
aActionIndex +
|
||||
" on " +
|
||||
prettyName(aAccOrElmOrId)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -159,13 +189,13 @@ function checkerOfActionInvoker(aType, aTarget, aActionObj) {
|
|||
};
|
||||
|
||||
this.check = function check(aEvent) {
|
||||
if (aType == "click" && aActionObj && "checkOnClickEvent" in aActionObj)
|
||||
if (aType == "click" && aActionObj && "checkOnClickEvent" in aActionObj) {
|
||||
aActionObj.checkOnClickEvent(aEvent);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var gActionDescrMap =
|
||||
{
|
||||
var gActionDescrMap = {
|
||||
jump: "Jump",
|
||||
press: "Press",
|
||||
check: "Check",
|
||||
|
|
|
@ -34,13 +34,14 @@ function testAbsentAttrs(aAccOrElmOrID, aAbsentAttrs) {
|
|||
*/
|
||||
function todoAttr(aAccOrElmOrID, aKey, aExpectedValue) {
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
if (!accessible)
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
var attrs = null;
|
||||
try {
|
||||
attrs = accessible.attributes;
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
|
||||
todo_is(attrs.getStringProperty(aKey), aExpectedValue, "attributes match");
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ function testCSSAttrs(aID) {
|
|||
var computedStyle = document.defaultView.getComputedStyle(node);
|
||||
|
||||
var attrs = {
|
||||
"display": computedStyle.display,
|
||||
display: computedStyle.display,
|
||||
"text-align": computedStyle.textAlign,
|
||||
"text-indent": computedStyle.textIndent,
|
||||
"margin-left": computedStyle.marginLeft,
|
||||
|
@ -69,7 +70,7 @@ function testCSSAttrs(aID) {
|
|||
*/
|
||||
function testAbsentCSSAttrs(aID) {
|
||||
var attrs = {
|
||||
"display": "",
|
||||
display: "",
|
||||
"text-align": "",
|
||||
"text-indent": "",
|
||||
"margin-left": "",
|
||||
|
@ -91,38 +92,53 @@ function testAbsentCSSAttrs(aID) {
|
|||
*/
|
||||
function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel) {
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
var levelObj = {}, posInSetObj = {}, setSizeObj = {};
|
||||
var levelObj = {},
|
||||
posInSetObj = {},
|
||||
setSizeObj = {};
|
||||
acc.groupPosition(levelObj, setSizeObj, posInSetObj);
|
||||
|
||||
if (aPosInSet && aSetSize) {
|
||||
is(posInSetObj.value, aPosInSet,
|
||||
"Wrong group position (posinset) for " + prettyName(aAccOrElmOrID));
|
||||
is(setSizeObj.value, aSetSize,
|
||||
"Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID));
|
||||
is(
|
||||
posInSetObj.value,
|
||||
aPosInSet,
|
||||
"Wrong group position (posinset) for " + prettyName(aAccOrElmOrID)
|
||||
);
|
||||
is(
|
||||
setSizeObj.value,
|
||||
aSetSize,
|
||||
"Wrong size of the group (setsize) for " + prettyName(aAccOrElmOrID)
|
||||
);
|
||||
|
||||
let attrs = {
|
||||
"posinset": String(aPosInSet),
|
||||
"setsize": String(aSetSize),
|
||||
posinset: String(aPosInSet),
|
||||
setsize: String(aSetSize),
|
||||
};
|
||||
testAttrs(aAccOrElmOrID, attrs, true);
|
||||
}
|
||||
|
||||
if (aLevel) {
|
||||
is(levelObj.value, aLevel,
|
||||
"Wrong group level for " + prettyName(aAccOrElmOrID));
|
||||
is(
|
||||
levelObj.value,
|
||||
aLevel,
|
||||
"Wrong group level for " + prettyName(aAccOrElmOrID)
|
||||
);
|
||||
|
||||
let attrs = { "level": String(aLevel) };
|
||||
let attrs = { level: String(aLevel) };
|
||||
testAttrs(aAccOrElmOrID, attrs, true);
|
||||
}
|
||||
}
|
||||
|
||||
function testGroupParentAttrs(aAccOrElmOrID, aChildItemCount, aIsHierarchical) {
|
||||
testAttrs(aAccOrElmOrID, { "child-item-count": String(aChildItemCount) }, true);
|
||||
testAttrs(
|
||||
aAccOrElmOrID,
|
||||
{ "child-item-count": String(aChildItemCount) },
|
||||
true
|
||||
);
|
||||
|
||||
if (aIsHierarchical) {
|
||||
testAttrs(aAccOrElmOrID, { "hierarchical": "true" }, true);
|
||||
testAttrs(aAccOrElmOrID, { hierarchical: "true" }, true);
|
||||
} else {
|
||||
testAbsentAttrs(aAccOrElmOrID, { "hierarchical": "true" });
|
||||
testAbsentAttrs(aAccOrElmOrID, { hierarchical: "true" });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,21 +164,36 @@ function testGroupParentAttrs(aAccOrElmOrID, aChildItemCount, aIsHierarchical) {
|
|||
* @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
|
||||
* unexpected attribute is encountered
|
||||
*/
|
||||
function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
|
||||
aStartOffset, aEndOffset, aSkipUnexpectedAttrs) {
|
||||
function testTextAttrs(
|
||||
aID,
|
||||
aOffset,
|
||||
aAttrs,
|
||||
aDefAttrs,
|
||||
aStartOffset,
|
||||
aEndOffset,
|
||||
aSkipUnexpectedAttrs
|
||||
) {
|
||||
var accessible = getAccessible(aID, [nsIAccessibleText]);
|
||||
if (!accessible)
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
var startOffset = { value: -1 };
|
||||
var endOffset = { value: -1 };
|
||||
|
||||
// do not include attributes exposed on hyper text accessible
|
||||
var attrs = getTextAttributes(aID, accessible, false, aOffset,
|
||||
startOffset, endOffset);
|
||||
var attrs = getTextAttributes(
|
||||
aID,
|
||||
accessible,
|
||||
false,
|
||||
aOffset,
|
||||
startOffset,
|
||||
endOffset
|
||||
);
|
||||
|
||||
if (!attrs)
|
||||
if (!attrs) {
|
||||
return;
|
||||
}
|
||||
|
||||
var errorMsg = " for " + aID + " at offset " + aOffset;
|
||||
|
||||
|
@ -173,19 +204,28 @@ function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
|
|||
|
||||
// include attributes exposed on hyper text accessible
|
||||
var expectedAttrs = {};
|
||||
for (let name in aAttrs)
|
||||
for (let name in aAttrs) {
|
||||
expectedAttrs[name] = aAttrs[name];
|
||||
|
||||
for (let name in aDefAttrs) {
|
||||
if (!(name in expectedAttrs))
|
||||
expectedAttrs[name] = aDefAttrs[name];
|
||||
}
|
||||
|
||||
attrs = getTextAttributes(aID, accessible, true, aOffset,
|
||||
startOffset, endOffset);
|
||||
for (let name in aDefAttrs) {
|
||||
if (!(name in expectedAttrs)) {
|
||||
expectedAttrs[name] = aDefAttrs[name];
|
||||
}
|
||||
}
|
||||
|
||||
if (!attrs)
|
||||
attrs = getTextAttributes(
|
||||
aID,
|
||||
accessible,
|
||||
true,
|
||||
aOffset,
|
||||
startOffset,
|
||||
endOffset
|
||||
);
|
||||
|
||||
if (!attrs) {
|
||||
return;
|
||||
}
|
||||
|
||||
compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs);
|
||||
}
|
||||
|
@ -202,14 +242,14 @@ function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
|
|||
*/
|
||||
function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs) {
|
||||
var accessible = getAccessible(aID, [nsIAccessibleText]);
|
||||
if (!accessible)
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
var defAttrs = null;
|
||||
try {
|
||||
defAttrs = accessible.defaultTextAttributes;
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (!defAttrs) {
|
||||
ok(false, "Can't get default text attributes for " + aID);
|
||||
|
@ -226,38 +266,56 @@ function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs) {
|
|||
function testTextAttrsWrongOffset(aID, aOffset) {
|
||||
var res = false;
|
||||
try {
|
||||
var s = {}, e = {};
|
||||
var acc = getAccessible(ID, [nsIAccessibleText]);
|
||||
var s = {},
|
||||
e = {};
|
||||
var acc = getAccessible(ID, [nsIAccessibleText]);
|
||||
acc.getTextAttributes(false, 157, s, e);
|
||||
} catch (ex) {
|
||||
res = true;
|
||||
}
|
||||
|
||||
ok(res,
|
||||
"text attributes are calculated successfully at wrong offset " + aOffset + " for " + prettyName(aID));
|
||||
ok(
|
||||
res,
|
||||
"text attributes are calculated successfully at wrong offset " +
|
||||
aOffset +
|
||||
" for " +
|
||||
prettyName(aID)
|
||||
);
|
||||
}
|
||||
|
||||
const kNormalFontWeight =
|
||||
function equalsToNormal(aWeight) { return aWeight <= 400 ; };
|
||||
const kNormalFontWeight = function equalsToNormal(aWeight) {
|
||||
return aWeight <= 400;
|
||||
};
|
||||
|
||||
const kBoldFontWeight =
|
||||
function equalsToBold(aWeight) { return aWeight > 400; };
|
||||
const kBoldFontWeight = function equalsToBold(aWeight) {
|
||||
return aWeight > 400;
|
||||
};
|
||||
|
||||
// The pt font size of the input element can vary by Linux distro.
|
||||
const kInputFontSize = WIN ?
|
||||
"10pt" : (MAC ? "8pt" : function() { return true; });
|
||||
const kInputFontSize = WIN
|
||||
? "10pt"
|
||||
: MAC
|
||||
? "8pt"
|
||||
: function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
const kAbsentFontFamily =
|
||||
function(aFontFamily) { return aFontFamily != "sans-serif"; };
|
||||
const kInputFontFamily =
|
||||
function(aFontFamily) { return aFontFamily != "sans-serif"; };
|
||||
const kAbsentFontFamily = function(aFontFamily) {
|
||||
return aFontFamily != "sans-serif";
|
||||
};
|
||||
const kInputFontFamily = function(aFontFamily) {
|
||||
return aFontFamily != "sans-serif";
|
||||
};
|
||||
|
||||
const kMonospaceFontFamily =
|
||||
function(aFontFamily) { return aFontFamily != "monospace"; };
|
||||
const kSansSerifFontFamily =
|
||||
function(aFontFamily) { return aFontFamily != "sans-serif"; };
|
||||
const kSerifFontFamily =
|
||||
function(aFontFamily) { return aFontFamily != "serif"; };
|
||||
const kMonospaceFontFamily = function(aFontFamily) {
|
||||
return aFontFamily != "monospace";
|
||||
};
|
||||
const kSansSerifFontFamily = function(aFontFamily) {
|
||||
return aFontFamily != "sans-serif";
|
||||
};
|
||||
const kSerifFontFamily = function(aFontFamily) {
|
||||
return aFontFamily != "serif";
|
||||
};
|
||||
|
||||
const kCursiveFontFamily = LINUX ? "DejaVu Serif" : "Comic Sans MS";
|
||||
|
||||
|
@ -289,15 +347,17 @@ function fontFamily(aComputedStyle) {
|
|||
function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily) {
|
||||
var elm = getNode(aID);
|
||||
var computedStyle = document.defaultView.getComputedStyle(elm);
|
||||
var bgColor = computedStyle.backgroundColor == "rgba(0, 0, 0, 0)" ?
|
||||
"rgb(255, 255, 255)" : computedStyle.backgroundColor;
|
||||
var bgColor =
|
||||
computedStyle.backgroundColor == "rgba(0, 0, 0, 0)"
|
||||
? "rgb(255, 255, 255)"
|
||||
: computedStyle.backgroundColor;
|
||||
|
||||
var defAttrs = {
|
||||
"font-style": computedStyle.fontStyle,
|
||||
"font-size": aFontSize,
|
||||
"background-color": bgColor,
|
||||
"font-weight": aFontWeight ? aFontWeight : kNormalFontWeight,
|
||||
"color": computedStyle.color,
|
||||
color: computedStyle.color,
|
||||
"font-family": aFontFamily ? aFontFamily : fontFamily(computedStyle),
|
||||
"text-position": computedStyle.verticalAlign,
|
||||
};
|
||||
|
@ -308,34 +368,49 @@ function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily) {
|
|||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// Private.
|
||||
|
||||
function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset,
|
||||
aStartOffset, aEndOffset) {
|
||||
function getTextAttributes(
|
||||
aID,
|
||||
aAccessible,
|
||||
aIncludeDefAttrs,
|
||||
aOffset,
|
||||
aStartOffset,
|
||||
aEndOffset
|
||||
) {
|
||||
// This function expects the passed in accessible to already be queried for
|
||||
// nsIAccessibleText.
|
||||
var attrs = null;
|
||||
try {
|
||||
attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset,
|
||||
aStartOffset, aEndOffset);
|
||||
} catch (e) {
|
||||
}
|
||||
attrs = aAccessible.getTextAttributes(
|
||||
aIncludeDefAttrs,
|
||||
aOffset,
|
||||
aStartOffset,
|
||||
aEndOffset
|
||||
);
|
||||
} catch (e) {}
|
||||
|
||||
if (attrs)
|
||||
if (attrs) {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
ok(false, "Can't get text attributes for " + aID);
|
||||
return null;
|
||||
}
|
||||
|
||||
function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs,
|
||||
aAbsentAttrs) {
|
||||
function testAttrsInternal(
|
||||
aAccOrElmOrID,
|
||||
aAttrs,
|
||||
aSkipUnexpectedAttrs,
|
||||
aAbsentAttrs
|
||||
) {
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
if (!accessible)
|
||||
if (!accessible) {
|
||||
return;
|
||||
}
|
||||
|
||||
var attrs = null;
|
||||
try {
|
||||
attrs = accessible.attributes;
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
|
||||
if (!attrs) {
|
||||
ok(false, "Can't get object attributes for " + prettyName(aAccOrElmOrID));
|
||||
|
@ -346,22 +421,36 @@ function testAttrsInternal(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs,
|
|||
compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs, aAbsentAttrs);
|
||||
}
|
||||
|
||||
function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
|
||||
aAbsentAttrs) {
|
||||
function compareAttrs(
|
||||
aErrorMsg,
|
||||
aAttrs,
|
||||
aExpectedAttrs,
|
||||
aSkipUnexpectedAttrs,
|
||||
aAbsentAttrs
|
||||
) {
|
||||
// Check if all obtained attributes are expected and have expected value.
|
||||
for (let prop of aAttrs.enumerate()) {
|
||||
if (!(prop.key in aExpectedAttrs)) {
|
||||
if (!aSkipUnexpectedAttrs)
|
||||
ok(false, "Unexpected attribute '" + prop.key + "' having '" +
|
||||
prop.value + "'" + aErrorMsg);
|
||||
if (!aSkipUnexpectedAttrs) {
|
||||
ok(
|
||||
false,
|
||||
"Unexpected attribute '" +
|
||||
prop.key +
|
||||
"' having '" +
|
||||
prop.value +
|
||||
"'" +
|
||||
aErrorMsg
|
||||
);
|
||||
}
|
||||
} else {
|
||||
var msg = "Attribute '" + prop.key + "' has wrong value" + aErrorMsg;
|
||||
var expectedValue = aExpectedAttrs[prop.key];
|
||||
|
||||
if (typeof expectedValue == "function")
|
||||
if (typeof expectedValue == "function") {
|
||||
ok(expectedValue(prop.value), msg);
|
||||
else
|
||||
} else {
|
||||
is(prop.value, expectedValue, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,11 +459,11 @@ function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
|
|||
var value = "";
|
||||
try {
|
||||
value = aAttrs.getStringProperty(name);
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
|
||||
if (!value)
|
||||
ok(false,
|
||||
"There is no expected attribute '" + name + "' " + aErrorMsg);
|
||||
if (!value) {
|
||||
ok(false, "There is no expected attribute '" + name + "' " + aErrorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all unexpected attributes are absent.
|
||||
|
@ -383,12 +472,15 @@ function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs,
|
|||
var wasFound = false;
|
||||
|
||||
for (let prop of aAttrs.enumerate()) {
|
||||
if (prop.key == name)
|
||||
if (prop.key == name) {
|
||||
wasFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok(!wasFound,
|
||||
"There is an unexpected attribute '" + name + "' " + aErrorMsg);
|
||||
ok(
|
||||
!wasFound,
|
||||
"There is an unexpected attribute '" + name + "' " + aErrorMsg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
const nsISupports = Ci.nsISupports;
|
||||
const nsIAutoCompleteResult = Ci.nsIAutoCompleteResult;
|
||||
const nsIAutoCompleteSearch = Ci.nsIAutoCompleteSearch;
|
||||
|
@ -16,10 +15,14 @@ var gDefaultAutoCompleteSearch = null;
|
|||
*/
|
||||
function initAutoComplete(aValues, aComments) {
|
||||
var allResults = new ResultsHeap(aValues, aComments);
|
||||
gDefaultAutoCompleteSearch =
|
||||
new AutoCompleteSearch("test-a11y-search", allResults);
|
||||
registerAutoCompleteSearch(gDefaultAutoCompleteSearch,
|
||||
"Accessibility Test AutoCompleteSearch");
|
||||
gDefaultAutoCompleteSearch = new AutoCompleteSearch(
|
||||
"test-a11y-search",
|
||||
allResults
|
||||
);
|
||||
registerAutoCompleteSearch(
|
||||
gDefaultAutoCompleteSearch,
|
||||
"Accessibility Test AutoCompleteSearch"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,7 +34,6 @@ function shutdownAutoComplete() {
|
|||
gDefaultAutoCompleteSearch = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the given AutoCompleteSearch.
|
||||
*
|
||||
|
@ -41,11 +43,14 @@ function shutdownAutoComplete() {
|
|||
function registerAutoCompleteSearch(aSearch, aDescription) {
|
||||
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
|
||||
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(nsIUUIDGenerator);
|
||||
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
nsIUUIDGenerator
|
||||
);
|
||||
var cid = uuidGenerator.generateUUID();
|
||||
|
||||
var componentManager = Components.manager.QueryInterface(nsIComponentRegistrar);
|
||||
var componentManager = Components.manager.QueryInterface(
|
||||
nsIComponentRegistrar
|
||||
);
|
||||
componentManager.registerFactory(cid, aDescription, name, aSearch);
|
||||
|
||||
// Keep the id on the object so we can unregister later.
|
||||
|
@ -56,11 +61,12 @@ function registerAutoCompleteSearch(aSearch, aDescription) {
|
|||
* Unregister the given AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
var componentManager = Components.manager.QueryInterface(nsIComponentRegistrar);
|
||||
var componentManager = Components.manager.QueryInterface(
|
||||
nsIComponentRegistrar
|
||||
);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A container to keep all possible results of autocomplete search.
|
||||
*/
|
||||
|
@ -69,15 +75,15 @@ function ResultsHeap(aValues, aComments) {
|
|||
this.comments = aComments;
|
||||
}
|
||||
|
||||
ResultsHeap.prototype =
|
||||
{
|
||||
ResultsHeap.prototype = {
|
||||
constructor: ResultsHeap,
|
||||
|
||||
/**
|
||||
* Return AutoCompleteResult for the given search string.
|
||||
*/
|
||||
getAutoCompleteResultFor(aSearchString) {
|
||||
var values = [], comments = [];
|
||||
var values = [],
|
||||
comments = [];
|
||||
for (var idx = 0; idx < this.values.length; idx++) {
|
||||
if (this.values[idx].includes(aSearchString)) {
|
||||
values.push(this.values[idx]);
|
||||
|
@ -88,7 +94,6 @@ ResultsHeap.prototype =
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation.
|
||||
*
|
||||
|
@ -100,8 +105,7 @@ function AutoCompleteSearch(aName, aAllResults) {
|
|||
this.allResults = aAllResults;
|
||||
}
|
||||
|
||||
AutoCompleteSearch.prototype =
|
||||
{
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
|
||||
// nsIAutoCompleteSearch implementation
|
||||
|
@ -113,7 +117,10 @@ AutoCompleteSearch.prototype =
|
|||
stopSearch() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
"nsIFactory",
|
||||
"nsIAutoCompleteSearch",
|
||||
]),
|
||||
|
||||
// nsIFactory implementation
|
||||
createInstance(outer, iid) {
|
||||
|
@ -127,7 +134,6 @@ AutoCompleteSearch.prototype =
|
|||
allResults: null,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteResult implementation.
|
||||
*/
|
||||
|
@ -135,14 +141,14 @@ function AutoCompleteResult(aValues, aComments) {
|
|||
this.values = aValues;
|
||||
this.comments = aComments;
|
||||
|
||||
if (this.values.length > 0)
|
||||
if (this.values.length > 0) {
|
||||
this.searchResult = nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
else
|
||||
} else {
|
||||
this.searchResult = nsIAutoCompleteResult.NOMATCH;
|
||||
}
|
||||
}
|
||||
|
||||
AutoCompleteResult.prototype =
|
||||
{
|
||||
AutoCompleteResult.prototype = {
|
||||
constructor: AutoCompleteResult,
|
||||
|
||||
searchString: "",
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
var {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
var { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* Load the browser with the given url and then invokes the given function.
|
||||
|
@ -91,10 +93,9 @@ function reloadButton() {
|
|||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// private section
|
||||
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var gBrowserContext =
|
||||
{
|
||||
var gBrowserContext = {
|
||||
browserWnd: null,
|
||||
testFunc: null,
|
||||
startURL: "",
|
||||
|
@ -104,20 +105,26 @@ function openBrowserWindowIntl() {
|
|||
var params = "chrome,all,dialog=no,non-remote";
|
||||
var rect = gBrowserContext.browserRect;
|
||||
if (rect) {
|
||||
if ("left" in rect)
|
||||
if ("left" in rect) {
|
||||
params += ",left=" + rect.left;
|
||||
if ("top" in rect)
|
||||
}
|
||||
if ("top" in rect) {
|
||||
params += ",top=" + rect.top;
|
||||
if ("width" in rect)
|
||||
}
|
||||
if ("width" in rect) {
|
||||
params += ",width=" + rect.width;
|
||||
if ("height" in rect)
|
||||
}
|
||||
if ("height" in rect) {
|
||||
params += ",height=" + rect.height;
|
||||
}
|
||||
}
|
||||
|
||||
gBrowserContext.browserWnd =
|
||||
window.openDialog(AppConstants.BROWSER_CHROME_URL,
|
||||
"_blank", params,
|
||||
gBrowserContext.startURL || "data:text/html,<html></html>");
|
||||
gBrowserContext.browserWnd = window.openDialog(
|
||||
AppConstants.BROWSER_CHROME_URL,
|
||||
"_blank",
|
||||
params,
|
||||
gBrowserContext.startURL || "data:text/html,<html></html>"
|
||||
);
|
||||
|
||||
whenDelayedStartupFinished(browserWindow(), function() {
|
||||
addA11yLoadEvent(startBrowserTests, browserWindow());
|
||||
|
@ -125,10 +132,12 @@ function openBrowserWindowIntl() {
|
|||
}
|
||||
|
||||
function startBrowserTests() {
|
||||
if (gBrowserContext.startURL) // wait for load
|
||||
if (gBrowserContext.startURL) {
|
||||
// wait for load
|
||||
addA11yLoadEvent(gBrowserContext.testFunc, currentBrowser().contentWindow);
|
||||
else
|
||||
} else {
|
||||
gBrowserContext.testFunc();
|
||||
}
|
||||
}
|
||||
|
||||
function whenDelayedStartupFinished(aWindow, aCallback) {
|
||||
|
|
|
@ -4,20 +4,15 @@
|
|||
const nsIAccessibilityService = Ci.nsIAccessibilityService;
|
||||
|
||||
const nsIAccessibleEvent = Ci.nsIAccessibleEvent;
|
||||
const nsIAccessibleStateChangeEvent =
|
||||
Ci.nsIAccessibleStateChangeEvent;
|
||||
const nsIAccessibleCaretMoveEvent =
|
||||
Ci.nsIAccessibleCaretMoveEvent;
|
||||
const nsIAccessibleScrollingEvent =
|
||||
Ci.nsIAccessibleScrollingEvent;
|
||||
const nsIAccessibleTextChangeEvent =
|
||||
Ci.nsIAccessibleTextChangeEvent;
|
||||
const nsIAccessibleStateChangeEvent = Ci.nsIAccessibleStateChangeEvent;
|
||||
const nsIAccessibleCaretMoveEvent = Ci.nsIAccessibleCaretMoveEvent;
|
||||
const nsIAccessibleScrollingEvent = Ci.nsIAccessibleScrollingEvent;
|
||||
const nsIAccessibleTextChangeEvent = Ci.nsIAccessibleTextChangeEvent;
|
||||
const nsIAccessibleVirtualCursorChangeEvent =
|
||||
Ci.nsIAccessibleVirtualCursorChangeEvent;
|
||||
const nsIAccessibleObjectAttributeChangedEvent =
|
||||
Ci.nsIAccessibleObjectAttributeChangedEvent;
|
||||
const nsIAccessibleAnnouncementEvent =
|
||||
Ci.nsIAccessibleAnnouncementEvent;
|
||||
const nsIAccessibleAnnouncementEvent = Ci.nsIAccessibleAnnouncementEvent;
|
||||
|
||||
const nsIAccessibleStates = Ci.nsIAccessibleStates;
|
||||
const nsIAccessibleRole = Ci.nsIAccessibleRole;
|
||||
|
@ -55,10 +50,10 @@ const nsIPropertyElement = Ci.nsIPropertyElement;
|
|||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// OS detect
|
||||
|
||||
const MAC = (navigator.platform.includes("Mac"));
|
||||
const LINUX = (navigator.platform.includes("Linux"));
|
||||
const SOLARIS = (navigator.platform.includes("SunOS"));
|
||||
const WIN = (navigator.platform.includes("Win"));
|
||||
const MAC = navigator.platform.includes("Mac");
|
||||
const LINUX = navigator.platform.includes("Linux");
|
||||
const SOLARIS = navigator.platform.includes("SunOS");
|
||||
const WIN = navigator.platform.includes("Win");
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// Application detect
|
||||
|
@ -73,9 +68,12 @@ const STATE_BUSY = nsIAccessibleStates.STATE_BUSY;
|
|||
|
||||
const SCROLL_TYPE_ANYWHERE = nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE;
|
||||
|
||||
const COORDTYPE_SCREEN_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE;
|
||||
const COORDTYPE_WINDOW_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE;
|
||||
const COORDTYPE_PARENT_RELATIVE = nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE;
|
||||
const COORDTYPE_SCREEN_RELATIVE =
|
||||
nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE;
|
||||
const COORDTYPE_WINDOW_RELATIVE =
|
||||
nsIAccessibleCoordinateType.COORDTYPE_WINDOW_RELATIVE;
|
||||
const COORDTYPE_PARENT_RELATIVE =
|
||||
nsIAccessibleCoordinateType.COORDTYPE_PARENT_RELATIVE;
|
||||
|
||||
const kEmbedChar = String.fromCharCode(0xfffc);
|
||||
|
||||
|
@ -89,13 +87,14 @@ const MAX_TRIM_LENGTH = 100;
|
|||
/**
|
||||
* Services to determine if e10s is enabled.
|
||||
*/
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* nsIAccessibilityService service.
|
||||
*/
|
||||
var gAccService = Cc["@mozilla.org/accessibilityService;1"].
|
||||
getService(nsIAccessibilityService);
|
||||
var gAccService = Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
nsIAccessibilityService
|
||||
);
|
||||
|
||||
/**
|
||||
* Enable/disable logging.
|
||||
|
@ -151,26 +150,25 @@ function dumpTree(aId, aMsg) {
|
|||
*/
|
||||
function addA11yLoadEvent(aFunc, aWindow) {
|
||||
function waitForDocLoad() {
|
||||
window.setTimeout(
|
||||
function() {
|
||||
var targetDocument = aWindow ? aWindow.document : document;
|
||||
var accDoc = getAccessible(targetDocument);
|
||||
var state = {};
|
||||
accDoc.getState(state, {});
|
||||
if (state.value & STATE_BUSY) {
|
||||
waitForDocLoad();
|
||||
return;
|
||||
}
|
||||
window.setTimeout(function() {
|
||||
var targetDocument = aWindow ? aWindow.document : document;
|
||||
var accDoc = getAccessible(targetDocument);
|
||||
var state = {};
|
||||
accDoc.getState(state, {});
|
||||
if (state.value & STATE_BUSY) {
|
||||
waitForDocLoad();
|
||||
return;
|
||||
}
|
||||
|
||||
window.setTimeout(aFunc, 0);
|
||||
},
|
||||
0
|
||||
);
|
||||
window.setTimeout(aFunc, 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
if (aWindow &&
|
||||
aWindow.document.activeElement &&
|
||||
aWindow.document.activeElement.localName == "browser") {
|
||||
if (
|
||||
aWindow &&
|
||||
aWindow.document.activeElement &&
|
||||
aWindow.document.activeElement.localName == "browser"
|
||||
) {
|
||||
waitForDocLoad();
|
||||
} else {
|
||||
SimpleTest.waitForFocus(waitForDocLoad, aWindow);
|
||||
|
@ -186,9 +184,15 @@ function isObject(aObj, aExpectedObj, aMsg) {
|
|||
return;
|
||||
}
|
||||
|
||||
ok(false,
|
||||
aMsg + " - got '" + prettyName(aObj) +
|
||||
"', expected '" + prettyName(aExpectedObj) + "'");
|
||||
ok(
|
||||
false,
|
||||
aMsg +
|
||||
" - got '" +
|
||||
prettyName(aObj) +
|
||||
"', expected '" +
|
||||
prettyName(aExpectedObj) +
|
||||
"'"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,8 +202,10 @@ function isWithin(aExpected, aGot, aWithin, aMsg) {
|
|||
if (Math.abs(aGot - aExpected) <= aWithin) {
|
||||
ok(true, `${aMsg} - Got ${aGot}`);
|
||||
} else {
|
||||
ok(false,
|
||||
`${aMsg} - Got ${aGot}, expected ${aExpected} with error of ${aWithin}`);
|
||||
ok(
|
||||
false,
|
||||
`${aMsg} - Got ${aGot}, expected ${aExpected} with error of ${aWithin}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,14 +216,17 @@ function isWithin(aExpected, aGot, aWithin, aMsg) {
|
|||
* Return the DOM node by identifier (may be accessible, DOM node or ID).
|
||||
*/
|
||||
function getNode(aAccOrNodeOrID, aDocument) {
|
||||
if (!aAccOrNodeOrID)
|
||||
if (!aAccOrNodeOrID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Node.isInstance(aAccOrNodeOrID))
|
||||
if (Node.isInstance(aAccOrNodeOrID)) {
|
||||
return aAccOrNodeOrID;
|
||||
}
|
||||
|
||||
if (aAccOrNodeOrID instanceof nsIAccessible)
|
||||
if (aAccOrNodeOrID instanceof nsIAccessible) {
|
||||
return aAccOrNodeOrID.DOMNode;
|
||||
}
|
||||
|
||||
var node = (aDocument || document).getElementById(aAccOrNodeOrID);
|
||||
if (!node) {
|
||||
|
@ -253,13 +262,16 @@ const DONOTFAIL_IF_NO_INTERFACE = 2;
|
|||
* constants above)
|
||||
*/
|
||||
function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
|
||||
if (!aAccOrElmOrID)
|
||||
if (!aAccOrElmOrID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var elm = null;
|
||||
|
||||
if (aAccOrElmOrID instanceof nsIAccessible) {
|
||||
try { elm = aAccOrElmOrID.DOMNode; } catch (e) { }
|
||||
try {
|
||||
elm = aAccOrElmOrID.DOMNode;
|
||||
} catch (e) {}
|
||||
} else if (Node.isInstance(aAccOrElmOrID)) {
|
||||
elm = aAccOrElmOrID;
|
||||
} else {
|
||||
|
@ -270,29 +282,32 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
|
|||
}
|
||||
}
|
||||
|
||||
if (aElmObj && (typeof aElmObj == "object"))
|
||||
if (aElmObj && typeof aElmObj == "object") {
|
||||
aElmObj.value = elm;
|
||||
}
|
||||
|
||||
var acc = (aAccOrElmOrID instanceof nsIAccessible) ? aAccOrElmOrID : null;
|
||||
var acc = aAccOrElmOrID instanceof nsIAccessible ? aAccOrElmOrID : null;
|
||||
if (!acc) {
|
||||
try {
|
||||
acc = gAccService.getAccessibleFor(elm);
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
if (!acc) {
|
||||
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC))
|
||||
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC)) {
|
||||
ok(false, "Can't get accessible for " + prettyName(aAccOrElmOrID));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aInterfaces)
|
||||
if (!aInterfaces) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (!(aInterfaces instanceof Array))
|
||||
aInterfaces = [ aInterfaces ];
|
||||
if (!(aInterfaces instanceof Array)) {
|
||||
aInterfaces = [aInterfaces];
|
||||
}
|
||||
|
||||
for (var index = 0; index < aInterfaces.length; index++) {
|
||||
if (acc instanceof aInterfaces[index]) {
|
||||
|
@ -301,8 +316,12 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
|
|||
try {
|
||||
acc.QueryInterface(aInterfaces[index]);
|
||||
} catch (e) {
|
||||
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE))
|
||||
ok(false, "Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID);
|
||||
if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE)) {
|
||||
ok(
|
||||
false,
|
||||
"Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -316,8 +335,12 @@ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) {
|
|||
* interfaces.
|
||||
*/
|
||||
function isAccessible(aAccOrElmOrID, aInterfaces) {
|
||||
return !!getAccessible(aAccOrElmOrID, aInterfaces, null,
|
||||
DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE);
|
||||
return !!getAccessible(
|
||||
aAccOrElmOrID,
|
||||
aInterfaces,
|
||||
null,
|
||||
DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -325,10 +348,11 @@ function isAccessible(aAccOrElmOrID, aInterfaces) {
|
|||
*/
|
||||
function getContainerAccessible(aAccOrElmOrID) {
|
||||
var node = getNode(aAccOrElmOrID);
|
||||
if (!node)
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while ((node = node.parentNode) && !isAccessible(node));
|
||||
while ((node = node.parentNode) && !isAccessible(node)) {}
|
||||
return node ? getAccessible(node) : null;
|
||||
}
|
||||
|
||||
|
@ -350,8 +374,9 @@ function getTabDocAccessible(aAccOrElmOrID) {
|
|||
var containerDocAcc = docAcc.parent.document;
|
||||
|
||||
// Test is running is stand-alone mode.
|
||||
if (acc.rootDocument == containerDocAcc)
|
||||
if (acc.rootDocument == containerDocAcc) {
|
||||
return docAcc;
|
||||
}
|
||||
|
||||
// In the case of running all tests together.
|
||||
return containerDocAcc.QueryInterface(nsIAccessible);
|
||||
|
@ -361,8 +386,9 @@ function getTabDocAccessible(aAccOrElmOrID) {
|
|||
* Return application accessible.
|
||||
*/
|
||||
function getApplicationAccessible() {
|
||||
return gAccService.getApplicationAccessible().
|
||||
QueryInterface(nsIAccessibleApplication);
|
||||
return gAccService
|
||||
.getApplicationAccessible()
|
||||
.QueryInterface(nsIAccessibleApplication);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -393,8 +419,9 @@ const kSkipTreeFullCheck = 1;
|
|||
// eslint-disable-next-line complexity
|
||||
function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var accTree = aAccTree;
|
||||
|
||||
|
@ -403,80 +430,106 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
|
|||
|
||||
// Test accessible properties.
|
||||
for (var prop in accTree) {
|
||||
var msg = "Wrong value of property '" + prop + "' for " +
|
||||
prettyName(acc) + ".";
|
||||
var msg =
|
||||
"Wrong value of property '" + prop + "' for " + prettyName(acc) + ".";
|
||||
|
||||
switch (prop) {
|
||||
case "actions": {
|
||||
testActionNames(acc, accTree.actions);
|
||||
break;
|
||||
}
|
||||
|
||||
case "attributes":
|
||||
testAttrs(acc, accTree[prop], true);
|
||||
break;
|
||||
|
||||
case "absentAttributes":
|
||||
testAbsentAttrs(acc, accTree[prop]);
|
||||
break;
|
||||
|
||||
case "interfaces": {
|
||||
var ifaces = (accTree[prop] instanceof Array) ?
|
||||
accTree[prop] : [ accTree[prop] ];
|
||||
for (let i = 0; i < ifaces.length; i++) {
|
||||
ok((acc instanceof ifaces[i]),
|
||||
"No " + ifaces[i] + " interface on " + prettyName(acc));
|
||||
case "actions": {
|
||||
testActionNames(acc, accTree.actions);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "relations": {
|
||||
for (var rel in accTree[prop])
|
||||
testRelation(acc, window[rel], accTree[prop][rel]);
|
||||
break;
|
||||
}
|
||||
case "attributes":
|
||||
testAttrs(acc, accTree[prop], true);
|
||||
break;
|
||||
|
||||
case "role":
|
||||
isRole(acc, accTree[prop], msg);
|
||||
break;
|
||||
case "absentAttributes":
|
||||
testAbsentAttrs(acc, accTree[prop]);
|
||||
break;
|
||||
|
||||
case "states":
|
||||
case "extraStates":
|
||||
case "absentStates":
|
||||
case "absentExtraStates": {
|
||||
testStates(acc, accTree.states, accTree.extraStates,
|
||||
accTree.absentStates, accTree.absentExtraStates);
|
||||
break;
|
||||
}
|
||||
|
||||
case "tagName":
|
||||
is(accTree[prop], acc.DOMNode.tagName, msg);
|
||||
break;
|
||||
|
||||
case "textAttrs": {
|
||||
var prevOffset = -1;
|
||||
for (var offset in accTree[prop]) {
|
||||
if (prevOffset != -1) {
|
||||
let attrs = accTree[prop][prevOffset];
|
||||
testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, +offset, true);
|
||||
case "interfaces": {
|
||||
var ifaces =
|
||||
accTree[prop] instanceof Array ? accTree[prop] : [accTree[prop]];
|
||||
for (let i = 0; i < ifaces.length; i++) {
|
||||
ok(
|
||||
acc instanceof ifaces[i],
|
||||
"No " + ifaces[i] + " interface on " + prettyName(acc)
|
||||
);
|
||||
}
|
||||
prevOffset = +offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if (prevOffset != -1) {
|
||||
var charCount = getAccessible(acc, [nsIAccessibleText]).characterCount;
|
||||
let attrs = accTree[prop][prevOffset];
|
||||
testTextAttrs(acc, prevOffset, attrs, { }, prevOffset, charCount, true);
|
||||
case "relations": {
|
||||
for (var rel in accTree[prop]) {
|
||||
testRelation(acc, window[rel], accTree[prop][rel]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "role":
|
||||
isRole(acc, accTree[prop], msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (prop.indexOf("todo_") == 0)
|
||||
todo(false, msg);
|
||||
else if (prop != "children")
|
||||
is(acc[prop], accTree[prop], msg);
|
||||
case "states":
|
||||
case "extraStates":
|
||||
case "absentStates":
|
||||
case "absentExtraStates": {
|
||||
testStates(
|
||||
acc,
|
||||
accTree.states,
|
||||
accTree.extraStates,
|
||||
accTree.absentStates,
|
||||
accTree.absentExtraStates
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "tagName":
|
||||
is(accTree[prop], acc.DOMNode.tagName, msg);
|
||||
break;
|
||||
|
||||
case "textAttrs": {
|
||||
var prevOffset = -1;
|
||||
for (var offset in accTree[prop]) {
|
||||
if (prevOffset != -1) {
|
||||
let attrs = accTree[prop][prevOffset];
|
||||
testTextAttrs(
|
||||
acc,
|
||||
prevOffset,
|
||||
attrs,
|
||||
{},
|
||||
prevOffset,
|
||||
+offset,
|
||||
true
|
||||
);
|
||||
}
|
||||
prevOffset = +offset;
|
||||
}
|
||||
|
||||
if (prevOffset != -1) {
|
||||
var charCount = getAccessible(acc, [nsIAccessibleText])
|
||||
.characterCount;
|
||||
let attrs = accTree[prop][prevOffset];
|
||||
testTextAttrs(
|
||||
acc,
|
||||
prevOffset,
|
||||
attrs,
|
||||
{},
|
||||
prevOffset,
|
||||
charCount,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (prop.indexOf("todo_") == 0) {
|
||||
todo(false, msg);
|
||||
} else if (prop != "children") {
|
||||
is(acc[prop], accTree[prop], msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,29 +540,62 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
|
|||
|
||||
if (accTree.children.length != childCount) {
|
||||
for (let i = 0; i < Math.max(accTree.children.length, childCount); i++) {
|
||||
var accChild = null, testChild = null;
|
||||
var accChild = null,
|
||||
testChild = null;
|
||||
try {
|
||||
testChild = accTree.children[i];
|
||||
accChild = children.queryElementAt(i, nsIAccessible);
|
||||
|
||||
if (!testChild) {
|
||||
ok(false, prettyName(acc) + " has an extra child at index " + i +
|
||||
" : " + prettyName(accChild));
|
||||
ok(
|
||||
false,
|
||||
prettyName(acc) +
|
||||
" has an extra child at index " +
|
||||
i +
|
||||
" : " +
|
||||
prettyName(accChild)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
testChild = normalizeAccTreeObj(testChild);
|
||||
if (accChild.role !== testChild.role) {
|
||||
ok(false, prettyName(accTree) + " and " + prettyName(acc) +
|
||||
" have different children at index " + i + " : " +
|
||||
prettyName(testChild) + ", " + prettyName(accChild));
|
||||
ok(
|
||||
false,
|
||||
prettyName(accTree) +
|
||||
" and " +
|
||||
prettyName(acc) +
|
||||
" have different children at index " +
|
||||
i +
|
||||
" : " +
|
||||
prettyName(testChild) +
|
||||
", " +
|
||||
prettyName(accChild)
|
||||
);
|
||||
}
|
||||
info("Matching " + prettyName(accTree) + " and " + prettyName(acc) +
|
||||
" child at index " + i + " : " + prettyName(accChild));
|
||||
info(
|
||||
"Matching " +
|
||||
prettyName(accTree) +
|
||||
" and " +
|
||||
prettyName(acc) +
|
||||
" child at index " +
|
||||
i +
|
||||
" : " +
|
||||
prettyName(accChild)
|
||||
);
|
||||
} catch (e) {
|
||||
ok(false, prettyName(accTree) + " is expected to have a child at index " + i +
|
||||
" : " + prettyName(testChild) + ", original tested: " +
|
||||
prettyName(aAccOrElmOrID) + ", " + e);
|
||||
ok(
|
||||
false,
|
||||
prettyName(accTree) +
|
||||
" is expected to have a child at index " +
|
||||
i +
|
||||
" : " +
|
||||
prettyName(testChild) +
|
||||
", original tested: " +
|
||||
prettyName(aAccOrElmOrID) +
|
||||
", " +
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -522,50 +608,77 @@ function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) {
|
|||
}
|
||||
|
||||
// nsIAccessible::firstChild
|
||||
var expectedFirstChild = childCount > 0 ?
|
||||
children.queryElementAt(0, nsIAccessible) : null;
|
||||
var expectedFirstChild =
|
||||
childCount > 0 ? children.queryElementAt(0, nsIAccessible) : null;
|
||||
var firstChild = null;
|
||||
try { firstChild = acc.firstChild; } catch (e) {}
|
||||
is(firstChild, expectedFirstChild,
|
||||
"Wrong first child of " + prettyName(acc));
|
||||
try {
|
||||
firstChild = acc.firstChild;
|
||||
} catch (e) {}
|
||||
is(
|
||||
firstChild,
|
||||
expectedFirstChild,
|
||||
"Wrong first child of " + prettyName(acc)
|
||||
);
|
||||
|
||||
// nsIAccessible::lastChild
|
||||
var expectedLastChild = childCount > 0 ?
|
||||
children.queryElementAt(childCount - 1, nsIAccessible) : null;
|
||||
var expectedLastChild =
|
||||
childCount > 0
|
||||
? children.queryElementAt(childCount - 1, nsIAccessible)
|
||||
: null;
|
||||
var lastChild = null;
|
||||
try { lastChild = acc.lastChild; } catch (e) {}
|
||||
is(lastChild, expectedLastChild,
|
||||
"Wrong last child of " + prettyName(acc));
|
||||
try {
|
||||
lastChild = acc.lastChild;
|
||||
} catch (e) {}
|
||||
is(
|
||||
lastChild,
|
||||
expectedLastChild,
|
||||
"Wrong last child of " + prettyName(acc)
|
||||
);
|
||||
|
||||
for (var i = 0; i < childCount; i++) {
|
||||
let child = children.queryElementAt(i, nsIAccessible);
|
||||
|
||||
// nsIAccessible::parent
|
||||
var parent = null;
|
||||
try { parent = child.parent; } catch (e) {}
|
||||
try {
|
||||
parent = child.parent;
|
||||
} catch (e) {}
|
||||
is(parent, acc, "Wrong parent of " + prettyName(child));
|
||||
|
||||
// nsIAccessible::indexInParent
|
||||
var indexInParent = -1;
|
||||
try { indexInParent = child.indexInParent; } catch (e) {}
|
||||
is(indexInParent, i,
|
||||
"Wrong index in parent of " + prettyName(child));
|
||||
try {
|
||||
indexInParent = child.indexInParent;
|
||||
} catch (e) {}
|
||||
is(indexInParent, i, "Wrong index in parent of " + prettyName(child));
|
||||
|
||||
// nsIAccessible::nextSibling
|
||||
var expectedNextSibling = (i < childCount - 1) ?
|
||||
children.queryElementAt(i + 1, nsIAccessible) : null;
|
||||
var expectedNextSibling =
|
||||
i < childCount - 1
|
||||
? children.queryElementAt(i + 1, nsIAccessible)
|
||||
: null;
|
||||
var nextSibling = null;
|
||||
try { nextSibling = child.nextSibling; } catch (e) {}
|
||||
is(nextSibling, expectedNextSibling,
|
||||
"Wrong next sibling of " + prettyName(child));
|
||||
try {
|
||||
nextSibling = child.nextSibling;
|
||||
} catch (e) {}
|
||||
is(
|
||||
nextSibling,
|
||||
expectedNextSibling,
|
||||
"Wrong next sibling of " + prettyName(child)
|
||||
);
|
||||
|
||||
// nsIAccessible::previousSibling
|
||||
var expectedPrevSibling = (i > 0) ?
|
||||
children.queryElementAt(i - 1, nsIAccessible) : null;
|
||||
var expectedPrevSibling =
|
||||
i > 0 ? children.queryElementAt(i - 1, nsIAccessible) : null;
|
||||
var prevSibling = null;
|
||||
try { prevSibling = child.previousSibling; } catch (e) {}
|
||||
is(prevSibling, expectedPrevSibling,
|
||||
"Wrong previous sibling of " + prettyName(child));
|
||||
try {
|
||||
prevSibling = child.previousSibling;
|
||||
} catch (e) {}
|
||||
is(
|
||||
prevSibling,
|
||||
expectedPrevSibling,
|
||||
"Wrong previous sibling of " + prettyName(child)
|
||||
);
|
||||
|
||||
// Go down through subtree
|
||||
testAccessibleTree(child, accTree.children[i], aFlags);
|
||||
|
@ -589,19 +702,22 @@ function isAccessibleInCache(aNodeOrId) {
|
|||
* @param aNodeOrId [in] the DOM node identifier for the defunct accessible
|
||||
*/
|
||||
function testDefunctAccessible(aAcc, aNodeOrId) {
|
||||
if (aNodeOrId)
|
||||
ok(!isAccessible(aNodeOrId),
|
||||
"Accessible for " + aNodeOrId + " wasn't properly shut down!");
|
||||
if (aNodeOrId) {
|
||||
ok(
|
||||
!isAccessible(aNodeOrId),
|
||||
"Accessible for " + aNodeOrId + " wasn't properly shut down!"
|
||||
);
|
||||
}
|
||||
|
||||
var msg = " doesn't fail for shut down accessible " +
|
||||
prettyName(aNodeOrId) + "!";
|
||||
var msg =
|
||||
" doesn't fail for shut down accessible " + prettyName(aNodeOrId) + "!";
|
||||
|
||||
// firstChild
|
||||
var success = false;
|
||||
try {
|
||||
aAcc.firstChild;
|
||||
} catch (e) {
|
||||
success = (e.result == Cr.NS_ERROR_FAILURE);
|
||||
success = e.result == Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
ok(success, "firstChild" + msg);
|
||||
|
||||
|
@ -610,7 +726,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
|
|||
try {
|
||||
aAcc.lastChild;
|
||||
} catch (e) {
|
||||
success = (e.result == Cr.NS_ERROR_FAILURE);
|
||||
success = e.result == Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
ok(success, "lastChild" + msg);
|
||||
|
||||
|
@ -619,7 +735,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
|
|||
try {
|
||||
aAcc.childCount;
|
||||
} catch (e) {
|
||||
success = (e.result == Cr.NS_ERROR_FAILURE);
|
||||
success = e.result == Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
ok(success, "childCount" + msg);
|
||||
|
||||
|
@ -628,7 +744,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
|
|||
try {
|
||||
aAcc.children;
|
||||
} catch (e) {
|
||||
success = (e.result == Cr.NS_ERROR_FAILURE);
|
||||
success = e.result == Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
ok(success, "children" + msg);
|
||||
|
||||
|
@ -637,7 +753,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
|
|||
try {
|
||||
aAcc.nextSibling;
|
||||
} catch (e) {
|
||||
success = (e.result == Cr.NS_ERROR_FAILURE);
|
||||
success = e.result == Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
ok(success, "nextSibling" + msg);
|
||||
|
||||
|
@ -646,7 +762,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
|
|||
try {
|
||||
aAcc.previousSibling;
|
||||
} catch (e) {
|
||||
success = (e.result == Cr.NS_ERROR_FAILURE);
|
||||
success = e.result == Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
ok(success, "previousSibling" + msg);
|
||||
|
||||
|
@ -655,7 +771,7 @@ function testDefunctAccessible(aAcc, aNodeOrId) {
|
|||
try {
|
||||
aAcc.parent;
|
||||
} catch (e) {
|
||||
success = (e.result == Cr.NS_ERROR_FAILURE);
|
||||
success = e.result == Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
ok(success, "parent" + msg);
|
||||
}
|
||||
|
@ -674,11 +790,13 @@ function statesToString(aStates, aExtraStates) {
|
|||
var list = gAccService.getStringStates(aStates, aExtraStates);
|
||||
|
||||
var str = "";
|
||||
for (var index = 0; index < list.length - 1; index++)
|
||||
for (var index = 0; index < list.length - 1; index++) {
|
||||
str += list.item(index) + ", ";
|
||||
}
|
||||
|
||||
if (list.length != 0)
|
||||
if (list.length != 0) {
|
||||
str += list.item(index);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
@ -705,11 +823,13 @@ function getLoadContext() {
|
|||
* Return text from clipboard.
|
||||
*/
|
||||
function getTextFromClipboard() {
|
||||
var trans = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
|
||||
Ci.nsITransferable
|
||||
);
|
||||
trans.init(getLoadContext());
|
||||
if (!trans)
|
||||
if (!trans) {
|
||||
return "";
|
||||
}
|
||||
|
||||
trans.addDataFlavor("text/unicode");
|
||||
Services.clipboard.getData(trans, Services.clipboard.kGlobalClipboard);
|
||||
|
@ -717,10 +837,12 @@ function getTextFromClipboard() {
|
|||
var str = {};
|
||||
trans.getTransferData("text/unicode", str);
|
||||
|
||||
if (str)
|
||||
if (str) {
|
||||
str = str.value.QueryInterface(Ci.nsISupportsString);
|
||||
if (str)
|
||||
}
|
||||
if (str) {
|
||||
return str.data;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -737,17 +859,23 @@ function getAccessibleDOMNodeID(accessible) {
|
|||
// If accessible is a document, trying to find its document body id.
|
||||
try {
|
||||
return accessible.DOMNode.body.id;
|
||||
} catch (e) { /* This only works if accessible is not a proxy. */ }
|
||||
} catch (e) {
|
||||
/* This only works if accessible is not a proxy. */
|
||||
}
|
||||
}
|
||||
try {
|
||||
return accessible.DOMNode.id;
|
||||
} catch (e) { /* This will fail if DOMNode is in different process. */ }
|
||||
} catch (e) {
|
||||
/* This will fail if DOMNode is in different process. */
|
||||
}
|
||||
try {
|
||||
// When e10s is enabled, accessible will have an "id" property if its
|
||||
// corresponding DOMNode has an id. If accessible is a document, its "id"
|
||||
// property corresponds to the "id" of its body element.
|
||||
return accessible.id;
|
||||
} catch (e) { /* This will fail if accessible is not a proxy. */ }
|
||||
} catch (e) {
|
||||
/* This will fail if accessible is not a proxy. */
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -758,8 +886,9 @@ function prettyName(aIdentifier) {
|
|||
if (aIdentifier instanceof Array) {
|
||||
let msg = "";
|
||||
for (var idx = 0; idx < aIdentifier.length; idx++) {
|
||||
if (msg != "")
|
||||
if (msg != "") {
|
||||
msg += ", ";
|
||||
}
|
||||
|
||||
msg += prettyName(aIdentifier[idx]);
|
||||
}
|
||||
|
@ -779,23 +908,26 @@ function prettyName(aIdentifier) {
|
|||
msg += `${getNodePrettyName(acc.DOMNode)}, `;
|
||||
}
|
||||
msg += "role: " + roleToString(acc.role);
|
||||
if (acc.name)
|
||||
if (acc.name) {
|
||||
msg += ", name: '" + shortenString(acc.name) + "'";
|
||||
}
|
||||
} catch (e) {
|
||||
msg += "defunct";
|
||||
}
|
||||
|
||||
if (acc)
|
||||
if (acc) {
|
||||
msg += ", address: " + getObjAddress(acc);
|
||||
}
|
||||
msg += "]";
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (Node.isInstance(aIdentifier))
|
||||
if (Node.isInstance(aIdentifier)) {
|
||||
return "[ " + getNodePrettyName(aIdentifier) + " ]";
|
||||
}
|
||||
|
||||
if (aIdentifier && typeof aIdentifier === "object" ) {
|
||||
if (aIdentifier && typeof aIdentifier === "object") {
|
||||
var treeObj = normalizeAccTreeObj(aIdentifier);
|
||||
if ("role" in treeObj) {
|
||||
function stringifyTree(aObj) {
|
||||
|
@ -825,13 +957,17 @@ function prettyName(aIdentifier) {
|
|||
* @returns the shortened string.
|
||||
*/
|
||||
function shortenString(aString, aMaxLength) {
|
||||
if (aString.length <= MAX_TRIM_LENGTH)
|
||||
if (aString.length <= MAX_TRIM_LENGTH) {
|
||||
return aString;
|
||||
}
|
||||
|
||||
// Trim the string if its length is > MAX_TRIM_LENGTH characters.
|
||||
var trimOffset = MAX_TRIM_LENGTH / 2;
|
||||
return aString.substring(0, trimOffset - 1) + "..." +
|
||||
aString.substring(aString.length - trimOffset, aString.length);
|
||||
return (
|
||||
aString.substring(0, trimOffset - 1) +
|
||||
"..." +
|
||||
aString.substring(aString.length - trimOffset, aString.length)
|
||||
);
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -873,8 +1009,9 @@ function getNodePrettyName(aNode) {
|
|||
tag = "document";
|
||||
} else {
|
||||
tag = aNode.localName;
|
||||
if (aNode.nodeType == Node.ELEMENT_NODE && aNode.hasAttribute("id"))
|
||||
tag += "@id=\"" + aNode.getAttribute("id") + "\"";
|
||||
if (aNode.nodeType == Node.ELEMENT_NODE && aNode.hasAttribute("id")) {
|
||||
tag += '@id="' + aNode.getAttribute("id") + '"';
|
||||
}
|
||||
}
|
||||
|
||||
return "'" + tag + " node', address: " + getObjAddress(aNode);
|
||||
|
@ -886,15 +1023,17 @@ function getNodePrettyName(aNode) {
|
|||
function getObjAddress(aObj) {
|
||||
var exp = /native\s*@\s*(0x[a-f0-9]+)/g;
|
||||
var match = exp.exec(aObj.toString());
|
||||
if (match)
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
|
||||
return aObj.toString();
|
||||
}
|
||||
|
||||
function getTestPluginTag(aPluginName) {
|
||||
var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
|
||||
.getService(SpecialPowers.Ci.nsIPluginHost);
|
||||
var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"].getService(
|
||||
SpecialPowers.Ci.nsIPluginHost
|
||||
);
|
||||
var tags = ph.getPluginTags();
|
||||
var name = aPluginName || "Test Plug-in";
|
||||
for (var tag of tags) {
|
||||
|
|
|
@ -60,22 +60,29 @@ function editableTextTest(aID) {
|
|||
}
|
||||
|
||||
aSkipStartOffset = aSkipStartOffset || 0;
|
||||
var insertTripple = aValue ?
|
||||
[ aSkipStartOffset, aSkipStartOffset + aValue.length, aValue ] : null;
|
||||
var insertTripple = aValue
|
||||
? [aSkipStartOffset, aSkipStartOffset + aValue.length, aValue]
|
||||
: null;
|
||||
var oldValue = getValue();
|
||||
var removeTripple = oldValue ?
|
||||
[ aSkipStartOffset, aSkipStartOffset + oldValue.length, oldValue ] : null;
|
||||
var removeTripple = oldValue
|
||||
? [aSkipStartOffset, aSkipStartOffset + oldValue.length, oldValue]
|
||||
: null;
|
||||
|
||||
this.generateTest(removeTripple, insertTripple, setTextContentsInvoke,
|
||||
getValueChecker(aValue), testID);
|
||||
this.generateTest(
|
||||
removeTripple,
|
||||
insertTripple,
|
||||
setTextContentsInvoke,
|
||||
getValueChecker(aValue),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* insertText test.
|
||||
*/
|
||||
this.insertText = function insertText(aStr, aPos, aResStr, aResPos) {
|
||||
var testID = "insertText '" + aStr + "' at " + aPos + " for " +
|
||||
prettyName(aID);
|
||||
var testID =
|
||||
"insertText '" + aStr + "' at " + aPos + " for " + prettyName(aID);
|
||||
|
||||
function insertTextInvoke() {
|
||||
dump(`\ninsertText '${aStr}' at ${aPos} pos\n`);
|
||||
|
@ -83,16 +90,26 @@ function editableTextTest(aID) {
|
|||
acc.insertText(aStr, aPos);
|
||||
}
|
||||
|
||||
var resPos = (aResPos != undefined) ? aResPos : aPos;
|
||||
this.generateTest(null, [resPos, resPos + aStr.length, aStr],
|
||||
insertTextInvoke, getValueChecker(aResStr), testID);
|
||||
var resPos = aResPos != undefined ? aResPos : aPos;
|
||||
this.generateTest(
|
||||
null,
|
||||
[resPos, resPos + aStr.length, aStr],
|
||||
insertTextInvoke,
|
||||
getValueChecker(aResStr),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* copyText test.
|
||||
*/
|
||||
this.copyText = function copyText(aStartPos, aEndPos, aClipboardStr) {
|
||||
var testID = "copyText from " + aStartPos + " to " + aEndPos + " for " +
|
||||
var testID =
|
||||
"copyText from " +
|
||||
aStartPos +
|
||||
" to " +
|
||||
aEndPos +
|
||||
" for " +
|
||||
prettyName(aID);
|
||||
|
||||
function copyTextInvoke() {
|
||||
|
@ -100,17 +117,33 @@ function editableTextTest(aID) {
|
|||
acc.copyText(aStartPos, aEndPos);
|
||||
}
|
||||
|
||||
this.generateTest(null, null, copyTextInvoke,
|
||||
getClipboardChecker(aClipboardStr), testID);
|
||||
this.generateTest(
|
||||
null,
|
||||
null,
|
||||
copyTextInvoke,
|
||||
getClipboardChecker(aClipboardStr),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* copyText and pasteText test.
|
||||
*/
|
||||
this.copyNPasteText = function copyNPasteText(aStartPos, aEndPos,
|
||||
aPos, aResStr) {
|
||||
var testID = "copyText from " + aStartPos + " to " + aEndPos +
|
||||
"and pasteText at " + aPos + " for " + prettyName(aID);
|
||||
this.copyNPasteText = function copyNPasteText(
|
||||
aStartPos,
|
||||
aEndPos,
|
||||
aPos,
|
||||
aResStr
|
||||
) {
|
||||
var testID =
|
||||
"copyText from " +
|
||||
aStartPos +
|
||||
" to " +
|
||||
aEndPos +
|
||||
"and pasteText at " +
|
||||
aPos +
|
||||
" for " +
|
||||
prettyName(aID);
|
||||
|
||||
function copyNPasteTextInvoke() {
|
||||
var acc = getAccessible(aID, nsIAccessibleEditableText);
|
||||
|
@ -118,16 +151,31 @@ function editableTextTest(aID) {
|
|||
acc.pasteText(aPos);
|
||||
}
|
||||
|
||||
this.generateTest(null, [aStartPos, aEndPos, getTextFromClipboard],
|
||||
copyNPasteTextInvoke, getValueChecker(aResStr), testID);
|
||||
this.generateTest(
|
||||
null,
|
||||
[aStartPos, aEndPos, getTextFromClipboard],
|
||||
copyNPasteTextInvoke,
|
||||
getValueChecker(aResStr),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* cutText test.
|
||||
*/
|
||||
this.cutText = function cutText(aStartPos, aEndPos, aResStr,
|
||||
aResStartPos, aResEndPos) {
|
||||
var testID = "cutText from " + aStartPos + " to " + aEndPos + " for " +
|
||||
this.cutText = function cutText(
|
||||
aStartPos,
|
||||
aEndPos,
|
||||
aResStr,
|
||||
aResStartPos,
|
||||
aResEndPos
|
||||
) {
|
||||
var testID =
|
||||
"cutText from " +
|
||||
aStartPos +
|
||||
" to " +
|
||||
aEndPos +
|
||||
" for " +
|
||||
prettyName(aID);
|
||||
|
||||
function cutTextInvoke() {
|
||||
|
@ -135,19 +183,35 @@ function editableTextTest(aID) {
|
|||
acc.cutText(aStartPos, aEndPos);
|
||||
}
|
||||
|
||||
var resStartPos = (aResStartPos != undefined) ? aResStartPos : aStartPos;
|
||||
var resEndPos = (aResEndPos != undefined) ? aResEndPos : aEndPos;
|
||||
this.generateTest([resStartPos, resEndPos, getTextFromClipboard], null,
|
||||
cutTextInvoke, getValueChecker(aResStr), testID);
|
||||
var resStartPos = aResStartPos != undefined ? aResStartPos : aStartPos;
|
||||
var resEndPos = aResEndPos != undefined ? aResEndPos : aEndPos;
|
||||
this.generateTest(
|
||||
[resStartPos, resEndPos, getTextFromClipboard],
|
||||
null,
|
||||
cutTextInvoke,
|
||||
getValueChecker(aResStr),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* cutText and pasteText test.
|
||||
*/
|
||||
this.cutNPasteText = function copyNPasteText(aStartPos, aEndPos,
|
||||
aPos, aResStr) {
|
||||
var testID = "cutText from " + aStartPos + " to " + aEndPos +
|
||||
" and pasteText at " + aPos + " for " + prettyName(aID);
|
||||
this.cutNPasteText = function copyNPasteText(
|
||||
aStartPos,
|
||||
aEndPos,
|
||||
aPos,
|
||||
aResStr
|
||||
) {
|
||||
var testID =
|
||||
"cutText from " +
|
||||
aStartPos +
|
||||
" to " +
|
||||
aEndPos +
|
||||
" and pasteText at " +
|
||||
aPos +
|
||||
" for " +
|
||||
prettyName(aID);
|
||||
|
||||
function cutNPasteTextInvoke() {
|
||||
var acc = getAccessible(aID, nsIAccessibleEditableText);
|
||||
|
@ -155,10 +219,13 @@ function editableTextTest(aID) {
|
|||
acc.pasteText(aPos);
|
||||
}
|
||||
|
||||
this.generateTest([aStartPos, aEndPos, getTextFromClipboard],
|
||||
[aPos, -1, getTextFromClipboard],
|
||||
cutNPasteTextInvoke, getValueChecker(aResStr),
|
||||
testID);
|
||||
this.generateTest(
|
||||
[aStartPos, aEndPos, getTextFromClipboard],
|
||||
[aPos, -1, getTextFromClipboard],
|
||||
cutNPasteTextInvoke,
|
||||
getValueChecker(aResStr),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -172,16 +239,26 @@ function editableTextTest(aID) {
|
|||
acc.pasteText(aPos);
|
||||
}
|
||||
|
||||
this.generateTest(null, [aPos, -1, getTextFromClipboard],
|
||||
pasteTextInvoke, getValueChecker(aResStr), testID);
|
||||
this.generateTest(
|
||||
null,
|
||||
[aPos, -1, getTextFromClipboard],
|
||||
pasteTextInvoke,
|
||||
getValueChecker(aResStr),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* deleteText test.
|
||||
*/
|
||||
this.deleteText = function deleteText(aStartPos, aEndPos, aResStr) {
|
||||
var testID = "deleteText from " + aStartPos + " to " + aEndPos +
|
||||
" for " + prettyName(aID);
|
||||
var testID =
|
||||
"deleteText from " +
|
||||
aStartPos +
|
||||
" to " +
|
||||
aEndPos +
|
||||
" for " +
|
||||
prettyName(aID);
|
||||
|
||||
var oldValue = getValue().substring(aStartPos, aEndPos);
|
||||
var removeTripple = oldValue ? [aStartPos, aEndPos, oldValue] : null;
|
||||
|
@ -191,8 +268,13 @@ function editableTextTest(aID) {
|
|||
acc.deleteText(aStartPos, aEndPos);
|
||||
}
|
||||
|
||||
this.generateTest(removeTripple, null, deleteTextInvoke,
|
||||
getValueChecker(aResStr), testID);
|
||||
this.generateTest(
|
||||
removeTripple,
|
||||
null,
|
||||
deleteTextInvoke,
|
||||
getValueChecker(aResStr),
|
||||
testID
|
||||
);
|
||||
};
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -201,11 +283,13 @@ function editableTextTest(aID) {
|
|||
function getValue() {
|
||||
var elm = getNode(aID);
|
||||
var elmClass = ChromeUtils.getClassName(elm);
|
||||
if (elmClass === "HTMLTextAreaElement" || elmClass === "HTMLInputElement")
|
||||
if (elmClass === "HTMLTextAreaElement" || elmClass === "HTMLInputElement") {
|
||||
return elm.value;
|
||||
}
|
||||
|
||||
if (elmClass === "HTMLDocument")
|
||||
if (elmClass === "HTMLDocument") {
|
||||
return elm.body.textContent;
|
||||
}
|
||||
|
||||
return elm.textContent;
|
||||
}
|
||||
|
@ -236,15 +320,21 @@ function editableTextTest(aID) {
|
|||
*/
|
||||
this.unwrapNextTest = function unwrapNextTest() {
|
||||
var data = this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1];
|
||||
if (data)
|
||||
if (data) {
|
||||
data.func.apply(this, data.funcArgs);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to generate an invoker object for the sheduled test.
|
||||
*/
|
||||
this.generateTest = function generateTest(aRemoveTriple, aInsertTriple,
|
||||
aInvokeFunc, aChecker, aInvokerID) {
|
||||
this.generateTest = function generateTest(
|
||||
aRemoveTriple,
|
||||
aInsertTriple,
|
||||
aInvokeFunc,
|
||||
aChecker,
|
||||
aInvokerID
|
||||
) {
|
||||
var et = this;
|
||||
var invoker = {
|
||||
eventSeq: [],
|
||||
|
@ -256,26 +346,37 @@ function editableTextTest(aID) {
|
|||
aChecker.check();
|
||||
et.unwrapNextTest(); // replace dummy invoker on real invoker object.
|
||||
},
|
||||
getID: function getID() { return aInvokerID; },
|
||||
getID: function getID() {
|
||||
return aInvokerID;
|
||||
},
|
||||
};
|
||||
|
||||
if (aRemoveTriple) {
|
||||
let checker = new textChangeChecker(aID, aRemoveTriple[0],
|
||||
aRemoveTriple[1], aRemoveTriple[2],
|
||||
false);
|
||||
let checker = new textChangeChecker(
|
||||
aID,
|
||||
aRemoveTriple[0],
|
||||
aRemoveTriple[1],
|
||||
aRemoveTriple[2],
|
||||
false
|
||||
);
|
||||
invoker.eventSeq.push(checker);
|
||||
}
|
||||
|
||||
if (aInsertTriple) {
|
||||
let checker = new textChangeChecker(aID, aInsertTriple[0],
|
||||
aInsertTriple[1], aInsertTriple[2],
|
||||
true);
|
||||
let checker = new textChangeChecker(
|
||||
aID,
|
||||
aInsertTriple[0],
|
||||
aInsertTriple[1],
|
||||
aInsertTriple[2],
|
||||
true
|
||||
);
|
||||
invoker.eventSeq.push(checker);
|
||||
}
|
||||
|
||||
// Claim that we don't want to fail when no events are expected.
|
||||
if (!aRemoveTriple && !aInsertTriple)
|
||||
if (!aRemoveTriple && !aInsertTriple) {
|
||||
invoker.noEventsOnAction = true;
|
||||
}
|
||||
|
||||
this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1] = invoker;
|
||||
};
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -31,8 +31,9 @@ function grid(aTableIdentifier) {
|
|||
var colIdx = aCell.cellIndex;
|
||||
|
||||
var rowIdx = aCell.parentNode.rowIndex;
|
||||
if (this.table.tHead)
|
||||
if (this.table.tHead) {
|
||||
rowIdx -= 1;
|
||||
}
|
||||
|
||||
var colsCount = this.getColsCount();
|
||||
return rowIdx * colsCount + colIdx;
|
||||
|
@ -44,8 +45,9 @@ function grid(aTableIdentifier) {
|
|||
for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
||||
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
var cell = this.table.rows[rowIdx].cells[colIdx];
|
||||
if (cell.hasAttribute("tabindex"))
|
||||
if (cell.hasAttribute("tabindex")) {
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -57,15 +59,17 @@ function grid(aTableIdentifier) {
|
|||
};
|
||||
|
||||
this.handleEvent = function handleEvent(aEvent) {
|
||||
if (aEvent instanceof KeyboardEvent)
|
||||
if (aEvent instanceof KeyboardEvent) {
|
||||
this.handleKeyEvent(aEvent);
|
||||
else
|
||||
} else {
|
||||
this.handleClickEvent(aEvent);
|
||||
}
|
||||
};
|
||||
|
||||
this.handleKeyEvent = function handleKeyEvent(aEvent) {
|
||||
if (aEvent.target.localName != "td")
|
||||
if (aEvent.target.localName != "td") {
|
||||
return;
|
||||
}
|
||||
|
||||
var cell = aEvent.target;
|
||||
switch (aEvent.keyCode) {
|
||||
|
@ -117,8 +121,9 @@ function grid(aTableIdentifier) {
|
|||
};
|
||||
|
||||
this.handleClickEvent = function handleClickEvent(aEvent) {
|
||||
if (aEvent.target.localName != "td")
|
||||
if (aEvent.target.localName != "td") {
|
||||
return;
|
||||
}
|
||||
|
||||
var curCell = this.getCurrentCell();
|
||||
var cell = aEvent.target;
|
||||
|
|
|
@ -13,22 +13,26 @@ function focusLink(aID, aSelectedAfter) {
|
|||
this.unexpectedEventSeq = [];
|
||||
|
||||
var checker = new invokerChecker(EVENT_FOCUS, this.accessible);
|
||||
if (aSelectedAfter)
|
||||
if (aSelectedAfter) {
|
||||
this.eventSeq.push(checker);
|
||||
else
|
||||
} else {
|
||||
this.unexpectedEventSeq.push(checker);
|
||||
}
|
||||
|
||||
this.invoke = function focusLink_invoke() {
|
||||
var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE : 0);
|
||||
var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE : 0) | STATE_FOCUSED;
|
||||
var expectedStates = aSelectedAfter ? STATE_FOCUSABLE : 0;
|
||||
var unexpectedStates =
|
||||
(!aSelectedAfter ? STATE_FOCUSABLE : 0) | STATE_FOCUSED;
|
||||
testStates(aID, expectedStates, 0, unexpectedStates, 0);
|
||||
|
||||
this.node.focus();
|
||||
};
|
||||
|
||||
this.finalCheck = function focusLink_finalCheck() {
|
||||
var expectedStates = (aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
|
||||
var unexpectedStates = (!aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0);
|
||||
var expectedStates = aSelectedAfter ? STATE_FOCUSABLE | STATE_FOCUSED : 0;
|
||||
var unexpectedStates = !aSelectedAfter
|
||||
? STATE_FOCUSABLE | STATE_FOCUSED
|
||||
: 0;
|
||||
testStates(aID, expectedStates, 0, unexpectedStates, 0);
|
||||
};
|
||||
|
||||
|
|
|
@ -6,17 +6,19 @@
|
|||
addMessageListener, currentTabDocument, currentBrowser*/
|
||||
|
||||
/**
|
||||
* A global variable holding an array of test functions.
|
||||
*/
|
||||
* A global variable holding an array of test functions.
|
||||
*/
|
||||
var gTestFuncs = [];
|
||||
/**
|
||||
* A global Iterator for the array of test functions.
|
||||
*/
|
||||
* A global Iterator for the array of test functions.
|
||||
*/
|
||||
var gIterator;
|
||||
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var AccessFu;
|
||||
const {Logger, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
|
||||
const { Logger, Utils } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
|
||||
const MovementGranularity = {
|
||||
CHARACTER: 1,
|
||||
|
@ -26,14 +28,16 @@ const MovementGranularity = {
|
|||
};
|
||||
|
||||
var AccessFuTest = {
|
||||
|
||||
addFunc: function AccessFuTest_addFunc(aFunc) {
|
||||
if (aFunc) {
|
||||
gTestFuncs.push(aFunc);
|
||||
}
|
||||
},
|
||||
|
||||
_registerListener: function AccessFuTest__registerListener(aWaitForMessage, aListenerFunc) {
|
||||
_registerListener: function AccessFuTest__registerListener(
|
||||
aWaitForMessage,
|
||||
aListenerFunc
|
||||
) {
|
||||
var listener = {
|
||||
observe: function observe(aMessage) {
|
||||
// Ignore unexpected messages.
|
||||
|
@ -59,11 +63,13 @@ var AccessFuTest = {
|
|||
},
|
||||
|
||||
once_log: function AccessFuTest_once_log(aWaitForMessage, aListenerFunc) {
|
||||
return this._registerListener(aWaitForMessage,
|
||||
return this._registerListener(
|
||||
aWaitForMessage,
|
||||
function listenAndUnregister() {
|
||||
Services.console.unregisterListener(this);
|
||||
aListenerFunc();
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
_addObserver: function AccessFuTest__addObserver(aWaitForData, aListener) {
|
||||
|
@ -134,7 +140,7 @@ var AccessFuTest = {
|
|||
}
|
||||
|
||||
// Create an Iterator for gTestFuncs array.
|
||||
gIterator = (function* () {
|
||||
gIterator = (function*() {
|
||||
for (var testFunc of gTestFuncs) {
|
||||
yield testFunc;
|
||||
}
|
||||
|
@ -144,12 +150,14 @@ var AccessFuTest = {
|
|||
Logger.logLevel = Logger.DEBUG;
|
||||
|
||||
// Start AccessFu and put it in stand-by.
|
||||
({AccessFu} = ChromeUtils.import("resource://gre/modules/accessibility/AccessFu.jsm"));
|
||||
({ AccessFu } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/AccessFu.jsm"
|
||||
));
|
||||
|
||||
var prefs = [["accessibility.accessfu.notify_output", 1]];
|
||||
prefs.push.apply(prefs, aAdditionalPrefs);
|
||||
|
||||
SpecialPowers.pushPrefEnv({ "set": prefs }, function() {
|
||||
SpecialPowers.pushPrefEnv({ set: prefs }, function() {
|
||||
if (AccessFuTest._waitForExplicitFinish) {
|
||||
// Run all test functions asynchronously.
|
||||
AccessFuTest.nextTest();
|
||||
|
@ -166,8 +174,10 @@ class AccessFuContentTestRunner {
|
|||
constructor() {
|
||||
this.listenersMap = new Map();
|
||||
let frames = Array.from(currentTabDocument().querySelectorAll("iframe"));
|
||||
this.mms = [Utils.getMessageManager(currentBrowser()),
|
||||
...frames.map(f => Utils.getMessageManager(f)).filter(mm => !!mm)];
|
||||
this.mms = [
|
||||
Utils.getMessageManager(currentBrowser()),
|
||||
...frames.map(f => Utils.getMessageManager(f)).filter(mm => !!mm),
|
||||
];
|
||||
}
|
||||
|
||||
start(aFinishedCallback) {
|
||||
|
@ -208,14 +218,19 @@ class AccessFuContentTestRunner {
|
|||
|
||||
isFocused(aExpected) {
|
||||
var doc = currentTabDocument();
|
||||
SimpleTest.is(doc.activeElement, doc.querySelector(aExpected),
|
||||
"Correct element is focused: " + aExpected);
|
||||
SimpleTest.is(
|
||||
doc.activeElement,
|
||||
doc.querySelector(aExpected),
|
||||
"Correct element is focused: " + aExpected
|
||||
);
|
||||
}
|
||||
|
||||
async setupMessageManager(aMessageManager) {
|
||||
function contentScript() {
|
||||
// eslint-disable-next-line no-shadow
|
||||
const {Logger, Utils} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
|
||||
const { Logger, Utils } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
Logger.logLevel = "DEBUG";
|
||||
Utils.inTest = true;
|
||||
|
||||
|
@ -232,13 +247,18 @@ class AccessFuContentTestRunner {
|
|||
}
|
||||
|
||||
aMessageManager.loadFrameScript(
|
||||
"data:,(" + contentScript.toString() + ")();", false);
|
||||
"data:,(" + contentScript.toString() + ")();",
|
||||
false
|
||||
);
|
||||
|
||||
aMessageManager.loadFrameScript(
|
||||
"chrome://global/content/accessibility/content-script.js", false);
|
||||
"chrome://global/content/accessibility/content-script.js",
|
||||
false
|
||||
);
|
||||
|
||||
let startedPromise = new Promise(resolve =>
|
||||
aMessageManager.addMessageListener("AccessFu:ContentStarted", resolve));
|
||||
aMessageManager.addMessageListener("AccessFu:ContentStarted", resolve)
|
||||
);
|
||||
|
||||
await startedPromise;
|
||||
|
||||
|
@ -254,7 +274,9 @@ class AccessFuContentTestRunner {
|
|||
if (this.debug) {
|
||||
info("Android event: " + JSON.stringify(evt));
|
||||
}
|
||||
let listener = (this.listenersMap.get(evt.eventType || evt) || []).shift();
|
||||
let listener = (
|
||||
this.listenersMap.get(evt.eventType || evt) || []
|
||||
).shift();
|
||||
if (listener) {
|
||||
listener(evt);
|
||||
}
|
||||
|
@ -282,34 +304,44 @@ class AccessFuContentTestRunner {
|
|||
}
|
||||
|
||||
moveNext(aRule, ...aExpectedEvents) {
|
||||
return this.moveCursor({ action: "moveNext", rule: aRule },
|
||||
...aExpectedEvents);
|
||||
return this.moveCursor(
|
||||
{ action: "moveNext", rule: aRule },
|
||||
...aExpectedEvents
|
||||
);
|
||||
}
|
||||
|
||||
movePrevious(aRule, ...aExpectedEvents) {
|
||||
return this.moveCursor({ action: "movePrevious", rule: aRule },
|
||||
...aExpectedEvents);
|
||||
return this.moveCursor(
|
||||
{ action: "movePrevious", rule: aRule },
|
||||
...aExpectedEvents
|
||||
);
|
||||
}
|
||||
|
||||
moveFirst(aRule, ...aExpectedEvents) {
|
||||
return this.moveCursor({ action: "moveFirst", rule: aRule },
|
||||
...aExpectedEvents);
|
||||
return this.moveCursor(
|
||||
{ action: "moveFirst", rule: aRule },
|
||||
...aExpectedEvents
|
||||
);
|
||||
}
|
||||
|
||||
moveLast(aRule, ...aExpectedEvents) {
|
||||
return this.moveCursor({ action: "moveLast", rule: aRule },
|
||||
...aExpectedEvents);
|
||||
return this.moveCursor(
|
||||
{ action: "moveLast", rule: aRule },
|
||||
...aExpectedEvents
|
||||
);
|
||||
}
|
||||
|
||||
async clearCursor() {
|
||||
return new Promise(resolve => {
|
||||
let _listener = (msg) => {
|
||||
this.mms.forEach(
|
||||
mm => mm.removeMessageListener("AccessFu:CursorCleared", _listener));
|
||||
let _listener = msg => {
|
||||
this.mms.forEach(mm =>
|
||||
mm.removeMessageListener("AccessFu:CursorCleared", _listener)
|
||||
);
|
||||
resolve();
|
||||
};
|
||||
this.mms.forEach(
|
||||
mm => mm.addMessageListener("AccessFu:CursorCleared", _listener));
|
||||
this.mms.forEach(mm =>
|
||||
mm.addMessageListener("AccessFu:CursorCleared", _listener)
|
||||
);
|
||||
this.sendMessage({
|
||||
name: "AccessFu:ClearCursor",
|
||||
data: {
|
||||
|
@ -355,15 +387,24 @@ class AccessFuContentTestRunner {
|
|||
}
|
||||
|
||||
eventTextMatches(aEvent, aExpected) {
|
||||
isDeeply(aEvent.text, aExpected,
|
||||
isDeeply(
|
||||
aEvent.text,
|
||||
aExpected,
|
||||
"Event text matches. " +
|
||||
`Got ${JSON.stringify(aEvent.text)}, expected ${JSON.stringify(aExpected)}.`);
|
||||
`Got ${JSON.stringify(aEvent.text)}, expected ${JSON.stringify(
|
||||
aExpected
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
|
||||
eventInfoMatches(aEvent, aExpected) {
|
||||
for (let key in aExpected) {
|
||||
is(aEvent[key], aExpected[key], `Event info matches for ${key}. ` +
|
||||
`Got ${aEvent[key]}, expected ${aExpected[key]}.`);
|
||||
is(
|
||||
aEvent[key],
|
||||
aExpected[key],
|
||||
`Event info matches for ${key}. ` +
|
||||
`Got ${aEvent[key]}, expected ${aExpected[key]}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance";
|
||||
|
||||
const {PivotContext} = ChromeUtils.import("resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/accessibility/OutputGenerator.jsm", this);
|
||||
const { PivotContext } = ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.import(
|
||||
"resource://gre/modules/accessibility/OutputGenerator.jsm",
|
||||
this
|
||||
);
|
||||
|
||||
/**
|
||||
* Test context output generation.
|
||||
|
@ -16,10 +21,17 @@ ChromeUtils.import("resource://gre/modules/accessibility/OutputGenerator.jsm", t
|
|||
* Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be
|
||||
* scoped to the "root" element in markup.
|
||||
*/
|
||||
function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator) {
|
||||
function testContextOutput(
|
||||
expected,
|
||||
aAccOrElmOrID,
|
||||
aOldAccOrElmOrID,
|
||||
aGenerator
|
||||
) {
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var oldAccessible = aOldAccOrElmOrID !== null ?
|
||||
getAccessible(aOldAccOrElmOrID || "root") : null;
|
||||
var oldAccessible =
|
||||
aOldAccOrElmOrID !== null
|
||||
? getAccessible(aOldAccOrElmOrID || "root")
|
||||
: null;
|
||||
var context = new PivotContext(accessible, oldAccessible);
|
||||
var output = aGenerator.genForContext(context);
|
||||
|
||||
|
@ -32,15 +44,23 @@ function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator
|
|||
if (expected[i] === null) {
|
||||
masked_output.push(null);
|
||||
} else {
|
||||
masked_output[i] = typeof output[i] === "string" ? output[i].trim() :
|
||||
output[i];
|
||||
masked_output[i] =
|
||||
typeof output[i] === "string" ? output[i].trim() : output[i];
|
||||
}
|
||||
}
|
||||
|
||||
isDeeply(masked_output, expected,
|
||||
"Context output is correct for " + aAccOrElmOrID +
|
||||
" (output: " + JSON.stringify(output) + ") ==" +
|
||||
" (expected: " + JSON.stringify(expected) + ")");
|
||||
isDeeply(
|
||||
masked_output,
|
||||
expected,
|
||||
"Context output is correct for " +
|
||||
aAccOrElmOrID +
|
||||
" (output: " +
|
||||
JSON.stringify(output) +
|
||||
") ==" +
|
||||
" (expected: " +
|
||||
JSON.stringify(expected) +
|
||||
")"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,8 +90,10 @@ function testObjectOutput(aAccOrElmOrID, aGenerator) {
|
|||
var nameIndex = output.indexOf(accessible.name);
|
||||
|
||||
if (nameIndex > -1) {
|
||||
ok(output.indexOf(accessible.name) === expectedNameIndex,
|
||||
"Object output is correct for " + aAccOrElmOrID);
|
||||
ok(
|
||||
output.indexOf(accessible.name) === expectedNameIndex,
|
||||
"Object output is correct for " + aAccOrElmOrID
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,8 +107,12 @@ function testObjectOutput(aAccOrElmOrID, aGenerator) {
|
|||
* @param aOutputKind the type of output
|
||||
*/
|
||||
function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
|
||||
testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID,
|
||||
UtteranceGenerator);
|
||||
testContextOutput(
|
||||
expected,
|
||||
aAccOrElmOrID,
|
||||
aOldAccOrElmOrID,
|
||||
UtteranceGenerator
|
||||
);
|
||||
// Just need to test object output for individual
|
||||
// accOrElmOrID.
|
||||
if (aOldAccOrElmOrID) {
|
||||
|
@ -97,13 +123,23 @@ function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
|
|||
|
||||
function testHints(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var oldAccessible = aOldAccOrElmOrID !== null ?
|
||||
getAccessible(aOldAccOrElmOrID || "root") : null;
|
||||
var oldAccessible =
|
||||
aOldAccOrElmOrID !== null
|
||||
? getAccessible(aOldAccOrElmOrID || "root")
|
||||
: null;
|
||||
var context = new PivotContext(accessible, oldAccessible);
|
||||
var hints = context.interactionHints;
|
||||
|
||||
isDeeply(hints, expected,
|
||||
"Context hitns are correct for " + aAccOrElmOrID +
|
||||
" (hints: " + JSON.stringify(hints) + ") ==" +
|
||||
" (expected: " + JSON.stringify(expected) + ")");
|
||||
isDeeply(
|
||||
hints,
|
||||
expected,
|
||||
"Context hitns are correct for " +
|
||||
aAccOrElmOrID +
|
||||
" (hints: " +
|
||||
JSON.stringify(hints) +
|
||||
") ==" +
|
||||
" (expected: " +
|
||||
JSON.stringify(expected) +
|
||||
")"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,15 +12,25 @@ function testChildAtPoint(aID, aX, aY, aChildID, aGrandChildID) {
|
|||
var child = getChildAtPoint(aID, aX, aY, false);
|
||||
var expectedChild = getAccessible(aChildID);
|
||||
|
||||
var msg = "Wrong direct child accessible at the point (" + aX + ", " + aY +
|
||||
") of " + prettyName(aID);
|
||||
var msg =
|
||||
"Wrong direct child accessible at the point (" +
|
||||
aX +
|
||||
", " +
|
||||
aY +
|
||||
") of " +
|
||||
prettyName(aID);
|
||||
isObject(child, expectedChild, msg);
|
||||
|
||||
var grandChild = getChildAtPoint(aID, aX, aY, true);
|
||||
var expectedGrandChild = getAccessible(aGrandChildID);
|
||||
|
||||
msg = "Wrong deepest child accessible at the point (" + aX + ", " + aY +
|
||||
") of " + prettyName(aID);
|
||||
msg =
|
||||
"Wrong deepest child accessible at the point (" +
|
||||
aX +
|
||||
", " +
|
||||
aY +
|
||||
") of " +
|
||||
prettyName(aID);
|
||||
isObject(grandChild, expectedGrandChild, msg);
|
||||
}
|
||||
|
||||
|
@ -36,12 +46,18 @@ function hitTest(aContainerID, aChildID, aGrandChildID) {
|
|||
var [x, y] = getBoundsForDOMElm(child);
|
||||
|
||||
var actualChild = container.getChildAtPoint(x + 1, y + 1);
|
||||
isObject(actualChild, child,
|
||||
"Wrong direct child of " + prettyName(aContainerID));
|
||||
isObject(
|
||||
actualChild,
|
||||
child,
|
||||
"Wrong direct child of " + prettyName(aContainerID)
|
||||
);
|
||||
|
||||
var actualGrandChild = container.getDeepestChildAtPoint(x + 1, y + 1);
|
||||
isObject(actualGrandChild, grandChild,
|
||||
"Wrong deepest child of " + prettyName(aContainerID));
|
||||
isObject(
|
||||
actualGrandChild,
|
||||
grandChild,
|
||||
"Wrong deepest child of " + prettyName(aContainerID)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,9 +66,16 @@ function hitTest(aContainerID, aChildID, aGrandChildID) {
|
|||
function testOffsetAtPoint(aHyperTextID, aX, aY, aCoordType, aExpectedOffset) {
|
||||
var hyperText = getAccessible(aHyperTextID, [nsIAccessibleText]);
|
||||
var offset = hyperText.getOffsetAtPoint(aX, aY, aCoordType);
|
||||
is(offset, aExpectedOffset,
|
||||
"Wrong offset at given point (" + aX + ", " + aY + ") for " +
|
||||
prettyName(aHyperTextID));
|
||||
is(
|
||||
offset,
|
||||
aExpectedOffset,
|
||||
"Wrong offset at given point (" +
|
||||
aX +
|
||||
", " +
|
||||
aY +
|
||||
") for " +
|
||||
prettyName(aHyperTextID)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,8 +110,9 @@ function setResolution(aDocument, aZoom) {
|
|||
*/
|
||||
function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) {
|
||||
var acc = getAccessible(aIdentifier);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var [screenX, screenY] = getBoundsForDOMElm(acc.DOMNode);
|
||||
|
||||
|
@ -96,10 +120,11 @@ function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) {
|
|||
var y = screenY + aY;
|
||||
|
||||
try {
|
||||
if (aFindDeepestChild)
|
||||
if (aFindDeepestChild) {
|
||||
return acc.getDeepestChildAtPoint(x, y);
|
||||
}
|
||||
return acc.getChildAtPoint(x, y);
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -109,7 +134,7 @@ function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild) {
|
|||
*/
|
||||
function testPos(aID, aPoint) {
|
||||
var [expectedX, expectedY] =
|
||||
(aPoint != undefined) ? aPoint : getBoundsForDOMElm(aID);
|
||||
aPoint != undefined ? aPoint : getBoundsForDOMElm(aID);
|
||||
|
||||
var [x, y] = getBounds(aID);
|
||||
is(x, expectedX, "Wrong x coordinate of " + prettyName(aID));
|
||||
|
@ -121,7 +146,7 @@ function testPos(aID, aPoint) {
|
|||
*/
|
||||
function testBounds(aID, aRect) {
|
||||
var [expectedX, expectedY, expectedWidth, expectedHeight] =
|
||||
(aRect != undefined) ? aRect : getBoundsForDOMElm(aID);
|
||||
aRect != undefined ? aRect : getBoundsForDOMElm(aID);
|
||||
|
||||
var [x, y, width, height] = getBounds(aID);
|
||||
is(x, expectedX, "Wrong x coordinate of " + prettyName(aID));
|
||||
|
@ -136,15 +161,27 @@ function testBounds(aID, aRect) {
|
|||
function testTextPos(aID, aOffset, aPoint, aCoordOrigin) {
|
||||
var [expectedX, expectedY] = aPoint;
|
||||
|
||||
var xObj = {}, yObj = {};
|
||||
var xObj = {},
|
||||
yObj = {};
|
||||
var hyperText = getAccessible(aID, [nsIAccessibleText]);
|
||||
hyperText.getCharacterExtents(aOffset, xObj, yObj, {}, {}, aCoordOrigin);
|
||||
is(xObj.value, expectedX,
|
||||
"Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID));
|
||||
ok(yObj.value - expectedY < 2 && expectedY - yObj.value < 2,
|
||||
"Wrong y coordinate at offset " + aOffset + " for " + prettyName(aID) +
|
||||
" - got " + yObj.value + ", expected " + expectedY +
|
||||
"The difference doesn't exceed 1.");
|
||||
is(
|
||||
xObj.value,
|
||||
expectedX,
|
||||
"Wrong x coordinate at offset " + aOffset + " for " + prettyName(aID)
|
||||
);
|
||||
ok(
|
||||
yObj.value - expectedY < 2 && expectedY - yObj.value < 2,
|
||||
"Wrong y coordinate at offset " +
|
||||
aOffset +
|
||||
" for " +
|
||||
prettyName(aID) +
|
||||
" - got " +
|
||||
yObj.value +
|
||||
", expected " +
|
||||
expectedY +
|
||||
"The difference doesn't exceed 1."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,33 +190,64 @@ function testTextPos(aID, aOffset, aPoint, aCoordOrigin) {
|
|||
function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) {
|
||||
var [expectedX, expectedY, expectedWidth, expectedHeight] = aRect;
|
||||
|
||||
var xObj = {}, yObj = {}, widthObj = {}, heightObj = {};
|
||||
var xObj = {},
|
||||
yObj = {},
|
||||
widthObj = {},
|
||||
heightObj = {};
|
||||
var hyperText = getAccessible(aID, [nsIAccessibleText]);
|
||||
hyperText.getRangeExtents(aStartOffset, aEndOffset,
|
||||
xObj, yObj, widthObj, heightObj, aCoordOrigin);
|
||||
hyperText.getRangeExtents(
|
||||
aStartOffset,
|
||||
aEndOffset,
|
||||
xObj,
|
||||
yObj,
|
||||
widthObj,
|
||||
heightObj,
|
||||
aCoordOrigin
|
||||
);
|
||||
|
||||
// x
|
||||
is(xObj.value, expectedX,
|
||||
"Wrong x coordinate of text between offsets (" + aStartOffset + ", " +
|
||||
aEndOffset + ") for " + prettyName(aID));
|
||||
is(
|
||||
xObj.value,
|
||||
expectedX,
|
||||
"Wrong x coordinate of text between offsets (" +
|
||||
aStartOffset +
|
||||
", " +
|
||||
aEndOffset +
|
||||
") for " +
|
||||
prettyName(aID)
|
||||
);
|
||||
|
||||
// y
|
||||
isWithin(yObj.value, expectedY, 1,
|
||||
`y coord of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
|
||||
`for ${prettyName(aID)}`);
|
||||
isWithin(
|
||||
yObj.value,
|
||||
expectedY,
|
||||
1,
|
||||
`y coord of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
|
||||
`for ${prettyName(aID)}`
|
||||
);
|
||||
|
||||
// Width
|
||||
var msg = "Wrong width of text between offsets (" + aStartOffset + ", " +
|
||||
aEndOffset + ") for " + prettyName(aID);
|
||||
if (widthObj.value == expectedWidth)
|
||||
var msg =
|
||||
"Wrong width of text between offsets (" +
|
||||
aStartOffset +
|
||||
", " +
|
||||
aEndOffset +
|
||||
") for " +
|
||||
prettyName(aID);
|
||||
if (widthObj.value == expectedWidth) {
|
||||
ok(true, msg);
|
||||
else
|
||||
todo(false, msg); // fails on some windows machines
|
||||
} else {
|
||||
todo(false, msg);
|
||||
} // fails on some windows machines
|
||||
|
||||
// Height
|
||||
isWithin(heightObj.value, expectedHeight, 1,
|
||||
`height of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
|
||||
`for ${prettyName(aID)}`);
|
||||
isWithin(
|
||||
heightObj.value,
|
||||
expectedHeight,
|
||||
1,
|
||||
`height of text between offsets (${aStartOffset}, ${aEndOffset}) ` +
|
||||
`for ${prettyName(aID)}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,7 +255,8 @@ function testTextBounds(aID, aStartOffset, aEndOffset, aRect, aCoordOrigin) {
|
|||
*/
|
||||
function getPos(aID) {
|
||||
var accessible = getAccessible(aID);
|
||||
var x = {}, y = {};
|
||||
var x = {},
|
||||
y = {};
|
||||
accessible.getBounds(x, y, {}, {});
|
||||
return [x.value, y.value];
|
||||
}
|
||||
|
@ -199,28 +268,60 @@ function getPos(aID) {
|
|||
*/
|
||||
function getBounds(aID, aDPR = window.devicePixelRatio) {
|
||||
const accessible = getAccessible(aID);
|
||||
let x = {}, y = {}, width = {}, height = {};
|
||||
let xInCSS = {}, yInCSS = {}, widthInCSS = {}, heightInCSS = {};
|
||||
let x = {},
|
||||
y = {},
|
||||
width = {},
|
||||
height = {};
|
||||
let xInCSS = {},
|
||||
yInCSS = {},
|
||||
widthInCSS = {},
|
||||
heightInCSS = {};
|
||||
accessible.getBounds(x, y, width, height);
|
||||
accessible.getBoundsInCSSPixels(xInCSS, yInCSS, widthInCSS, heightInCSS);
|
||||
|
||||
isWithin(x.value / aDPR, xInCSS.value, 1,
|
||||
"Heights in CSS pixels is calculated correctly");
|
||||
isWithin(y.value / aDPR, yInCSS.value, 1,
|
||||
"Heights in CSS pixels is calculated correctly");
|
||||
isWithin(width.value / aDPR, widthInCSS.value, 1,
|
||||
"Heights in CSS pixels is calculated correctly");
|
||||
isWithin(height.value / aDPR, heightInCSS.value, 1,
|
||||
"Heights in CSS pixels is calculated correctly");
|
||||
isWithin(
|
||||
x.value / aDPR,
|
||||
xInCSS.value,
|
||||
1,
|
||||
"Heights in CSS pixels is calculated correctly"
|
||||
);
|
||||
isWithin(
|
||||
y.value / aDPR,
|
||||
yInCSS.value,
|
||||
1,
|
||||
"Heights in CSS pixels is calculated correctly"
|
||||
);
|
||||
isWithin(
|
||||
width.value / aDPR,
|
||||
widthInCSS.value,
|
||||
1,
|
||||
"Heights in CSS pixels is calculated correctly"
|
||||
);
|
||||
isWithin(
|
||||
height.value / aDPR,
|
||||
heightInCSS.value,
|
||||
1,
|
||||
"Heights in CSS pixels is calculated correctly"
|
||||
);
|
||||
|
||||
return [x.value, y.value, width.value, height.value];
|
||||
}
|
||||
|
||||
function getRangeExtents(aID, aStartOffset, aEndOffset, aCoordOrigin) {
|
||||
var hyperText = getAccessible(aID, [nsIAccessibleText]);
|
||||
var x = {}, y = {}, width = {}, height = {};
|
||||
hyperText.getRangeExtents(aStartOffset, aEndOffset,
|
||||
x, y, width, height, aCoordOrigin);
|
||||
var x = {},
|
||||
y = {},
|
||||
width = {},
|
||||
height = {};
|
||||
hyperText.getRangeExtents(
|
||||
aStartOffset,
|
||||
aEndOffset,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
aCoordOrigin
|
||||
);
|
||||
return [x.value, y.value, width.value, height.value];
|
||||
}
|
||||
|
||||
|
@ -229,7 +330,10 @@ function getRangeExtents(aID, aStartOffset, aEndOffset, aCoordOrigin) {
|
|||
* pixels.
|
||||
*/
|
||||
function getBoundsForDOMElm(aID) {
|
||||
var x = 0, y = 0, width = 0, height = 0;
|
||||
var x = 0,
|
||||
y = 0,
|
||||
width = 0,
|
||||
height = 0;
|
||||
|
||||
var elm = getNode(aID);
|
||||
if (elm.localName == "area") {
|
||||
|
@ -257,11 +361,13 @@ function getBoundsForDOMElm(aID) {
|
|||
}
|
||||
|
||||
var elmWindow = elm.ownerGlobal;
|
||||
return CSSToDevicePixels(elmWindow,
|
||||
x + elmWindow.mozInnerScreenX,
|
||||
y + elmWindow.mozInnerScreenY,
|
||||
width,
|
||||
height);
|
||||
return CSSToDevicePixels(
|
||||
elmWindow,
|
||||
x + elmWindow.mozInnerScreenX,
|
||||
y + elmWindow.mozInnerScreenY,
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) {
|
||||
|
@ -271,6 +377,10 @@ function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) {
|
|||
|
||||
// CSS pixels and ratio can be not integer. Device pixels are always integer.
|
||||
// Do our best and hope it works.
|
||||
return [ Math.round(aX * ratio), Math.round(aY * ratio),
|
||||
Math.round(aWidth * ratio), Math.round(aHeight * ratio) ];
|
||||
return [
|
||||
Math.round(aX * ratio),
|
||||
Math.round(aY * ratio),
|
||||
Math.round(aWidth * ratio),
|
||||
Math.round(aHeight * ratio),
|
||||
];
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@ function testName(aAccOrElmOrID, aName, aMsg, aTodo) {
|
|||
var msg = aMsg ? aMsg : "";
|
||||
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var func = aTodo ? todo_is : is;
|
||||
var txtID = prettyName(aAccOrElmOrID);
|
||||
|
@ -23,9 +24,13 @@ function testName(aAccOrElmOrID, aName, aMsg, aTodo) {
|
|||
*/
|
||||
function testDescr(aAccOrElmOrID, aDescr) {
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
if (!acc)
|
||||
return;
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
is(acc.description, aDescr,
|
||||
"Wrong description for " + prettyName(aAccOrElmOrID));
|
||||
is(
|
||||
acc.description,
|
||||
aDescr,
|
||||
"Wrong description for " + prettyName(aAccOrElmOrID)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -31,17 +31,20 @@ function testNames() {
|
|||
/**
|
||||
* Helper class to interate through name tests.
|
||||
*/
|
||||
var gTestIterator =
|
||||
{
|
||||
var gTestIterator = {
|
||||
iterateMarkups: function gTestIterator_iterateMarkups(aMarkupElms) {
|
||||
this.markupElms = aMarkupElms;
|
||||
|
||||
this.iterateNext();
|
||||
},
|
||||
|
||||
iterateRules: function gTestIterator_iterateRules(aElm, aContainer,
|
||||
aRuleSetElm, aRuleElms,
|
||||
aTestID) {
|
||||
iterateRules: function gTestIterator_iterateRules(
|
||||
aElm,
|
||||
aContainer,
|
||||
aRuleSetElm,
|
||||
aRuleElms,
|
||||
aTestID
|
||||
) {
|
||||
this.ruleSetElm = aRuleSetElm;
|
||||
this.ruleElms = aRuleElms;
|
||||
this.elm = aElm;
|
||||
|
@ -61,11 +64,15 @@ var gTestIterator =
|
|||
this.ruleIdx++;
|
||||
if (this.ruleIdx == this.ruleElms.length) {
|
||||
// When test is finished then name is empty and no explict-name.
|
||||
var defaultName = this.ruleSetElm.hasAttribute("defaultName") ?
|
||||
this.ruleSetElm.getAttribute("defaultName") : null;
|
||||
testName(this.elm, defaultName,
|
||||
"Default name test (" + gTestIterator.testID + "). ");
|
||||
testAbsentAttrs(this.elm, {"explicit-name": "true"});
|
||||
var defaultName = this.ruleSetElm.hasAttribute("defaultName")
|
||||
? this.ruleSetElm.getAttribute("defaultName")
|
||||
: null;
|
||||
testName(
|
||||
this.elm,
|
||||
defaultName,
|
||||
"Default name test (" + gTestIterator.testID + "). "
|
||||
);
|
||||
testAbsentAttrs(this.elm, { "explicit-name": "true" });
|
||||
|
||||
this.markupIdx++;
|
||||
if (this.markupIdx == this.markupElms.length) {
|
||||
|
@ -77,11 +84,19 @@ var gTestIterator =
|
|||
this.ruleIdx = -1;
|
||||
|
||||
if (gDumpToConsole) {
|
||||
dump("\nPend next markup processing. Wait for reorder event on " +
|
||||
prettyName(document) + "'\n");
|
||||
dump(
|
||||
"\nPend next markup processing. Wait for reorder event on " +
|
||||
prettyName(document) +
|
||||
"'\n"
|
||||
);
|
||||
}
|
||||
waitForEvent(EVENT_REORDER, document, testNamesForMarkup,
|
||||
null, this.markupElms[this.markupIdx]);
|
||||
waitForEvent(
|
||||
EVENT_REORDER,
|
||||
document,
|
||||
testNamesForMarkup,
|
||||
null,
|
||||
this.markupElms[this.markupIdx]
|
||||
);
|
||||
|
||||
document.body.removeChild(this.container);
|
||||
return;
|
||||
|
@ -105,8 +120,9 @@ var gTestIterator =
|
|||
* function.
|
||||
*/
|
||||
function testNamesForMarkup(aMarkupElm) {
|
||||
if (gDumpToConsole)
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessing markup '" + aMarkupElm.getAttribute("id") + "'\n");
|
||||
}
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("id", "test");
|
||||
|
@ -119,19 +135,29 @@ function testNamesForMarkup(aMarkupElm) {
|
|||
}
|
||||
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessing markup. Wait for reorder event on " +
|
||||
prettyName(document) + "'\n");
|
||||
dump(
|
||||
"\nProcessing markup. Wait for reorder event on " +
|
||||
prettyName(document) +
|
||||
"'\n"
|
||||
);
|
||||
}
|
||||
waitForEvent(EVENT_REORDER, document, testNamesForMarkupRules,
|
||||
null, aMarkupElm, div);
|
||||
waitForEvent(
|
||||
EVENT_REORDER,
|
||||
document,
|
||||
testNamesForMarkupRules,
|
||||
null,
|
||||
aMarkupElm,
|
||||
div
|
||||
);
|
||||
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
|
||||
function testNamesForMarkupRules(aMarkupElm, aContainer) {
|
||||
var testID = aMarkupElm.getAttribute("id");
|
||||
if (gDumpToConsole)
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessing markup rules '" + testID + "'\n");
|
||||
}
|
||||
|
||||
var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref");
|
||||
var elm = evaluateXPath(document, expr, htmlDocResolver)[0];
|
||||
|
@ -140,18 +166,24 @@ function testNamesForMarkupRules(aMarkupElm, aContainer) {
|
|||
var ruleElm = gRuleDoc.querySelector("[id='" + ruleId + "']");
|
||||
var ruleElms = getRuleElmsByRulesetId(ruleId);
|
||||
|
||||
var processMarkupRules =
|
||||
gTestIterator.iterateRules.bind(gTestIterator, elm, aContainer,
|
||||
ruleElm, ruleElms, testID);
|
||||
var processMarkupRules = gTestIterator.iterateRules.bind(
|
||||
gTestIterator,
|
||||
elm,
|
||||
aContainer,
|
||||
ruleElm,
|
||||
ruleElms,
|
||||
testID
|
||||
);
|
||||
|
||||
// Images may be recreated after we append them into subtree. We need to wait
|
||||
// in this case. If we are on profiling enabled build then stack tracing
|
||||
// works and thus let's log instead. Note, that works if you enabled logging
|
||||
// (refer to testNames() function).
|
||||
if (isAccessible(elm) || isLogged("stack"))
|
||||
if (isAccessible(elm) || isLogged("stack")) {
|
||||
processMarkupRules();
|
||||
else
|
||||
} else {
|
||||
waitForEvent(EVENT_SHOW, elm, processMarkupRules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,21 +193,31 @@ function testNamesForMarkupRules(aMarkupElm, aContainer) {
|
|||
function testNameForRule(aElm, aRuleElm) {
|
||||
if (aRuleElm.hasAttribute("attr")) {
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") + " }\n");
|
||||
dump(
|
||||
"\nProcessing rule { attr: " + aRuleElm.getAttribute("attr") + " }\n"
|
||||
);
|
||||
}
|
||||
|
||||
testNameForAttrRule(aElm, aRuleElm);
|
||||
} else if (aRuleElm.hasAttribute("elm")) {
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessing rule { elm: " + aRuleElm.getAttribute("elm") +
|
||||
", elmattr: " + aRuleElm.getAttribute("elmattr") + " }\n");
|
||||
dump(
|
||||
"\nProcessing rule { elm: " +
|
||||
aRuleElm.getAttribute("elm") +
|
||||
", elmattr: " +
|
||||
aRuleElm.getAttribute("elmattr") +
|
||||
" }\n"
|
||||
);
|
||||
}
|
||||
|
||||
testNameForElmRule(aElm, aRuleElm);
|
||||
} else if (aRuleElm.getAttribute("fromsubtree") == "true") {
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessing rule { fromsubtree: " +
|
||||
aRuleElm.getAttribute("fromsubtree") + " }\n");
|
||||
dump(
|
||||
"\nProcessing rule { fromsubtree: " +
|
||||
aRuleElm.getAttribute("fromsubtree") +
|
||||
" }\n"
|
||||
);
|
||||
}
|
||||
|
||||
testNameForSubtreeRule(aElm, aRuleElm);
|
||||
|
@ -195,8 +237,9 @@ function testNameForAttrRule(aElm, aRule) {
|
|||
var ids = attrValue.split(/\s+/);
|
||||
for (var idx = 0; idx < ids.length; idx++) {
|
||||
var labelElm = getNode(ids[idx]);
|
||||
if (name != "")
|
||||
if (name != "") {
|
||||
name += " ";
|
||||
}
|
||||
|
||||
name += labelElm.getAttribute("textequiv");
|
||||
}
|
||||
|
@ -205,25 +248,33 @@ function testNameForAttrRule(aElm, aRule) {
|
|||
var msg = "Attribute '" + attr + "' test (" + gTestIterator.testID + "). ";
|
||||
testName(aElm, name, msg);
|
||||
|
||||
if (aRule.getAttribute("explict-name") != "false")
|
||||
testAttrs(aElm, {"explicit-name": "true"}, true);
|
||||
else
|
||||
testAbsentAttrs(aElm, {"explicit-name": "true"});
|
||||
if (aRule.getAttribute("explict-name") != "false") {
|
||||
testAttrs(aElm, { "explicit-name": "true" }, true);
|
||||
} else {
|
||||
testAbsentAttrs(aElm, { "explicit-name": "true" });
|
||||
}
|
||||
|
||||
// If @recreated attribute is used then this attribute change recreates an
|
||||
// accessible. Wait for reorder event in this case or otherwise proceed next
|
||||
// test immediately.
|
||||
if (aRule.hasAttribute("recreated")) {
|
||||
waitForEvent(EVENT_REORDER, aElm.parentNode,
|
||||
gTestIterator.iterateNext, gTestIterator);
|
||||
waitForEvent(
|
||||
EVENT_REORDER,
|
||||
aElm.parentNode,
|
||||
gTestIterator.iterateNext,
|
||||
gTestIterator
|
||||
);
|
||||
aElm.removeAttribute(attr);
|
||||
} else if (aRule.hasAttribute("textchanged")) {
|
||||
waitForEvent(EVENT_TEXT_INSERTED, aElm,
|
||||
gTestIterator.iterateNext, gTestIterator);
|
||||
waitForEvent(
|
||||
EVENT_TEXT_INSERTED,
|
||||
aElm,
|
||||
gTestIterator.iterateNext,
|
||||
gTestIterator
|
||||
);
|
||||
aElm.removeAttribute(attr);
|
||||
} else if (aRule.hasAttribute("contentchanged")) {
|
||||
waitForEvent(EVENT_REORDER, aElm,
|
||||
gTestIterator.iterateNext, gTestIterator);
|
||||
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
|
||||
aElm.removeAttribute(attr);
|
||||
} else {
|
||||
aElm.removeAttribute(attr);
|
||||
|
@ -239,9 +290,12 @@ function testNameForElmRule(aElm, aRule) {
|
|||
if (attrname) {
|
||||
var filter = {
|
||||
acceptNode: function filter_acceptNode(aNode) {
|
||||
if (aNode.localName == this.mLocalName &&
|
||||
aNode.getAttribute(this.mAttrName) == this.mAttrValue)
|
||||
if (
|
||||
aNode.localName == this.mLocalName &&
|
||||
aNode.getAttribute(this.mAttrName) == this.mAttrValue
|
||||
) {
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
}
|
||||
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
},
|
||||
|
@ -251,15 +305,18 @@ function testNameForElmRule(aElm, aRule) {
|
|||
mAttrValue: aElm.getAttribute("id"),
|
||||
};
|
||||
|
||||
var treeWalker = document.createTreeWalker(document.body,
|
||||
NodeFilter.SHOW_ELEMENT,
|
||||
filter);
|
||||
var treeWalker = document.createTreeWalker(
|
||||
document.body,
|
||||
NodeFilter.SHOW_ELEMENT,
|
||||
filter
|
||||
);
|
||||
labelElm = treeWalker.nextNode();
|
||||
} else {
|
||||
// if attrname is empty then look for the element in subtree.
|
||||
labelElm = aElm.getElementsByTagName(tagname)[0];
|
||||
if (!labelElm)
|
||||
if (!labelElm) {
|
||||
labelElm = aElm.getElementsByTagName("html:" + tagname)[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!labelElm) {
|
||||
|
@ -270,16 +327,23 @@ function testNameForElmRule(aElm, aRule) {
|
|||
|
||||
var msg = "Element '" + tagname + "' test (" + gTestIterator.testID + ").";
|
||||
testName(aElm, labelElm.getAttribute("textequiv"), msg);
|
||||
testAttrs(aElm, {"explicit-name": "true"}, true);
|
||||
testAttrs(aElm, { "explicit-name": "true" }, true);
|
||||
|
||||
var parentNode = labelElm.parentNode;
|
||||
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessed elm rule. Wait for reorder event on " +
|
||||
prettyName(parentNode) + "\n");
|
||||
dump(
|
||||
"\nProcessed elm rule. Wait for reorder event on " +
|
||||
prettyName(parentNode) +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
waitForEvent(EVENT_REORDER, parentNode,
|
||||
gTestIterator.iterateNext, gTestIterator);
|
||||
waitForEvent(
|
||||
EVENT_REORDER,
|
||||
parentNode,
|
||||
gTestIterator.iterateNext,
|
||||
gTestIterator
|
||||
);
|
||||
|
||||
parentNode.removeChild(labelElm);
|
||||
}
|
||||
|
@ -287,16 +351,20 @@ function testNameForElmRule(aElm, aRule) {
|
|||
function testNameForSubtreeRule(aElm, aRule) {
|
||||
var msg = "From subtree test (" + gTestIterator.testID + ").";
|
||||
testName(aElm, aElm.getAttribute("textequiv"), msg);
|
||||
testAbsentAttrs(aElm, {"explicit-name": "true"});
|
||||
testAbsentAttrs(aElm, { "explicit-name": "true" });
|
||||
|
||||
if (gDumpToConsole) {
|
||||
dump("\nProcessed from subtree rule. Wait for reorder event on " +
|
||||
prettyName(aElm) + "\n");
|
||||
dump(
|
||||
"\nProcessed from subtree rule. Wait for reorder event on " +
|
||||
prettyName(aElm) +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
|
||||
|
||||
while (aElm.firstChild)
|
||||
while (aElm.firstChild) {
|
||||
aElm.firstChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -311,17 +379,20 @@ function getRuleElmsByRulesetId(aRulesetId) {
|
|||
|
||||
function getRuleElmsFromRulesetElm(aRulesetElm) {
|
||||
var rulesetId = aRulesetElm.getAttribute("ref");
|
||||
if (rulesetId)
|
||||
if (rulesetId) {
|
||||
return getRuleElmsByRulesetId(rulesetId);
|
||||
}
|
||||
|
||||
var ruleElms = [];
|
||||
|
||||
var child = aRulesetElm.firstChild;
|
||||
while (child) {
|
||||
if (child.localName == "ruleset")
|
||||
if (child.localName == "ruleset") {
|
||||
ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
|
||||
if (child.localName == "rule")
|
||||
}
|
||||
if (child.localName == "rule") {
|
||||
ruleElms.push(child);
|
||||
}
|
||||
|
||||
child = child.nextSibling;
|
||||
}
|
||||
|
@ -337,23 +408,26 @@ function evaluateXPath(aNode, aExpr, aResolver) {
|
|||
|
||||
var resolver = aResolver;
|
||||
if (!resolver) {
|
||||
var node = aNode.ownerDocument == null ?
|
||||
aNode.documentElement : aNode.ownerDocument.documentElement;
|
||||
var node =
|
||||
aNode.ownerDocument == null
|
||||
? aNode.documentElement
|
||||
: aNode.ownerDocument.documentElement;
|
||||
resolver = xpe.createNSResolver(node);
|
||||
}
|
||||
|
||||
var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
|
||||
var found = [];
|
||||
var res;
|
||||
while ((res = result.iterateNext()))
|
||||
while ((res = result.iterateNext())) {
|
||||
found.push(res);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
function htmlDocResolver(aPrefix) {
|
||||
var ns = {
|
||||
"html": "http://www.w3.org/1999/xhtml",
|
||||
html: "http://www.w3.org/1999/xhtml",
|
||||
};
|
||||
return ns[aPrefix] || null;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,7 @@ const NS_ERROR_INVALID_ARG = 0x80070057;
|
|||
/**
|
||||
* Rule object to traverse all focusable nodes and text nodes.
|
||||
*/
|
||||
var HeadersTraversalRule =
|
||||
{
|
||||
var HeadersTraversalRule = {
|
||||
getMatchRoles() {
|
||||
return [ROLE_HEADING];
|
||||
},
|
||||
|
@ -39,8 +38,7 @@ var HeadersTraversalRule =
|
|||
/**
|
||||
* Traversal rule for all focusable nodes or leafs.
|
||||
*/
|
||||
var ObjectTraversalRule =
|
||||
{
|
||||
var ObjectTraversalRule = {
|
||||
getMatchRoles() {
|
||||
return [];
|
||||
},
|
||||
|
@ -50,12 +48,18 @@ var ObjectTraversalRule =
|
|||
match(aAccessible) {
|
||||
var rv = FILTER_IGNORE;
|
||||
var role = aAccessible.role;
|
||||
if (hasState(aAccessible, STATE_FOCUSABLE) &&
|
||||
(role != ROLE_DOCUMENT && role != ROLE_INTERNAL_FRAME))
|
||||
if (
|
||||
hasState(aAccessible, STATE_FOCUSABLE) &&
|
||||
(role != ROLE_DOCUMENT && role != ROLE_INTERNAL_FRAME)
|
||||
) {
|
||||
rv = FILTER_IGNORE_SUBTREE | FILTER_MATCH;
|
||||
else if (aAccessible.childCount == 0 &&
|
||||
role != ROLE_STATICTEXT && aAccessible.name.trim())
|
||||
} else if (
|
||||
aAccessible.childCount == 0 &&
|
||||
role != ROLE_STATICTEXT &&
|
||||
aAccessible.name.trim()
|
||||
) {
|
||||
rv = FILTER_MATCH;
|
||||
}
|
||||
|
||||
return rv;
|
||||
},
|
||||
|
@ -69,8 +73,14 @@ var ObjectTraversalRule =
|
|||
/**
|
||||
* A checker for virtual cursor changed events.
|
||||
*/
|
||||
function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMethod,
|
||||
aIsFromUserInput, aBoundaryType = NO_BOUNDARY) {
|
||||
function VCChangedChecker(
|
||||
aDocAcc,
|
||||
aIdOrNameOrAcc,
|
||||
aTextOffsets,
|
||||
aPivotMoveMethod,
|
||||
aIsFromUserInput,
|
||||
aBoundaryType = NO_BOUNDARY
|
||||
) {
|
||||
this.__proto__ = new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc);
|
||||
|
||||
this.match = function VCChangedChecker_match(aEvent) {
|
||||
|
@ -81,11 +91,13 @@ function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMetho
|
|||
return false;
|
||||
}
|
||||
|
||||
var expectedReason = VCChangedChecker.methodReasonMap[aPivotMoveMethod] ||
|
||||
var expectedReason =
|
||||
VCChangedChecker.methodReasonMap[aPivotMoveMethod] ||
|
||||
nsIAccessiblePivot.REASON_NONE;
|
||||
|
||||
return event.reason == expectedReason &&
|
||||
event.boundaryType == aBoundaryType;
|
||||
return (
|
||||
event.reason == expectedReason && event.boundaryType == aBoundaryType
|
||||
);
|
||||
};
|
||||
|
||||
this.check = function VCChangedChecker_check(aEvent) {
|
||||
|
@ -103,65 +115,100 @@ function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMetho
|
|||
var nameMatches = position && position.name == aIdOrNameOrAcc;
|
||||
var accMatches = position == aIdOrNameOrAcc;
|
||||
|
||||
SimpleTest.ok(idMatches || nameMatches || accMatches,
|
||||
"id or name matches - expecting " +
|
||||
prettyName(aIdOrNameOrAcc) + ", got '" + prettyName(position));
|
||||
SimpleTest.ok(
|
||||
idMatches || nameMatches || accMatches,
|
||||
"id or name matches - expecting " +
|
||||
prettyName(aIdOrNameOrAcc) +
|
||||
", got '" +
|
||||
prettyName(position)
|
||||
);
|
||||
|
||||
SimpleTest.is(aEvent.isFromUserInput, aIsFromUserInput,
|
||||
"Expected user input is " + aIsFromUserInput + "\n");
|
||||
SimpleTest.is(
|
||||
aEvent.isFromUserInput,
|
||||
aIsFromUserInput,
|
||||
"Expected user input is " + aIsFromUserInput + "\n"
|
||||
);
|
||||
|
||||
SimpleTest.is(event.newAccessible, position,
|
||||
"new position in event is incorrect");
|
||||
SimpleTest.is(
|
||||
event.newAccessible,
|
||||
position,
|
||||
"new position in event is incorrect"
|
||||
);
|
||||
|
||||
if (aTextOffsets) {
|
||||
SimpleTest.is(aDocAcc.virtualCursor.startOffset, aTextOffsets[0],
|
||||
"wrong start offset");
|
||||
SimpleTest.is(aDocAcc.virtualCursor.endOffset, aTextOffsets[1],
|
||||
"wrong end offset");
|
||||
SimpleTest.is(event.newStartOffset, aTextOffsets[0],
|
||||
"wrong start offset in event");
|
||||
SimpleTest.is(event.newEndOffset, aTextOffsets[1],
|
||||
"wrong end offset in event");
|
||||
SimpleTest.is(
|
||||
aDocAcc.virtualCursor.startOffset,
|
||||
aTextOffsets[0],
|
||||
"wrong start offset"
|
||||
);
|
||||
SimpleTest.is(
|
||||
aDocAcc.virtualCursor.endOffset,
|
||||
aTextOffsets[1],
|
||||
"wrong end offset"
|
||||
);
|
||||
SimpleTest.is(
|
||||
event.newStartOffset,
|
||||
aTextOffsets[0],
|
||||
"wrong start offset in event"
|
||||
);
|
||||
SimpleTest.is(
|
||||
event.newEndOffset,
|
||||
aTextOffsets[1],
|
||||
"wrong end offset in event"
|
||||
);
|
||||
}
|
||||
|
||||
var prevPosAndOffset = VCChangedChecker.
|
||||
getPreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
var prevPosAndOffset = VCChangedChecker.getPreviousPosAndOffset(
|
||||
aDocAcc.virtualCursor
|
||||
);
|
||||
|
||||
if (prevPosAndOffset) {
|
||||
SimpleTest.is(event.oldAccessible, prevPosAndOffset.position,
|
||||
"previous position does not match");
|
||||
SimpleTest.is(event.oldStartOffset, prevPosAndOffset.startOffset,
|
||||
"previous start offset does not match");
|
||||
SimpleTest.is(event.oldEndOffset, prevPosAndOffset.endOffset,
|
||||
"previous end offset does not match");
|
||||
SimpleTest.is(
|
||||
event.oldAccessible,
|
||||
prevPosAndOffset.position,
|
||||
"previous position does not match"
|
||||
);
|
||||
SimpleTest.is(
|
||||
event.oldStartOffset,
|
||||
prevPosAndOffset.startOffset,
|
||||
"previous start offset does not match"
|
||||
);
|
||||
SimpleTest.is(
|
||||
event.oldEndOffset,
|
||||
prevPosAndOffset.endOffset,
|
||||
"previous end offset does not match"
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
VCChangedChecker.prevPosAndOffset = {};
|
||||
|
||||
VCChangedChecker.storePreviousPosAndOffset =
|
||||
function storePreviousPosAndOffset(aPivot) {
|
||||
VCChangedChecker.prevPosAndOffset[aPivot] =
|
||||
{position: aPivot.position,
|
||||
startOffset: aPivot.startOffset,
|
||||
endOffset: aPivot.endOffset};
|
||||
VCChangedChecker.storePreviousPosAndOffset = function storePreviousPosAndOffset(
|
||||
aPivot
|
||||
) {
|
||||
VCChangedChecker.prevPosAndOffset[aPivot] = {
|
||||
position: aPivot.position,
|
||||
startOffset: aPivot.startOffset,
|
||||
endOffset: aPivot.endOffset,
|
||||
};
|
||||
};
|
||||
|
||||
VCChangedChecker.getPreviousPosAndOffset =
|
||||
function getPreviousPosAndOffset(aPivot) {
|
||||
VCChangedChecker.getPreviousPosAndOffset = function getPreviousPosAndOffset(
|
||||
aPivot
|
||||
) {
|
||||
return VCChangedChecker.prevPosAndOffset[aPivot];
|
||||
};
|
||||
|
||||
VCChangedChecker.methodReasonMap = {
|
||||
"moveNext": nsIAccessiblePivot.REASON_NEXT,
|
||||
"movePrevious": nsIAccessiblePivot.REASON_PREV,
|
||||
"moveFirst": nsIAccessiblePivot.REASON_FIRST,
|
||||
"moveLast": nsIAccessiblePivot.REASON_LAST,
|
||||
"setTextRange": nsIAccessiblePivot.REASON_NONE,
|
||||
"moveNextByText": nsIAccessiblePivot.REASON_NEXT,
|
||||
"movePreviousByText": nsIAccessiblePivot.REASON_PREV,
|
||||
"moveToPoint": nsIAccessiblePivot.REASON_POINT,
|
||||
moveNext: nsIAccessiblePivot.REASON_NEXT,
|
||||
movePrevious: nsIAccessiblePivot.REASON_PREV,
|
||||
moveFirst: nsIAccessiblePivot.REASON_FIRST,
|
||||
moveLast: nsIAccessiblePivot.REASON_LAST,
|
||||
setTextRange: nsIAccessiblePivot.REASON_NONE,
|
||||
moveNextByText: nsIAccessiblePivot.REASON_NEXT,
|
||||
movePreviousByText: nsIAccessiblePivot.REASON_PREV,
|
||||
moveToPoint: nsIAccessiblePivot.REASON_POINT,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -174,21 +221,35 @@ VCChangedChecker.methodReasonMap = {
|
|||
*/
|
||||
function setVCRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets) {
|
||||
this.invoke = function virtualCursorChangedInvoker_invoke() {
|
||||
VCChangedChecker.
|
||||
storePreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
SimpleTest.info(prettyName(aTextAccessible) + " " + aTextOffsets);
|
||||
aDocAcc.virtualCursor.setTextRange(aTextAccessible,
|
||||
aTextOffsets[0],
|
||||
aTextOffsets[1]);
|
||||
aDocAcc.virtualCursor.setTextRange(
|
||||
aTextAccessible,
|
||||
aTextOffsets[0],
|
||||
aTextOffsets[1]
|
||||
);
|
||||
};
|
||||
|
||||
this.getID = function setVCRangeInvoker_getID() {
|
||||
return "Set offset in " + prettyName(aTextAccessible) +
|
||||
" to (" + aTextOffsets[0] + ", " + aTextOffsets[1] + ")";
|
||||
return (
|
||||
"Set offset in " +
|
||||
prettyName(aTextAccessible) +
|
||||
" to (" +
|
||||
aTextOffsets[0] +
|
||||
", " +
|
||||
aTextOffsets[1] +
|
||||
")"
|
||||
);
|
||||
};
|
||||
|
||||
this.eventSeq = [
|
||||
new VCChangedChecker(aDocAcc, aTextAccessible, aTextOffsets, "setTextRange", true),
|
||||
new VCChangedChecker(
|
||||
aDocAcc,
|
||||
aTextAccessible,
|
||||
aTextOffsets,
|
||||
"setTextRange",
|
||||
true
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -204,31 +265,42 @@ function setVCRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets) {
|
|||
* @param aIsFromUserInput [in] set user input flag when invoking method, and
|
||||
* expect it in the event.
|
||||
*/
|
||||
function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc,
|
||||
aIsFromUserInput) {
|
||||
function setVCPosInvoker(
|
||||
aDocAcc,
|
||||
aPivotMoveMethod,
|
||||
aRule,
|
||||
aIdOrNameOrAcc,
|
||||
aIsFromUserInput
|
||||
) {
|
||||
// eslint-disable-next-line mozilla/no-compare-against-boolean-literals
|
||||
var expectMove = aIdOrNameOrAcc != false;
|
||||
this.invoke = function virtualCursorChangedInvoker_invoke() {
|
||||
VCChangedChecker.
|
||||
storePreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
if (aPivotMoveMethod && aRule) {
|
||||
var moved = false;
|
||||
switch (aPivotMoveMethod) {
|
||||
case "moveFirst":
|
||||
case "moveLast":
|
||||
moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule,
|
||||
aIsFromUserInput === undefined ? true : aIsFromUserInput);
|
||||
moved = aDocAcc.virtualCursor[aPivotMoveMethod](
|
||||
aRule,
|
||||
aIsFromUserInput === undefined ? true : aIsFromUserInput
|
||||
);
|
||||
break;
|
||||
case "moveNext":
|
||||
case "movePrevious":
|
||||
moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule,
|
||||
aDocAcc.virtualCursor.position, false,
|
||||
aIsFromUserInput === undefined ? true : aIsFromUserInput);
|
||||
moved = aDocAcc.virtualCursor[aPivotMoveMethod](
|
||||
aRule,
|
||||
aDocAcc.virtualCursor.position,
|
||||
false,
|
||||
aIsFromUserInput === undefined ? true : aIsFromUserInput
|
||||
);
|
||||
break;
|
||||
}
|
||||
SimpleTest.is(!!moved, !!expectMove,
|
||||
"moved pivot with " + aPivotMoveMethod +
|
||||
" to " + aIdOrNameOrAcc);
|
||||
SimpleTest.is(
|
||||
!!moved,
|
||||
!!expectMove,
|
||||
"moved pivot with " + aPivotMoveMethod + " to " + aIdOrNameOrAcc
|
||||
);
|
||||
} else {
|
||||
aDocAcc.virtualCursor.position = getAccessible(aIdOrNameOrAcc);
|
||||
}
|
||||
|
@ -240,8 +312,13 @@ function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc,
|
|||
|
||||
if (expectMove) {
|
||||
this.eventSeq = [
|
||||
new VCChangedChecker(aDocAcc, aIdOrNameOrAcc, null, aPivotMoveMethod,
|
||||
aIsFromUserInput === undefined ? !!aPivotMoveMethod : aIsFromUserInput),
|
||||
new VCChangedChecker(
|
||||
aDocAcc,
|
||||
aIdOrNameOrAcc,
|
||||
null,
|
||||
aPivotMoveMethod,
|
||||
aIsFromUserInput === undefined ? !!aPivotMoveMethod : aIsFromUserInput
|
||||
),
|
||||
];
|
||||
} else {
|
||||
this.eventSeq = [];
|
||||
|
@ -265,30 +342,55 @@ function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc,
|
|||
* @param aIsFromUserInput [in] set user input flag when invoking method, and
|
||||
* expect it in the event.
|
||||
*/
|
||||
function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets,
|
||||
aIdOrNameOrAcc, aIsFromUserInput) {
|
||||
function setVCTextInvoker(
|
||||
aDocAcc,
|
||||
aPivotMoveMethod,
|
||||
aBoundary,
|
||||
aTextOffsets,
|
||||
aIdOrNameOrAcc,
|
||||
aIsFromUserInput
|
||||
) {
|
||||
// eslint-disable-next-line mozilla/no-compare-against-boolean-literals
|
||||
var expectMove = aIdOrNameOrAcc != false;
|
||||
this.invoke = function virtualCursorChangedInvoker_invoke() {
|
||||
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
SimpleTest.info(aDocAcc.virtualCursor.position);
|
||||
var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aBoundary,
|
||||
aIsFromUserInput === undefined);
|
||||
SimpleTest.is(!!moved, !!expectMove,
|
||||
"moved pivot by text with " + aPivotMoveMethod +
|
||||
" to " + aIdOrNameOrAcc);
|
||||
var moved = aDocAcc.virtualCursor[aPivotMoveMethod](
|
||||
aBoundary,
|
||||
aIsFromUserInput === undefined
|
||||
);
|
||||
SimpleTest.is(
|
||||
!!moved,
|
||||
!!expectMove,
|
||||
"moved pivot by text with " + aPivotMoveMethod + " to " + aIdOrNameOrAcc
|
||||
);
|
||||
};
|
||||
|
||||
this.getID = function setVCPosInvoker_getID() {
|
||||
return "Do " + (expectMove ? "" : "no-op ") + aPivotMoveMethod + " in " +
|
||||
prettyName(aIdOrNameOrAcc) + ", " + boundaryToString(aBoundary) +
|
||||
", [" + aTextOffsets + "]";
|
||||
return (
|
||||
"Do " +
|
||||
(expectMove ? "" : "no-op ") +
|
||||
aPivotMoveMethod +
|
||||
" in " +
|
||||
prettyName(aIdOrNameOrAcc) +
|
||||
", " +
|
||||
boundaryToString(aBoundary) +
|
||||
", [" +
|
||||
aTextOffsets +
|
||||
"]"
|
||||
);
|
||||
};
|
||||
|
||||
if (expectMove) {
|
||||
this.eventSeq = [
|
||||
new VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets, aPivotMoveMethod,
|
||||
aIsFromUserInput === undefined ? true : aIsFromUserInput, aBoundary),
|
||||
new VCChangedChecker(
|
||||
aDocAcc,
|
||||
aIdOrNameOrAcc,
|
||||
aTextOffsets,
|
||||
aPivotMoveMethod,
|
||||
aIsFromUserInput === undefined ? true : aIsFromUserInput,
|
||||
aBoundary
|
||||
),
|
||||
];
|
||||
} else {
|
||||
this.eventSeq = [];
|
||||
|
@ -298,7 +400,6 @@ function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move the pivot to the position under the point.
|
||||
*
|
||||
|
@ -312,21 +413,34 @@ function setVCTextInvoker(aDocAcc, aPivotMoveMethod, aBoundary, aTextOffsets,
|
|||
* virtual cursor to land on after performing move method.
|
||||
* false if no move is expected.
|
||||
*/
|
||||
function moveVCCoordInvoker(aDocAcc, aX, aY, aIgnoreNoMatch,
|
||||
aRule, aIdOrNameOrAcc) {
|
||||
function moveVCCoordInvoker(
|
||||
aDocAcc,
|
||||
aX,
|
||||
aY,
|
||||
aIgnoreNoMatch,
|
||||
aRule,
|
||||
aIdOrNameOrAcc
|
||||
) {
|
||||
// eslint-disable-next-line mozilla/no-compare-against-boolean-literals
|
||||
var expectMove = aIdOrNameOrAcc != false;
|
||||
this.invoke = function virtualCursorChangedInvoker_invoke() {
|
||||
VCChangedChecker.
|
||||
storePreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
var moved = aDocAcc.virtualCursor.moveToPoint(aRule, aX, aY,
|
||||
aIgnoreNoMatch);
|
||||
SimpleTest.ok((expectMove && moved) || (!expectMove && !moved),
|
||||
"moved pivot");
|
||||
VCChangedChecker.storePreviousPosAndOffset(aDocAcc.virtualCursor);
|
||||
var moved = aDocAcc.virtualCursor.moveToPoint(
|
||||
aRule,
|
||||
aX,
|
||||
aY,
|
||||
aIgnoreNoMatch
|
||||
);
|
||||
SimpleTest.ok(
|
||||
(expectMove && moved) || (!expectMove && !moved),
|
||||
"moved pivot"
|
||||
);
|
||||
};
|
||||
|
||||
this.getID = function setVCPosInvoker_getID() {
|
||||
return "Do " + (expectMove ? "" : "no-op ") + "moveToPoint " + aIdOrNameOrAcc;
|
||||
return (
|
||||
"Do " + (expectMove ? "" : "no-op ") + "moveToPoint " + aIdOrNameOrAcc
|
||||
);
|
||||
};
|
||||
|
||||
if (expectMove) {
|
||||
|
@ -355,12 +469,17 @@ function setModalRootInvoker(aDocAcc, aModalRootAcc, aExpectedResult) {
|
|||
aDocAcc.virtualCursor.modalRoot = aModalRootAcc;
|
||||
} catch (x) {
|
||||
SimpleTest.ok(
|
||||
x.result, "Unexpected exception when changing modal root: " + x);
|
||||
x.result,
|
||||
"Unexpected exception when changing modal root: " + x
|
||||
);
|
||||
errorResult = x.result;
|
||||
}
|
||||
|
||||
SimpleTest.is(errorResult, aExpectedResult,
|
||||
"Did not get expected result when changing modalRoot");
|
||||
SimpleTest.is(
|
||||
errorResult,
|
||||
aExpectedResult,
|
||||
"Did not get expected result when changing modalRoot"
|
||||
);
|
||||
};
|
||||
|
||||
this.getID = function setModalRootInvoker_getID() {
|
||||
|
@ -394,8 +513,7 @@ function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence) {
|
|||
aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0]));
|
||||
|
||||
for (let i = 1; i < aSequence.length; i++) {
|
||||
let invoker =
|
||||
new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
|
||||
let invoker = new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
|
||||
aQueue.push(invoker);
|
||||
}
|
||||
|
||||
|
@ -403,22 +521,34 @@ function queueTraversalSequence(aQueue, aDocAcc, aRule, aModalRoot, aSequence) {
|
|||
aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false));
|
||||
|
||||
for (let i = aSequence.length - 2; i >= 0; i--) {
|
||||
let invoker =
|
||||
new setVCPosInvoker(aDocAcc, "movePrevious", aRule, aSequence[i]);
|
||||
let invoker = new setVCPosInvoker(
|
||||
aDocAcc,
|
||||
"movePrevious",
|
||||
aRule,
|
||||
aSequence[i]
|
||||
);
|
||||
aQueue.push(invoker);
|
||||
}
|
||||
|
||||
// No previous more matches for given rule, expect no virtual cursor changes.
|
||||
aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false));
|
||||
|
||||
aQueue.push(new setVCPosInvoker(aDocAcc, "moveLast", aRule,
|
||||
aSequence[aSequence.length - 1]));
|
||||
aQueue.push(
|
||||
new setVCPosInvoker(
|
||||
aDocAcc,
|
||||
"moveLast",
|
||||
aRule,
|
||||
aSequence[aSequence.length - 1]
|
||||
)
|
||||
);
|
||||
|
||||
// No further more matches for given rule, expect no virtual cursor changes.
|
||||
aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, false));
|
||||
|
||||
// set isFromUserInput to false, just to test..
|
||||
aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0], false));
|
||||
aQueue.push(
|
||||
new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0], false)
|
||||
);
|
||||
|
||||
// No previous more matches for given rule, expect no virtual cursor changes.
|
||||
aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, false));
|
||||
|
@ -441,8 +571,10 @@ function removeVCPositionChecker(aDocAcc, aHiddenParentAcc) {
|
|||
errorResult = x.result;
|
||||
}
|
||||
SimpleTest.is(
|
||||
errorResult, NS_ERROR_NOT_IN_TREE,
|
||||
"Expecting NOT_IN_TREE error when moving pivot from invalid position.");
|
||||
errorResult,
|
||||
NS_ERROR_NOT_IN_TREE,
|
||||
"Expecting NOT_IN_TREE error when moving pivot from invalid position."
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -484,8 +616,10 @@ function removeVCRootChecker(aPivot) {
|
|||
errorResult = x.result;
|
||||
}
|
||||
SimpleTest.is(
|
||||
errorResult, NS_ERROR_NOT_IN_TREE,
|
||||
"Expecting NOT_IN_TREE error when moving pivot from invalid position.");
|
||||
errorResult,
|
||||
NS_ERROR_NOT_IN_TREE,
|
||||
"Expecting NOT_IN_TREE error when moving pivot from invalid position."
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -507,9 +641,7 @@ function removeVCRootInvoker(aRootNode) {
|
|||
return "Remove root of pivot from tree.";
|
||||
};
|
||||
|
||||
this.eventSeq = [
|
||||
new removeVCRootChecker(this.pivot),
|
||||
];
|
||||
this.eventSeq = [new removeVCRootChecker(this.pivot)];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,9 +18,12 @@ var RELATION_NODE_PARENT_OF = nsIAccessibleRelation.RELATION_NODE_PARENT_OF;
|
|||
var RELATION_PARENT_WINDOW_OF = nsIAccessibleRelation.RELATION_PARENT_WINDOW_OF;
|
||||
var RELATION_POPUP_FOR = nsIAccessibleRelation.RELATION_POPUP_FOR;
|
||||
var RELATION_SUBWINDOW_OF = nsIAccessibleRelation.RELATION_SUBWINDOW_OF;
|
||||
var RELATION_CONTAINING_DOCUMENT = nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT;
|
||||
var RELATION_CONTAINING_TAB_PANE = nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE;
|
||||
var RELATION_CONTAINING_APPLICATION = nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION;
|
||||
var RELATION_CONTAINING_DOCUMENT =
|
||||
nsIAccessibleRelation.RELATION_CONTAINING_DOCUMENT;
|
||||
var RELATION_CONTAINING_TAB_PANE =
|
||||
nsIAccessibleRelation.RELATION_CONTAINING_TAB_PANE;
|
||||
var RELATION_CONTAINING_APPLICATION =
|
||||
nsIAccessibleRelation.RELATION_CONTAINING_APPLICATION;
|
||||
const RELATION_DETAILS = nsIAccessibleRelation.RELATION_DETAILS;
|
||||
const RELATION_DETAILS_FOR = nsIAccessibleRelation.RELATION_DETAILS_FOR;
|
||||
const RELATION_ERRORMSG = nsIAccessibleRelation.RELATION_ERRORMSG;
|
||||
|
@ -50,8 +53,11 @@ function testRelation(aIdentifier, aRelType, aRelatedIdentifiers) {
|
|||
return;
|
||||
}
|
||||
|
||||
var msg = relDescrStart + "has no expected targets: '" +
|
||||
prettyName(aRelatedIdentifiers) + "'";
|
||||
var msg =
|
||||
relDescrStart +
|
||||
"has no expected targets: '" +
|
||||
prettyName(aRelatedIdentifiers) +
|
||||
"'";
|
||||
|
||||
ok(false, msg);
|
||||
return;
|
||||
|
@ -60,15 +66,19 @@ function testRelation(aIdentifier, aRelType, aRelatedIdentifiers) {
|
|||
return;
|
||||
}
|
||||
|
||||
var relatedIds = (aRelatedIdentifiers instanceof Array) ?
|
||||
aRelatedIdentifiers : [aRelatedIdentifiers];
|
||||
var relatedIds =
|
||||
aRelatedIdentifiers instanceof Array
|
||||
? aRelatedIdentifiers
|
||||
: [aRelatedIdentifiers];
|
||||
|
||||
var targets = [];
|
||||
for (let idx = 0; idx < relatedIds.length; idx++)
|
||||
targets.push(getAccessible(relatedIds[idx]));
|
||||
for (let idx = 0; idx < relatedIds.length; idx++) {
|
||||
targets.push(getAccessible(relatedIds[idx]));
|
||||
}
|
||||
|
||||
if (targets.length != relatedIds.length)
|
||||
if (targets.length != relatedIds.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var actualTargets = relation.getTargets();
|
||||
|
||||
|
@ -88,10 +98,14 @@ function testRelation(aIdentifier, aRelType, aRelatedIdentifiers) {
|
|||
// Check if all obtained targets are given related accessibles.
|
||||
for (let relatedAcc of actualTargets.enumerate(Ci.nsIAccessible)) {
|
||||
let idx;
|
||||
for (idx = 0; idx < targets.length && relatedAcc != targets[idx]; idx++);
|
||||
for (idx = 0; idx < targets.length && relatedAcc != targets[idx]; idx++) {}
|
||||
|
||||
if (idx == targets.length)
|
||||
ok(false, "There is unexpected target" + prettyName(relatedAcc) + "of" + relDescr);
|
||||
if (idx == targets.length) {
|
||||
ok(
|
||||
false,
|
||||
"There is unexpected target" + prettyName(relatedAcc) + "of" + relDescr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,15 +134,19 @@ function testAbsentRelation(aIdentifier, aRelType, aUnrelatedIdentifiers) {
|
|||
return;
|
||||
}
|
||||
|
||||
var relatedIds = (aUnrelatedIdentifiers instanceof Array) ?
|
||||
aUnrelatedIdentifiers : [aUnrelatedIdentifiers];
|
||||
var relatedIds =
|
||||
aUnrelatedIdentifiers instanceof Array
|
||||
? aUnrelatedIdentifiers
|
||||
: [aUnrelatedIdentifiers];
|
||||
|
||||
var targets = [];
|
||||
for (let idx = 0; idx < relatedIds.length; idx++)
|
||||
for (let idx = 0; idx < relatedIds.length; idx++) {
|
||||
targets.push(getAccessible(relatedIds[idx]));
|
||||
}
|
||||
|
||||
if (targets.length != relatedIds.length)
|
||||
if (targets.length != relatedIds.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var actualTargets = relation.getTargets();
|
||||
|
||||
|
@ -155,8 +173,9 @@ function testAbsentRelation(aIdentifier, aRelType, aUnrelatedIdentifiers) {
|
|||
*/
|
||||
function getRelationByType(aIdentifier, aRelType) {
|
||||
var acc = getAccessible(aIdentifier);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var relation = null;
|
||||
try {
|
||||
|
|
|
@ -154,8 +154,9 @@ function testRole(aAccOrElmOrID, aRole) {
|
|||
*/
|
||||
function getRole(aAccOrElmOrID) {
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
var role = -1;
|
||||
try {
|
||||
|
@ -172,8 +173,9 @@ function getRole(aAccOrElmOrID) {
|
|||
*/
|
||||
function isRole(aIdentifier, aRole, aMsg) {
|
||||
var role = getRole(aIdentifier);
|
||||
if (role == -1)
|
||||
if (role == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (role == aRole) {
|
||||
ok(true, aMsg);
|
||||
|
|
|
@ -6,37 +6,62 @@
|
|||
*/
|
||||
function testSelectableSelection(aIdentifier, aSelectedChildren, aMsg) {
|
||||
var acc = getAccessible(aIdentifier, [nsIAccessibleSelectable]);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = aMsg ? aMsg : "";
|
||||
var len = aSelectedChildren.length;
|
||||
|
||||
// getSelectedChildren
|
||||
var selectedChildren = acc.selectedItems;
|
||||
is(selectedChildren ? selectedChildren.length : 0, len,
|
||||
msg + "getSelectedChildren: wrong selected children count for " +
|
||||
prettyName(aIdentifier));
|
||||
is(
|
||||
selectedChildren ? selectedChildren.length : 0,
|
||||
len,
|
||||
msg +
|
||||
"getSelectedChildren: wrong selected children count for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
for (let idx = 0; idx < len; idx++) {
|
||||
let expectedAcc = getAccessible(aSelectedChildren[idx]);
|
||||
var actualAcc = selectedChildren.queryElementAt(idx, nsIAccessible);
|
||||
is(actualAcc, expectedAcc,
|
||||
msg + "getSelectedChildren: wrong selected child at index " + idx +
|
||||
" for " + prettyName(aIdentifier) + " { actual : " +
|
||||
prettyName(actualAcc) + ", expected: " + prettyName(expectedAcc) + "}");
|
||||
is(
|
||||
actualAcc,
|
||||
expectedAcc,
|
||||
msg +
|
||||
"getSelectedChildren: wrong selected child at index " +
|
||||
idx +
|
||||
" for " +
|
||||
prettyName(aIdentifier) +
|
||||
" { actual : " +
|
||||
prettyName(actualAcc) +
|
||||
", expected: " +
|
||||
prettyName(expectedAcc) +
|
||||
"}"
|
||||
);
|
||||
}
|
||||
|
||||
// selectedItemCount
|
||||
is(acc.selectedItemCount, aSelectedChildren.length,
|
||||
"selectedItemCount: wrong selected children count for " + prettyName(aIdentifier));
|
||||
is(
|
||||
acc.selectedItemCount,
|
||||
aSelectedChildren.length,
|
||||
"selectedItemCount: wrong selected children count for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
// getSelectedItemAt
|
||||
for (let idx = 0; idx < len; idx++) {
|
||||
let expectedAcc = getAccessible(aSelectedChildren[idx]);
|
||||
is(acc.getSelectedItemAt(idx), expectedAcc,
|
||||
msg + "getSelectedItemAt: wrong selected child at index " + idx + " for " +
|
||||
prettyName(aIdentifier));
|
||||
is(
|
||||
acc.getSelectedItemAt(idx),
|
||||
expectedAcc,
|
||||
msg +
|
||||
"getSelectedItemAt: wrong selected child at index " +
|
||||
idx +
|
||||
" for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
}
|
||||
|
||||
// isItemSelected
|
||||
|
@ -46,7 +71,13 @@ function testSelectableSelection(aIdentifier, aSelectedChildren, aMsg) {
|
|||
/**
|
||||
* Test isItemSelected method, helper for testSelectableSelection
|
||||
*/
|
||||
function testIsItemSelected(aSelectAcc, aTraversedAcc, aIndexObj, aSelectedChildren, aMsg) {
|
||||
function testIsItemSelected(
|
||||
aSelectAcc,
|
||||
aTraversedAcc,
|
||||
aIndexObj,
|
||||
aSelectedChildren,
|
||||
aMsg
|
||||
) {
|
||||
var childCount = aTraversedAcc.childCount;
|
||||
for (var idx = 0; idx < childCount; idx++) {
|
||||
var child = aTraversedAcc.getChildAt(idx);
|
||||
|
@ -62,13 +93,24 @@ function testIsItemSelected(aSelectAcc, aTraversedAcc, aIndexObj, aSelectedChild
|
|||
}
|
||||
|
||||
// isItemSelected
|
||||
is(aSelectAcc.isItemSelected(aIndexObj.value++), isSelected,
|
||||
aMsg + "isItemSelected: wrong selected child " + prettyName(child) +
|
||||
" for " + prettyName(aSelectAcc));
|
||||
is(
|
||||
aSelectAcc.isItemSelected(aIndexObj.value++),
|
||||
isSelected,
|
||||
aMsg +
|
||||
"isItemSelected: wrong selected child " +
|
||||
prettyName(child) +
|
||||
" for " +
|
||||
prettyName(aSelectAcc)
|
||||
);
|
||||
|
||||
// selected state
|
||||
testStates(child, isSelected ? STATE_SELECTED : 0, 0,
|
||||
!isSelected ? STATE_SELECTED : 0, 0);
|
||||
testStates(
|
||||
child,
|
||||
isSelected ? STATE_SELECTED : 0,
|
||||
0,
|
||||
!isSelected ? STATE_SELECTED : 0,
|
||||
0
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -72,92 +72,178 @@ const kExtraState = 1;
|
|||
* @param aAbsentExtraState Extra state bits that are not wanted.
|
||||
* @param aTestName The test name.
|
||||
*/
|
||||
function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
|
||||
aAbsentExtraState, aTestName) {
|
||||
function testStates(
|
||||
aAccOrElmOrID,
|
||||
aState,
|
||||
aExtraState,
|
||||
aAbsentState,
|
||||
aAbsentExtraState,
|
||||
aTestName
|
||||
) {
|
||||
var [state, extraState] = getStates(aAccOrElmOrID);
|
||||
var role = getRole(aAccOrElmOrID);
|
||||
var id = prettyName(aAccOrElmOrID) + (aTestName ? " [" + aTestName + "]" : "");
|
||||
var id =
|
||||
prettyName(aAccOrElmOrID) + (aTestName ? " [" + aTestName + "]" : "");
|
||||
|
||||
// Primary test.
|
||||
if (aState) {
|
||||
isState(state & aState, aState, false,
|
||||
"wrong state bits for " + id + "!");
|
||||
isState(state & aState, aState, false, "wrong state bits for " + id + "!");
|
||||
}
|
||||
|
||||
if (aExtraState)
|
||||
isState(extraState & aExtraState, aExtraState, true,
|
||||
"wrong extra state bits for " + id + "!");
|
||||
if (aExtraState) {
|
||||
isState(
|
||||
extraState & aExtraState,
|
||||
aExtraState,
|
||||
true,
|
||||
"wrong extra state bits for " + id + "!"
|
||||
);
|
||||
}
|
||||
|
||||
if (aAbsentState)
|
||||
isState(state & aAbsentState, 0, false,
|
||||
"state bits should not be present in ID " + id + "!");
|
||||
if (aAbsentState) {
|
||||
isState(
|
||||
state & aAbsentState,
|
||||
0,
|
||||
false,
|
||||
"state bits should not be present in ID " + id + "!"
|
||||
);
|
||||
}
|
||||
|
||||
if (aAbsentExtraState)
|
||||
isState(extraState & aAbsentExtraState, 0, true,
|
||||
"extraState bits should not be present in ID " + id + "!");
|
||||
if (aAbsentExtraState) {
|
||||
isState(
|
||||
extraState & aAbsentExtraState,
|
||||
0,
|
||||
true,
|
||||
"extraState bits should not be present in ID " + id + "!"
|
||||
);
|
||||
}
|
||||
|
||||
// Additional test.
|
||||
|
||||
// focused/focusable
|
||||
if (state & STATE_FOCUSED)
|
||||
isState(state & STATE_FOCUSABLE, STATE_FOCUSABLE, false,
|
||||
"Focussed " + id + " must be focusable!");
|
||||
if (state & STATE_FOCUSED) {
|
||||
isState(
|
||||
state & STATE_FOCUSABLE,
|
||||
STATE_FOCUSABLE,
|
||||
false,
|
||||
"Focussed " + id + " must be focusable!"
|
||||
);
|
||||
}
|
||||
|
||||
if (aAbsentState && (aAbsentState & STATE_FOCUSABLE)) {
|
||||
isState(state & STATE_FOCUSED, 0, false,
|
||||
"Not focusable " + id + " must be not focused!");
|
||||
if (aAbsentState && aAbsentState & STATE_FOCUSABLE) {
|
||||
isState(
|
||||
state & STATE_FOCUSED,
|
||||
0,
|
||||
false,
|
||||
"Not focusable " + id + " must be not focused!"
|
||||
);
|
||||
}
|
||||
|
||||
// multiline/singleline
|
||||
if (extraState & EXT_STATE_MULTI_LINE)
|
||||
isState(extraState & EXT_STATE_SINGLE_LINE, 0, true,
|
||||
"Multiline " + id + " cannot be singleline!");
|
||||
if (extraState & EXT_STATE_MULTI_LINE) {
|
||||
isState(
|
||||
extraState & EXT_STATE_SINGLE_LINE,
|
||||
0,
|
||||
true,
|
||||
"Multiline " + id + " cannot be singleline!"
|
||||
);
|
||||
}
|
||||
|
||||
if (extraState & EXT_STATE_SINGLE_LINE)
|
||||
isState(extraState & EXT_STATE_MULTI_LINE, 0, true,
|
||||
"Singleline " + id + " cannot be multiline!");
|
||||
if (extraState & EXT_STATE_SINGLE_LINE) {
|
||||
isState(
|
||||
extraState & EXT_STATE_MULTI_LINE,
|
||||
0,
|
||||
true,
|
||||
"Singleline " + id + " cannot be multiline!"
|
||||
);
|
||||
}
|
||||
|
||||
// expanded/collapsed/expandable
|
||||
if (state & STATE_COLLAPSED || state & STATE_EXPANDED)
|
||||
isState(extraState & EXT_STATE_EXPANDABLE, EXT_STATE_EXPANDABLE, true,
|
||||
"Collapsed or expanded " + id + " must be expandable!");
|
||||
if (state & STATE_COLLAPSED || state & STATE_EXPANDED) {
|
||||
isState(
|
||||
extraState & EXT_STATE_EXPANDABLE,
|
||||
EXT_STATE_EXPANDABLE,
|
||||
true,
|
||||
"Collapsed or expanded " + id + " must be expandable!"
|
||||
);
|
||||
}
|
||||
|
||||
if (state & STATE_COLLAPSED)
|
||||
isState(state & STATE_EXPANDED, 0, false,
|
||||
"Collapsed " + id + " cannot be expanded!");
|
||||
if (state & STATE_COLLAPSED) {
|
||||
isState(
|
||||
state & STATE_EXPANDED,
|
||||
0,
|
||||
false,
|
||||
"Collapsed " + id + " cannot be expanded!"
|
||||
);
|
||||
}
|
||||
|
||||
if (state & STATE_EXPANDED)
|
||||
isState(state & STATE_COLLAPSED, 0, false,
|
||||
"Expanded " + id + " cannot be collapsed!");
|
||||
if (state & STATE_EXPANDED) {
|
||||
isState(
|
||||
state & STATE_COLLAPSED,
|
||||
0,
|
||||
false,
|
||||
"Expanded " + id + " cannot be collapsed!"
|
||||
);
|
||||
}
|
||||
|
||||
if (aAbsentState && (extraState & EXT_STATE_EXPANDABLE)) {
|
||||
if (aAbsentState && extraState & EXT_STATE_EXPANDABLE) {
|
||||
if (aAbsentState & STATE_EXPANDED) {
|
||||
isState(state & STATE_COLLAPSED, STATE_COLLAPSED, false,
|
||||
"Not expanded " + id + " must be collapsed!");
|
||||
isState(
|
||||
state & STATE_COLLAPSED,
|
||||
STATE_COLLAPSED,
|
||||
false,
|
||||
"Not expanded " + id + " must be collapsed!"
|
||||
);
|
||||
} else if (aAbsentState & STATE_COLLAPSED) {
|
||||
isState(state & STATE_EXPANDED, STATE_EXPANDED, false,
|
||||
"Not collapsed " + id + " must be expanded!");
|
||||
isState(
|
||||
state & STATE_EXPANDED,
|
||||
STATE_EXPANDED,
|
||||
false,
|
||||
"Not collapsed " + id + " must be expanded!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// checked/mixed/checkable
|
||||
if (state & STATE_CHECKED || state & STATE_MIXED &&
|
||||
role != ROLE_TOGGLE_BUTTON && role != ROLE_PROGRESSBAR)
|
||||
isState(state & STATE_CHECKABLE, STATE_CHECKABLE, false,
|
||||
"Checked or mixed element must be checkable!");
|
||||
if (
|
||||
state & STATE_CHECKED ||
|
||||
(state & STATE_MIXED &&
|
||||
role != ROLE_TOGGLE_BUTTON &&
|
||||
role != ROLE_PROGRESSBAR)
|
||||
) {
|
||||
isState(
|
||||
state & STATE_CHECKABLE,
|
||||
STATE_CHECKABLE,
|
||||
false,
|
||||
"Checked or mixed element must be checkable!"
|
||||
);
|
||||
}
|
||||
|
||||
if (state & STATE_CHECKED)
|
||||
isState(state & STATE_MIXED, 0, false,
|
||||
"Checked element cannot be state mixed!");
|
||||
if (state & STATE_CHECKED) {
|
||||
isState(
|
||||
state & STATE_MIXED,
|
||||
0,
|
||||
false,
|
||||
"Checked element cannot be state mixed!"
|
||||
);
|
||||
}
|
||||
|
||||
if (state & STATE_MIXED)
|
||||
isState(state & STATE_CHECKED, 0, false,
|
||||
"Mixed element cannot be state checked!");
|
||||
if (state & STATE_MIXED) {
|
||||
isState(
|
||||
state & STATE_CHECKED,
|
||||
0,
|
||||
false,
|
||||
"Mixed element cannot be state checked!"
|
||||
);
|
||||
}
|
||||
|
||||
// selected/selectable
|
||||
if ((state & STATE_SELECTED) && !(aAbsentState & STATE_SELECTABLE)) {
|
||||
isState(state & STATE_SELECTABLE, STATE_SELECTABLE, false,
|
||||
"Selected element must be selectable!");
|
||||
if (state & STATE_SELECTED && !(aAbsentState & STATE_SELECTABLE)) {
|
||||
isState(
|
||||
state & STATE_SELECTABLE,
|
||||
STATE_SELECTABLE,
|
||||
false,
|
||||
"Selected element must be selectable!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,13 +260,15 @@ function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
|
|||
function testStatesInSubtree(aAccOrElmOrID, aState, aExtraState, aAbsentState) {
|
||||
// test accessible and its subtree for propagated states.
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getRole(acc) != ROLE_TEXT_LEAF)
|
||||
if (getRole(acc) != ROLE_TEXT_LEAF) {
|
||||
// Right now, text leafs don't get tested because the states are not being
|
||||
// propagated.
|
||||
testStates(acc, aState, aExtraState, aAbsentState);
|
||||
}
|
||||
|
||||
// Iterate over its children to see if the state got propagated.
|
||||
var children = null;
|
||||
|
@ -202,9 +290,13 @@ function testStatesInSubtree(aAccOrElmOrID, aState, aExtraState, aAbsentState) {
|
|||
*/
|
||||
function testIsDefunct(aAccessible, aTestName) {
|
||||
var id = prettyName(aAccessible) + (aTestName ? " [" + aTestName + "]" : "");
|
||||
var [/* state*/, extraState] = getStates(aAccessible);
|
||||
isState(extraState & EXT_STATE_DEFUNCT, EXT_STATE_DEFUNCT, true,
|
||||
"no defuct state for " + id + "!");
|
||||
var [, /* state*/ extraState] = getStates(aAccessible);
|
||||
isState(
|
||||
extraState & EXT_STATE_DEFUNCT,
|
||||
EXT_STATE_DEFUNCT,
|
||||
true,
|
||||
"no defuct state for " + id + "!"
|
||||
);
|
||||
}
|
||||
|
||||
function getStringStates(aAccOrElmOrID) {
|
||||
|
@ -214,10 +306,12 @@ function getStringStates(aAccOrElmOrID) {
|
|||
|
||||
function getStates(aAccOrElmOrID) {
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
var state = {}, extraState = {};
|
||||
var state = {},
|
||||
extraState = {};
|
||||
acc.getState(state, extraState);
|
||||
|
||||
return [state.value, extraState.value];
|
||||
|
@ -228,8 +322,10 @@ function getStates(aAccOrElmOrID) {
|
|||
*/
|
||||
function hasState(aAccOrElmOrID, aState, aExtraState) {
|
||||
var [state, exstate] = getStates(aAccOrElmOrID);
|
||||
return (aState ? state & aState : true) &&
|
||||
(aExtraState ? exstate & aExtraState : true);
|
||||
return (
|
||||
(aState ? state & aState : true) &&
|
||||
(aExtraState ? exstate & aExtraState : true)
|
||||
);
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -246,14 +342,18 @@ function isState(aState1, aState2, aIsExtraStates, aMsg) {
|
|||
|
||||
var got = "0";
|
||||
if (aState1) {
|
||||
got = statesToString(aIsExtraStates ? 0 : aState1,
|
||||
aIsExtraStates ? aState1 : 0);
|
||||
got = statesToString(
|
||||
aIsExtraStates ? 0 : aState1,
|
||||
aIsExtraStates ? aState1 : 0
|
||||
);
|
||||
}
|
||||
|
||||
var expected = "0";
|
||||
if (aState2) {
|
||||
expected = statesToString(aIsExtraStates ? 0 : aState2,
|
||||
aIsExtraStates ? aState2 : 0);
|
||||
expected = statesToString(
|
||||
aIsExtraStates ? 0 : aState2,
|
||||
aIsExtraStates ? aState2 : 0
|
||||
);
|
||||
}
|
||||
|
||||
ok(false, aMsg + "got '" + got + "', expected '" + expected + "'");
|
||||
|
|
|
@ -47,10 +47,18 @@ const kMathTable = 2;
|
|||
* @param aTableType [in] specifies the table type.
|
||||
* @param aRowRoles [in] array of row roles.
|
||||
*/
|
||||
function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
|
||||
aCaption, aSummary, aTableType, aRowRoles) {
|
||||
function testTableStruct(
|
||||
aIdentifier,
|
||||
aCellsArray,
|
||||
aColHeaderType,
|
||||
aCaption,
|
||||
aSummary,
|
||||
aTableType,
|
||||
aRowRoles
|
||||
) {
|
||||
var tableNode = getNode(aIdentifier);
|
||||
var isGrid = tableNode.getAttribute("role") == "grid" ||
|
||||
var isGrid =
|
||||
tableNode.getAttribute("role") == "grid" ||
|
||||
tableNode.getAttribute("role") == "treegrid" ||
|
||||
tableNode.localName == "tree";
|
||||
|
||||
|
@ -126,8 +134,12 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
|
|||
var role = ROLE_NOTHING;
|
||||
switch (celltype) {
|
||||
case kDataCell:
|
||||
role = (aTableType == kMathTable ? ROLE_MATHML_CELL :
|
||||
(isGrid ? ROLE_GRID_CELL : ROLE_CELL));
|
||||
role =
|
||||
aTableType == kMathTable
|
||||
? ROLE_MATHML_CELL
|
||||
: isGrid
|
||||
? ROLE_GRID_CELL
|
||||
: ROLE_CELL;
|
||||
break;
|
||||
case kRowHeaderCell:
|
||||
role = ROLE_ROWHEADER;
|
||||
|
@ -152,15 +164,25 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
|
|||
var table = getAccessible(aIdentifier, [nsIAccessibleTable]);
|
||||
|
||||
// summary
|
||||
if (aSummary)
|
||||
is(table.summary, aSummary,
|
||||
"Wrong summary of the table " + prettyName(aIdentifier));
|
||||
if (aSummary) {
|
||||
is(
|
||||
table.summary,
|
||||
aSummary,
|
||||
"Wrong summary of the table " + prettyName(aIdentifier)
|
||||
);
|
||||
}
|
||||
|
||||
// rowCount and columnCount
|
||||
is(table.rowCount, rowCount,
|
||||
"Wrong rows count of " + prettyName(aIdentifier));
|
||||
is(table.columnCount, colsCount,
|
||||
"Wrong columns count of " + prettyName(aIdentifier));
|
||||
is(
|
||||
table.rowCount,
|
||||
rowCount,
|
||||
"Wrong rows count of " + prettyName(aIdentifier)
|
||||
);
|
||||
is(
|
||||
table.columnCount,
|
||||
colsCount,
|
||||
"Wrong columns count of " + prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
// rows and columns extents
|
||||
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
||||
|
@ -170,37 +192,70 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
|
|||
// table getRowExtentAt
|
||||
var rowExtent = table.getRowExtentAt(rowIdx, colIdx);
|
||||
let idx;
|
||||
for (idx = rowIdx + 1;
|
||||
idx < rowCount && (aCellsArray[idx][colIdx] & kRowSpanned);
|
||||
idx++);
|
||||
for (
|
||||
idx = rowIdx + 1;
|
||||
idx < rowCount && aCellsArray[idx][colIdx] & kRowSpanned;
|
||||
idx++
|
||||
) {}
|
||||
|
||||
var expectedRowExtent = idx - rowIdx;
|
||||
is(rowExtent, expectedRowExtent,
|
||||
"getRowExtentAt: Wrong number of spanned rows at (" + rowIdx + ", " +
|
||||
colIdx + ") for " + prettyName(aIdentifier));
|
||||
is(
|
||||
rowExtent,
|
||||
expectedRowExtent,
|
||||
"getRowExtentAt: Wrong number of spanned rows at (" +
|
||||
rowIdx +
|
||||
", " +
|
||||
colIdx +
|
||||
") for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
// table getColumnExtentAt
|
||||
var colExtent = table.getColumnExtentAt(rowIdx, colIdx);
|
||||
for (idx = colIdx + 1;
|
||||
idx < colsCount && (aCellsArray[rowIdx][idx] & kColSpanned);
|
||||
idx++);
|
||||
for (
|
||||
idx = colIdx + 1;
|
||||
idx < colsCount && aCellsArray[rowIdx][idx] & kColSpanned;
|
||||
idx++
|
||||
) {}
|
||||
|
||||
var expectedColExtent = idx - colIdx;
|
||||
is(colExtent, expectedColExtent,
|
||||
"getColumnExtentAt: Wrong number of spanned columns at (" + rowIdx +
|
||||
", " + colIdx + ") for " + prettyName(aIdentifier));
|
||||
is(
|
||||
colExtent,
|
||||
expectedColExtent,
|
||||
"getColumnExtentAt: Wrong number of spanned columns at (" +
|
||||
rowIdx +
|
||||
", " +
|
||||
colIdx +
|
||||
") for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
// cell rowExtent and columnExtent
|
||||
var cell = getAccessible(table.getCellAt(rowIdx, colIdx),
|
||||
[nsIAccessibleTableCell]);
|
||||
var cell = getAccessible(table.getCellAt(rowIdx, colIdx), [
|
||||
nsIAccessibleTableCell,
|
||||
]);
|
||||
|
||||
is(cell.rowExtent, expectedRowExtent,
|
||||
"rowExtent: Wrong number of spanned rows at (" + rowIdx + ", " +
|
||||
colIdx + ") for " + prettyName(aIdentifier));
|
||||
is(
|
||||
cell.rowExtent,
|
||||
expectedRowExtent,
|
||||
"rowExtent: Wrong number of spanned rows at (" +
|
||||
rowIdx +
|
||||
", " +
|
||||
colIdx +
|
||||
") for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
is(cell.columnExtent, expectedColExtent,
|
||||
"columnExtent: Wrong number of spanned column at (" + rowIdx + ", " +
|
||||
colIdx + ") for " + prettyName(aIdentifier));
|
||||
is(
|
||||
cell.columnExtent,
|
||||
expectedColExtent,
|
||||
"columnExtent: Wrong number of spanned column at (" +
|
||||
rowIdx +
|
||||
", " +
|
||||
colIdx +
|
||||
") for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,8 +269,9 @@ function testTableStruct(aIdentifier, aCellsArray, aColHeaderType,
|
|||
*/
|
||||
function testTableIndexes(aIdentifier, aIdxes) {
|
||||
var tableAcc = getAccessible(aIdentifier, [nsIAccessibleTable]);
|
||||
if (!tableAcc)
|
||||
if (!tableAcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var obtainedRowIdx, obtainedColIdx, obtainedIdx;
|
||||
var cellAcc;
|
||||
|
@ -232,55 +288,105 @@ function testTableIndexes(aIdentifier, aIdxes) {
|
|||
try {
|
||||
cellAcc = null;
|
||||
cellAcc = tableAcc.getCellAt(rowIdx, colIdx);
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
|
||||
ok(idx != -1 && cellAcc || idx == -1 && !cellAcc,
|
||||
id + ": Can't get cell accessible at row = " + rowIdx + ", column = " + colIdx);
|
||||
ok(
|
||||
(idx != -1 && cellAcc) || (idx == -1 && !cellAcc),
|
||||
id +
|
||||
": Can't get cell accessible at row = " +
|
||||
rowIdx +
|
||||
", column = " +
|
||||
colIdx
|
||||
);
|
||||
|
||||
if (idx != -1) {
|
||||
// getRowIndexAt
|
||||
var origRowIdx = rowIdx;
|
||||
while (origRowIdx > 0 &&
|
||||
aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx])
|
||||
while (
|
||||
origRowIdx > 0 &&
|
||||
aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx]
|
||||
) {
|
||||
origRowIdx--;
|
||||
}
|
||||
|
||||
try {
|
||||
obtainedRowIdx = tableAcc.getRowIndexAt(idx);
|
||||
} catch (e) {
|
||||
ok(false, id + ": can't get row index for cell index " + idx + "," + e);
|
||||
ok(
|
||||
false,
|
||||
id + ": can't get row index for cell index " + idx + "," + e
|
||||
);
|
||||
}
|
||||
|
||||
is(obtainedRowIdx, origRowIdx,
|
||||
id + ": row for index " + idx + " is not correct (getRowIndexAt)");
|
||||
is(
|
||||
obtainedRowIdx,
|
||||
origRowIdx,
|
||||
id + ": row for index " + idx + " is not correct (getRowIndexAt)"
|
||||
);
|
||||
|
||||
// getColumnIndexAt
|
||||
var origColIdx = colIdx;
|
||||
while (origColIdx > 0 &&
|
||||
aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1])
|
||||
while (
|
||||
origColIdx > 0 &&
|
||||
aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1]
|
||||
) {
|
||||
origColIdx--;
|
||||
}
|
||||
|
||||
try {
|
||||
obtainedColIdx = tableAcc.getColumnIndexAt(idx);
|
||||
} catch (e) {
|
||||
ok(false, id + ": can't get column index for cell index " + idx + "," + e);
|
||||
ok(
|
||||
false,
|
||||
id + ": can't get column index for cell index " + idx + "," + e
|
||||
);
|
||||
}
|
||||
|
||||
is(obtainedColIdx, origColIdx,
|
||||
id + ": column for index " + idx + " is not correct (getColumnIndexAt)");
|
||||
is(
|
||||
obtainedColIdx,
|
||||
origColIdx,
|
||||
id +
|
||||
": column for index " +
|
||||
idx +
|
||||
" is not correct (getColumnIndexAt)"
|
||||
);
|
||||
|
||||
// getRowAndColumnIndicesAt
|
||||
var obtainedRowIdxObj = { }, obtainedColIdxObj = { };
|
||||
var obtainedRowIdxObj = {},
|
||||
obtainedColIdxObj = {};
|
||||
try {
|
||||
tableAcc.getRowAndColumnIndicesAt(idx, obtainedRowIdxObj,
|
||||
obtainedColIdxObj);
|
||||
tableAcc.getRowAndColumnIndicesAt(
|
||||
idx,
|
||||
obtainedRowIdxObj,
|
||||
obtainedColIdxObj
|
||||
);
|
||||
} catch (e) {
|
||||
ok(false, id + ": can't get row and column indices for cell index " + idx + "," + e);
|
||||
ok(
|
||||
false,
|
||||
id +
|
||||
": can't get row and column indices for cell index " +
|
||||
idx +
|
||||
"," +
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
is(obtainedRowIdxObj.value, origRowIdx,
|
||||
id + ": row for index " + idx + " is not correct (getRowAndColumnIndicesAt)");
|
||||
is(obtainedColIdxObj.value, origColIdx,
|
||||
id + ": column for index " + idx + " is not correct (getRowAndColumnIndicesAt)");
|
||||
is(
|
||||
obtainedRowIdxObj.value,
|
||||
origRowIdx,
|
||||
id +
|
||||
": row for index " +
|
||||
idx +
|
||||
" is not correct (getRowAndColumnIndicesAt)"
|
||||
);
|
||||
is(
|
||||
obtainedColIdxObj.value,
|
||||
origColIdx,
|
||||
id +
|
||||
": column for index " +
|
||||
idx +
|
||||
" is not correct (getRowAndColumnIndicesAt)"
|
||||
);
|
||||
|
||||
if (cellAcc) {
|
||||
var cellId = prettyName(cellAcc);
|
||||
|
@ -292,45 +398,74 @@ function testTableIndexes(aIdentifier, aIdxes) {
|
|||
try {
|
||||
strIdx = attrs.getStringProperty("table-cell-index");
|
||||
} catch (e) {
|
||||
ok(false,
|
||||
cellId + ": no cell index from object attributes on the cell accessible at index " + idx + ".");
|
||||
ok(
|
||||
false,
|
||||
cellId +
|
||||
": no cell index from object attributes on the cell accessible at index " +
|
||||
idx +
|
||||
"."
|
||||
);
|
||||
}
|
||||
|
||||
if (strIdx) {
|
||||
is(parseInt(strIdx), idx,
|
||||
cellId + ": cell index from object attributes of cell accessible isn't corrent.");
|
||||
is(
|
||||
parseInt(strIdx),
|
||||
idx,
|
||||
cellId +
|
||||
": cell index from object attributes of cell accessible isn't corrent."
|
||||
);
|
||||
}
|
||||
|
||||
// cell: table
|
||||
try {
|
||||
is(cellAcc.table, tableAcc,
|
||||
cellId + ": wrong table accessible for the cell.");
|
||||
is(
|
||||
cellAcc.table,
|
||||
tableAcc,
|
||||
cellId + ": wrong table accessible for the cell."
|
||||
);
|
||||
} catch (e) {
|
||||
ok(false,
|
||||
cellId + ": can't get table accessible from the cell.");
|
||||
ok(false, cellId + ": can't get table accessible from the cell.");
|
||||
}
|
||||
|
||||
// cell: getRowIndex
|
||||
try {
|
||||
obtainedRowIdx = cellAcc.rowIndex;
|
||||
} catch (e) {
|
||||
ok(false,
|
||||
cellId + ": can't get row index of the cell at index " + idx + "," + e);
|
||||
ok(
|
||||
false,
|
||||
cellId +
|
||||
": can't get row index of the cell at index " +
|
||||
idx +
|
||||
"," +
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
is(obtainedRowIdx, origRowIdx,
|
||||
cellId + ": row for the cell at index " + idx + " is not correct");
|
||||
is(
|
||||
obtainedRowIdx,
|
||||
origRowIdx,
|
||||
cellId + ": row for the cell at index " + idx + " is not correct"
|
||||
);
|
||||
|
||||
// cell: getColumnIndex
|
||||
try {
|
||||
obtainedColIdx = cellAcc.columnIndex;
|
||||
} catch (e) {
|
||||
ok(false,
|
||||
cellId + ": can't get column index of the cell at index " + idx + "," + e);
|
||||
ok(
|
||||
false,
|
||||
cellId +
|
||||
": can't get column index of the cell at index " +
|
||||
idx +
|
||||
"," +
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
is(obtainedColIdx, origColIdx,
|
||||
id + ": column for the cell at index " + idx + " is not correct");
|
||||
is(
|
||||
obtainedColIdx,
|
||||
origColIdx,
|
||||
id + ": column for the cell at index " + idx + " is not correct"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,8 +476,18 @@ function testTableIndexes(aIdentifier, aIdxes) {
|
|||
obtainedIdx = -1;
|
||||
}
|
||||
|
||||
is(obtainedIdx, idx,
|
||||
id + ": row " + rowIdx + " /column " + colIdx + " and index " + obtainedIdx + " aren't inconsistent.");
|
||||
is(
|
||||
obtainedIdx,
|
||||
idx,
|
||||
id +
|
||||
": row " +
|
||||
rowIdx +
|
||||
" /column " +
|
||||
colIdx +
|
||||
" and index " +
|
||||
obtainedIdx +
|
||||
" aren't inconsistent."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,8 +504,9 @@ function testTableIndexes(aIdentifier, aIdxes) {
|
|||
function testTableSelection(aIdentifier, aCellsArray, aMsg) {
|
||||
var msg = aMsg ? aMsg : "";
|
||||
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rowCount = aCellsArray.length;
|
||||
var colsCount = aCellsArray[0].length;
|
||||
|
@ -372,36 +518,56 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
|
|||
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
var isColSelected = true;
|
||||
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
||||
if (!aCellsArray[rowIdx][colIdx] ||
|
||||
aCellsArray[rowIdx][colIdx] == undefined) {
|
||||
if (
|
||||
!aCellsArray[rowIdx][colIdx] ||
|
||||
aCellsArray[rowIdx][colIdx] == undefined
|
||||
) {
|
||||
isColSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
is(acc.isColumnSelected(colIdx), isColSelected,
|
||||
msg + "Wrong selection state of " + colIdx + " column for " +
|
||||
prettyName(aIdentifier));
|
||||
is(
|
||||
acc.isColumnSelected(colIdx),
|
||||
isColSelected,
|
||||
msg +
|
||||
"Wrong selection state of " +
|
||||
colIdx +
|
||||
" column for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
if (isColSelected)
|
||||
if (isColSelected) {
|
||||
selCols.push(colIdx);
|
||||
}
|
||||
}
|
||||
|
||||
// selectedColsCount test
|
||||
is(acc.selectedColumnCount, selCols.length,
|
||||
msg + "Wrong count of selected columns for " + prettyName(aIdentifier));
|
||||
is(
|
||||
acc.selectedColumnCount,
|
||||
selCols.length,
|
||||
msg + "Wrong count of selected columns for " + prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
// getSelectedColumns test
|
||||
var actualSelCols = acc.getSelectedColumnIndices();
|
||||
|
||||
var actualSelColsCount = actualSelCols.length;
|
||||
is(actualSelColsCount, selCols.length,
|
||||
msg + "Wrong count of selected columns for " + prettyName(aIdentifier) +
|
||||
"from getSelectedColumns.");
|
||||
is(
|
||||
actualSelColsCount,
|
||||
selCols.length,
|
||||
msg +
|
||||
"Wrong count of selected columns for " +
|
||||
prettyName(aIdentifier) +
|
||||
"from getSelectedColumns."
|
||||
);
|
||||
|
||||
for (let i = 0; i < actualSelColsCount; i++) {
|
||||
is(actualSelCols[i], selCols[i],
|
||||
msg + "Column at index " + selCols[i] + " should be selected.");
|
||||
is(
|
||||
actualSelCols[i],
|
||||
selCols[i],
|
||||
msg + "Column at index " + selCols[i] + " should be selected."
|
||||
);
|
||||
}
|
||||
|
||||
// Rows selection tests.
|
||||
|
@ -411,36 +577,56 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
|
|||
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
||||
var isRowSelected = true;
|
||||
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
if (!aCellsArray[rowIdx][colIdx] ||
|
||||
aCellsArray[rowIdx][colIdx] == undefined) {
|
||||
if (
|
||||
!aCellsArray[rowIdx][colIdx] ||
|
||||
aCellsArray[rowIdx][colIdx] == undefined
|
||||
) {
|
||||
isRowSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
is(acc.isRowSelected(rowIdx), isRowSelected,
|
||||
msg + "Wrong selection state of " + rowIdx + " row for " +
|
||||
prettyName(aIdentifier));
|
||||
is(
|
||||
acc.isRowSelected(rowIdx),
|
||||
isRowSelected,
|
||||
msg +
|
||||
"Wrong selection state of " +
|
||||
rowIdx +
|
||||
" row for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
if (isRowSelected)
|
||||
if (isRowSelected) {
|
||||
selRows.push(rowIdx);
|
||||
}
|
||||
}
|
||||
|
||||
// selectedRowCount test
|
||||
is(acc.selectedRowCount, selRows.length,
|
||||
msg + "Wrong count of selected rows for " + prettyName(aIdentifier));
|
||||
is(
|
||||
acc.selectedRowCount,
|
||||
selRows.length,
|
||||
msg + "Wrong count of selected rows for " + prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
// getSelectedRows test
|
||||
var actualSelRows = acc.getSelectedRowIndices();
|
||||
|
||||
var actualSelrowCount = actualSelRows.length;
|
||||
is(actualSelrowCount, selRows.length,
|
||||
msg + "Wrong count of selected rows for " + prettyName(aIdentifier) +
|
||||
"from getSelectedRows.");
|
||||
is(
|
||||
actualSelrowCount,
|
||||
selRows.length,
|
||||
msg +
|
||||
"Wrong count of selected rows for " +
|
||||
prettyName(aIdentifier) +
|
||||
"from getSelectedRows."
|
||||
);
|
||||
|
||||
for (let i = 0; i < actualSelrowCount; i++) {
|
||||
is(actualSelRows[i], selRows[i],
|
||||
msg + "Row at index " + selRows[i] + " should be selected.");
|
||||
is(
|
||||
actualSelRows[i],
|
||||
selRows[i],
|
||||
msg + "Row at index " + selRows[i] + " should be selected."
|
||||
);
|
||||
}
|
||||
|
||||
// Cells selection tests.
|
||||
|
@ -449,69 +635,103 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
|
|||
// isCellSelected test
|
||||
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
||||
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
if (aCellsArray[rowIdx][colIdx] & kSpanned)
|
||||
if (aCellsArray[rowIdx][colIdx] & kSpanned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var isSelected = !!aCellsArray[rowIdx][colIdx];
|
||||
is(acc.isCellSelected(rowIdx, colIdx), isSelected,
|
||||
msg + "Wrong selection state of cell at " + rowIdx + " row and " +
|
||||
colIdx + " column for " + prettyName(aIdentifier));
|
||||
is(
|
||||
acc.isCellSelected(rowIdx, colIdx),
|
||||
isSelected,
|
||||
msg +
|
||||
"Wrong selection state of cell at " +
|
||||
rowIdx +
|
||||
" row and " +
|
||||
colIdx +
|
||||
" column for " +
|
||||
prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
if (aCellsArray[rowIdx][colIdx])
|
||||
if (aCellsArray[rowIdx][colIdx]) {
|
||||
selCells.push(acc.getCellIndexAt(rowIdx, colIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// selectedCellCount tests
|
||||
is(acc.selectedCellCount, selCells.length,
|
||||
msg + "Wrong count of selected cells for " + prettyName(aIdentifier));
|
||||
is(
|
||||
acc.selectedCellCount,
|
||||
selCells.length,
|
||||
msg + "Wrong count of selected cells for " + prettyName(aIdentifier)
|
||||
);
|
||||
|
||||
// getSelectedCellIndices test
|
||||
var actualSelCells = acc.getSelectedCellIndices();
|
||||
|
||||
var actualSelCellsCount = actualSelCells.length;
|
||||
is(actualSelCellsCount, selCells.length,
|
||||
msg + "Wrong count of selected cells for " + prettyName(aIdentifier) +
|
||||
"from getSelectedCells.");
|
||||
is(
|
||||
actualSelCellsCount,
|
||||
selCells.length,
|
||||
msg +
|
||||
"Wrong count of selected cells for " +
|
||||
prettyName(aIdentifier) +
|
||||
"from getSelectedCells."
|
||||
);
|
||||
|
||||
for (let i = 0; i < actualSelCellsCount; i++) {
|
||||
is(actualSelCells[i], selCells[i],
|
||||
msg + "getSelectedCellIndices: Cell at index " + selCells[i] +
|
||||
" should be selected.");
|
||||
is(
|
||||
actualSelCells[i],
|
||||
selCells[i],
|
||||
msg +
|
||||
"getSelectedCellIndices: Cell at index " +
|
||||
selCells[i] +
|
||||
" should be selected."
|
||||
);
|
||||
}
|
||||
|
||||
// selectedCells and isSelected tests
|
||||
var actualSelCellsArray = acc.selectedCells;
|
||||
for (let i = 0; i < actualSelCellsCount; i++) {
|
||||
var actualSelCellAccessible =
|
||||
actualSelCellsArray.queryElementAt(i, nsIAccessibleTableCell);
|
||||
var actualSelCellAccessible = actualSelCellsArray.queryElementAt(
|
||||
i,
|
||||
nsIAccessibleTableCell
|
||||
);
|
||||
|
||||
let colIdx = acc.getColumnIndexAt(selCells[i]);
|
||||
let rowIdx = acc.getRowIndexAt(selCells[i]);
|
||||
var expectedSelCellAccessible = acc.getCellAt(rowIdx, colIdx);
|
||||
|
||||
is(actualSelCellAccessible, expectedSelCellAccessible,
|
||||
msg + "getSelectedCells: Cell at index " + selCells[i] +
|
||||
" should be selected.");
|
||||
is(
|
||||
actualSelCellAccessible,
|
||||
expectedSelCellAccessible,
|
||||
msg +
|
||||
"getSelectedCells: Cell at index " +
|
||||
selCells[i] +
|
||||
" should be selected."
|
||||
);
|
||||
|
||||
ok(actualSelCellAccessible.isSelected(),
|
||||
"isSelected: Cell at index " + selCells[i] + " should be selected.");
|
||||
ok(
|
||||
actualSelCellAccessible.isSelected(),
|
||||
"isSelected: Cell at index " + selCells[i] + " should be selected."
|
||||
);
|
||||
}
|
||||
|
||||
// selected states tests
|
||||
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
||||
for (let colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
if (aCellsArray[rowIdx][colIdx] & kSpanned)
|
||||
if (aCellsArray[rowIdx][colIdx] & kSpanned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var cell = acc.getCellAt(rowIdx, colIdx);
|
||||
var isSel = aCellsArray[rowIdx][colIdx];
|
||||
if (isSel == undefined)
|
||||
if (isSel == undefined) {
|
||||
testStates(cell, 0, 0, STATE_SELECTABLE | STATE_SELECTED);
|
||||
else if (isSel)
|
||||
} else if (isSel) {
|
||||
testStates(cell, STATE_SELECTED);
|
||||
else
|
||||
} else {
|
||||
testStates(cell, STATE_SELECTABLE, 0, STATE_SELECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -521,20 +741,27 @@ function testTableSelection(aIdentifier, aCellsArray, aMsg) {
|
|||
*/
|
||||
function testUnselectTableColumn(aIdentifier, aColIdx, aCellsArray) {
|
||||
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rowCount = aCellsArray.length;
|
||||
for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
|
||||
// Unselect origin cell.
|
||||
var [origRowIdx, origColIdx] =
|
||||
getOrigRowAndColumn(aCellsArray, rowIdx, aColIdx);
|
||||
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
|
||||
aCellsArray,
|
||||
rowIdx,
|
||||
aColIdx
|
||||
);
|
||||
aCellsArray[origRowIdx][origColIdx] = false;
|
||||
}
|
||||
|
||||
acc.unselectColumn(aColIdx);
|
||||
testTableSelection(aIdentifier, aCellsArray,
|
||||
"Unselect " + aColIdx + " column: ");
|
||||
testTableSelection(
|
||||
aIdentifier,
|
||||
aCellsArray,
|
||||
"Unselect " + aColIdx + " column: "
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -542,8 +769,9 @@ function testUnselectTableColumn(aIdentifier, aColIdx, aCellsArray) {
|
|||
*/
|
||||
function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
|
||||
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rowCount = aCellsArray.length;
|
||||
var colsCount = aCellsArray[0].length;
|
||||
|
@ -552,17 +780,22 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
|
|||
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
var cellState = aCellsArray[rowIdx][colIdx];
|
||||
|
||||
if (colIdx == aColIdx) { // select target column
|
||||
if (colIdx == aColIdx) {
|
||||
// select target column
|
||||
if (!(cellState & kSpanned)) {
|
||||
// Select the cell if it is origin.
|
||||
aCellsArray[rowIdx][colIdx] = true;
|
||||
} else {
|
||||
// If the cell is spanned then search origin cell and select it.
|
||||
var [origRowIdx, origColIdx] = getOrigRowAndColumn(aCellsArray,
|
||||
rowIdx, colIdx);
|
||||
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
|
||||
aCellsArray,
|
||||
rowIdx,
|
||||
colIdx
|
||||
);
|
||||
aCellsArray[origRowIdx][origColIdx] = true;
|
||||
}
|
||||
} else if (!(cellState & kSpanned)) { // unselect other columns
|
||||
} else if (!(cellState & kSpanned)) {
|
||||
// unselect other columns
|
||||
if (colIdx > aColIdx) {
|
||||
// Unselect the cell if traversed column index is greater than column
|
||||
// index of target cell.
|
||||
|
@ -572,8 +805,11 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
|
|||
aCellsArray[rowIdx][colIdx] = false;
|
||||
} else {
|
||||
// Unselect the cell if it is not spanned to the target cell.
|
||||
for (var spannedColIdx = colIdx + 1; spannedColIdx < aColIdx;
|
||||
spannedColIdx++) {
|
||||
for (
|
||||
var spannedColIdx = colIdx + 1;
|
||||
spannedColIdx < aColIdx;
|
||||
spannedColIdx++
|
||||
) {
|
||||
var spannedCellState = aCellsArray[rowIdx][spannedColIdx];
|
||||
if (!(spannedCellState & kRowSpanned)) {
|
||||
aCellsArray[rowIdx][colIdx] = false;
|
||||
|
@ -586,8 +822,11 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
|
|||
}
|
||||
|
||||
acc.selectColumn(aColIdx);
|
||||
testTableSelection(aIdentifier, aCellsArray,
|
||||
"Select " + aColIdx + " column: ");
|
||||
testTableSelection(
|
||||
aIdentifier,
|
||||
aCellsArray,
|
||||
"Select " + aColIdx + " column: "
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -595,20 +834,27 @@ function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
|
|||
*/
|
||||
function testUnselectTableRow(aIdentifier, aRowIdx, aCellsArray) {
|
||||
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var colsCount = aCellsArray[0].length;
|
||||
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
// Unselect origin cell.
|
||||
var [origRowIdx, origColIdx] = getOrigRowAndColumn(aCellsArray,
|
||||
aRowIdx, colIdx);
|
||||
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
|
||||
aCellsArray,
|
||||
aRowIdx,
|
||||
colIdx
|
||||
);
|
||||
aCellsArray[origRowIdx][origColIdx] = false;
|
||||
}
|
||||
|
||||
acc.unselectRow(aRowIdx);
|
||||
testTableSelection(aIdentifier, aCellsArray,
|
||||
"Unselect " + aRowIdx + " row: ");
|
||||
testTableSelection(
|
||||
aIdentifier,
|
||||
aCellsArray,
|
||||
"Unselect " + aRowIdx + " row: "
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -616,8 +862,9 @@ function testUnselectTableRow(aIdentifier, aRowIdx, aCellsArray) {
|
|||
*/
|
||||
function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
|
||||
var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
|
||||
if (!acc)
|
||||
if (!acc) {
|
||||
return;
|
||||
}
|
||||
|
||||
var rowCount = aCellsArray.length;
|
||||
var colsCount = aCellsArray[0].length;
|
||||
|
@ -626,18 +873,23 @@ function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
|
|||
for (var colIdx = 0; colIdx < colsCount; colIdx++) {
|
||||
var cellState = aCellsArray[rowIdx][colIdx];
|
||||
|
||||
if (rowIdx == aRowIdx) { // select the given row
|
||||
if (rowIdx == aRowIdx) {
|
||||
// select the given row
|
||||
if (!(cellState & kSpanned)) {
|
||||
// Select the cell if it is origin.
|
||||
aCellsArray[rowIdx][colIdx] = true;
|
||||
} else {
|
||||
// If the cell is spanned then search origin cell and select it.
|
||||
var [origRowIdx, origColIdx] = getOrigRowAndColumn(aCellsArray,
|
||||
rowIdx, colIdx);
|
||||
var [origRowIdx, origColIdx] = getOrigRowAndColumn(
|
||||
aCellsArray,
|
||||
rowIdx,
|
||||
colIdx
|
||||
);
|
||||
|
||||
aCellsArray[origRowIdx][origColIdx] = true;
|
||||
}
|
||||
} else if (!(cellState & kSpanned)) { // unselect other rows
|
||||
} else if (!(cellState & kSpanned)) {
|
||||
// unselect other rows
|
||||
if (rowIdx > aRowIdx) {
|
||||
// Unselect the cell if traversed row index is greater than row
|
||||
// index of target cell.
|
||||
|
@ -647,8 +899,11 @@ function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
|
|||
aCellsArray[rowIdx][colIdx] = false;
|
||||
} else {
|
||||
// Unselect the cell if it is not spanned to the target cell.
|
||||
for (var spannedRowIdx = rowIdx + 1; spannedRowIdx < aRowIdx;
|
||||
spannedRowIdx++) {
|
||||
for (
|
||||
var spannedRowIdx = rowIdx + 1;
|
||||
spannedRowIdx < aRowIdx;
|
||||
spannedRowIdx++
|
||||
) {
|
||||
var spannedCellState = aCellsArray[spannedRowIdx][colIdx];
|
||||
if (!(spannedCellState & kRowSpanned)) {
|
||||
aCellsArray[rowIdx][colIdx] = false;
|
||||
|
@ -661,8 +916,7 @@ function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
|
|||
}
|
||||
|
||||
acc.selectRow(aRowIdx);
|
||||
testTableSelection(aIdentifier, aCellsArray,
|
||||
"Select " + aRowIdx + " row: ");
|
||||
testTableSelection(aIdentifier, aCellsArray, "Select " + aRowIdx + " row: ");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -679,18 +933,28 @@ function testHeaderCells(aHeaderInfoMap) {
|
|||
var actualRowHeaderCells = dataCell.rowHeaderCells;
|
||||
var actualRowHeaderCellsCount = actualRowHeaderCells.length;
|
||||
|
||||
is(actualRowHeaderCellsCount, rowHeaderCellsCount,
|
||||
"Wrong number of row header cells for the cell " +
|
||||
prettyName(dataCellIdentifier));
|
||||
is(
|
||||
actualRowHeaderCellsCount,
|
||||
rowHeaderCellsCount,
|
||||
"Wrong number of row header cells for the cell " +
|
||||
prettyName(dataCellIdentifier)
|
||||
);
|
||||
|
||||
if (actualRowHeaderCellsCount == rowHeaderCellsCount) {
|
||||
for (let idx = 0; idx < rowHeaderCellsCount; idx++) {
|
||||
var rowHeaderCell = getAccessible(rowHeaderCells[idx]);
|
||||
var actualRowHeaderCell =
|
||||
actualRowHeaderCells.queryElementAt(idx, nsIAccessible);
|
||||
isObject(actualRowHeaderCell, rowHeaderCell,
|
||||
"Wrong row header cell at index " + idx + " for the cell " +
|
||||
dataCellIdentifier);
|
||||
var actualRowHeaderCell = actualRowHeaderCells.queryElementAt(
|
||||
idx,
|
||||
nsIAccessible
|
||||
);
|
||||
isObject(
|
||||
actualRowHeaderCell,
|
||||
rowHeaderCell,
|
||||
"Wrong row header cell at index " +
|
||||
idx +
|
||||
" for the cell " +
|
||||
dataCellIdentifier
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,18 +964,28 @@ function testHeaderCells(aHeaderInfoMap) {
|
|||
var actualColHeaderCells = dataCell.columnHeaderCells;
|
||||
var actualColHeaderCellsCount = actualColHeaderCells.length;
|
||||
|
||||
is(actualColHeaderCellsCount, colHeaderCellsCount,
|
||||
"Wrong number of column header cells for the cell " +
|
||||
prettyName(dataCellIdentifier));
|
||||
is(
|
||||
actualColHeaderCellsCount,
|
||||
colHeaderCellsCount,
|
||||
"Wrong number of column header cells for the cell " +
|
||||
prettyName(dataCellIdentifier)
|
||||
);
|
||||
|
||||
if (actualColHeaderCellsCount == colHeaderCellsCount) {
|
||||
for (let idx = 0; idx < colHeaderCellsCount; idx++) {
|
||||
var colHeaderCell = getAccessible(colHeaderCells[idx]);
|
||||
var actualColHeaderCell =
|
||||
actualColHeaderCells.queryElementAt(idx, nsIAccessible);
|
||||
isObject(actualColHeaderCell, colHeaderCell,
|
||||
"Wrong column header cell at index " + idx + " for the cell " +
|
||||
dataCellIdentifier);
|
||||
var actualColHeaderCell = actualColHeaderCells.queryElementAt(
|
||||
idx,
|
||||
nsIAccessible
|
||||
);
|
||||
isObject(
|
||||
actualColHeaderCell,
|
||||
colHeaderCell,
|
||||
"Wrong column header cell at index " +
|
||||
idx +
|
||||
" for the cell " +
|
||||
dataCellIdentifier
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -726,7 +1000,8 @@ function testHeaderCells(aHeaderInfoMap) {
|
|||
function getOrigRowAndColumn(aCellsArray, aRowIdx, aColIdx) {
|
||||
var cellState = aCellsArray[aRowIdx][aColIdx];
|
||||
|
||||
var origRowIdx = aRowIdx, origColIdx = aColIdx;
|
||||
var origRowIdx = aRowIdx,
|
||||
origColIdx = aColIdx;
|
||||
if (cellState & kRowSpanned) {
|
||||
for (var prevRowIdx = aRowIdx - 1; prevRowIdx >= 0; prevRowIdx--) {
|
||||
let prevCellState = aCellsArray[prevRowIdx][aColIdx];
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче