// This file has circular dependencies that may require other files. Rather // than use import-globals-from, we list the globals individually here to save // confusing ESLint. // actions.js /* globals testActionNames */ // attributes.js /* globals testAttrs, testAbsentAttrs, testTextAttrs */ // relations.js /* globals testRelation */ // role.js /* globals isRole */ // state.js /* globals testStates */
/** * Enable/disable logging.
*/ function enableLogging(aModules) {
gAccService.setLogging(aModules);
} function disableLogging() {
gAccService.setLogging("");
} function isLogged(aModule) { return gAccService.isLogged(aModule);
}
/** * Dumps the accessible tree into console.
*/ function dumpTree(aId, aMsg) { function dumpTreeIntl(acc, indent) {
dump(indent + prettyName(acc) + "\n");
var children = acc.children; for (var i = 0; i < children.length; i++) { var child = children.queryElementAt(i, nsIAccessible);
dumpTreeIntl(child, indent + " ");
}
}
function dumpDOMTreeIntl(node, indent) {
dump(indent + prettyName(node) + "\n");
var children = node.childNodes; for (var i = 0; i < children.length; i++) { var child = children.item(i);
dumpDOMTreeIntl(child, indent + " ");
}
}
dump(aMsg + "\n"); var root = getAccessible(aId);
dumpTreeIntl(root, " ");
/** * Invokes the given function when document is loaded and focused. Preferable * to mochitests 'addLoadEvent' function -- additionally ensures state of the * document accessible is not busy. * * @param aFunc the function to invoke
*/ 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;
}
/** * Analogy of SimpleTest.is function used to compare objects.
*/ function isObject(aObj, aExpectedObj, aMsg) { if (aObj == aExpectedObj) {
ok(true, aMsg); return;
}
/** * is() function checking the expected value is within the range.
*/ 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}`
);
}
}
// ////////////////////////////////////////////////////////////////////////////// // Helpers for getting DOM node/accessible
/** * Return the DOM node by identifier (may be accessible, DOM node or ID).
*/ function getNode(aAccOrNodeOrID, aDocument) { if (!aAccOrNodeOrID) { returnnull;
}
if (Node.isInstance(aAccOrNodeOrID)) { return aAccOrNodeOrID;
}
if (aAccOrNodeOrID instanceof nsIAccessible) { return aAccOrNodeOrID.DOMNode;
}
var node = (aDocument || document).getElementById(aAccOrNodeOrID); if (!node) {
ok(false, "Can't get DOM element for " + aAccOrNodeOrID); returnnull;
}
return node;
}
/** * Constants indicates getAccessible doesn't fail if there is no accessible.
*/ const DONOTFAIL_IF_NO_ACC = 1;
/** * Constants indicates getAccessible won't fail if accessible doesn't implement * the requested interfaces.
*/ const DONOTFAIL_IF_NO_INTERFACE = 2;
/** * Return accessible for the given identifier (may be ID attribute or DOM * element or accessible object) or null. * * @param aAccOrElmOrID [in] identifier to get an accessible implementing * the given interfaces * @param aInterfaces [in, optional] the interface or an array interfaces * to query it/them from obtained accessible * @param aElmObj [out, optional] object to store DOM element which * accessible is obtained for * @param aDoNotFailIf [in, optional] no error for special cases (see * constants above)
*/ function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIf) { if (!aAccOrElmOrID) { returnnull;
}
var elm = null;
if (aAccOrElmOrID instanceof nsIAccessible) { try {
elm = aAccOrElmOrID.DOMNode;
} catch (e) {}
} elseif (Node.isInstance(aAccOrElmOrID)) {
elm = aAccOrElmOrID;
} else {
elm = document.getElementById(aAccOrElmOrID); if (!elm) {
ok(false, "Can't get DOM element for " + aAccOrElmOrID); returnnull;
}
}
if (!acc) { if (!(aDoNotFailIf & DONOTFAIL_IF_NO_ACC)) {
ok(false, "Can't get accessible for " + prettyName(aAccOrElmOrID));
}
returnnull;
}
}
if (!aInterfaces) { return acc;
}
if (!(aInterfaces instanceof Array)) {
aInterfaces = [aInterfaces];
}
for (var index = 0; index < aInterfaces.length; index++) { if (acc instanceof aInterfaces[index]) { continue;
} try {
acc.QueryInterface(aInterfaces[index]);
} catch (e) { if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE)) {
ok( false, "Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID
);
}
returnnull;
}
}
return acc;
}
/** * Return true if the given identifier has an accessible, or exposes the wanted * interfaces.
*/ function isAccessible(aAccOrElmOrID, aInterfaces) { return !!getAccessible(
aAccOrElmOrID,
aInterfaces, null,
DONOTFAIL_IF_NO_ACC | DONOTFAIL_IF_NO_INTERFACE
);
}
/** * Return an accessible that contains the DOM node for the given identifier.
*/ function getContainerAccessible(aAccOrElmOrID) { var node = getNode(aAccOrElmOrID); if (!node) { returnnull;
}
/** * Return root accessible for the given identifier.
*/ function getRootAccessible(aAccOrElmOrID) { var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document); return acc ? acc.rootDocument.QueryInterface(nsIAccessible) : null;
}
/** * Return tab document accessible the given accessible is contained by.
*/ function getTabDocAccessible(aAccOrElmOrID) { var acc = getAccessible(aAccOrElmOrID ? aAccOrElmOrID : document);
var docAcc = acc.document.QueryInterface(nsIAccessible); var containerDocAcc = docAcc.parent.document;
// Test is running is stand-alone mode. if (acc.rootDocument == containerDocAcc) { return docAcc;
}
// In the case of running all tests together. return containerDocAcc.QueryInterface(nsIAccessible);
}
/** * A version of accessible tree testing, doesn't fail if tree is not complete.
*/ function testElm(aID, aTreeObj) {
testAccessibleTree(aID, aTreeObj, kSkipTreeFullCheck);
}
/** * Flags used for testAccessibleTree
*/ const kSkipTreeFullCheck = 1;
/** * Compare expected and actual accessibles trees. * * @param aAccOrElmOrID [in] accessible identifier * @param aAccTree [in] JS object, each field corresponds to property of * accessible object. Additionally special properties * are presented: * children - an array of JS objects representing * children of accessible * states - an object having states and extraStates * fields * @param aFlags [in, optional] flags, see constants above
*/ // eslint-disable-next-line complexity function testAccessibleTree(aAccOrElmOrID, aAccTree, aFlags) { var acc = getAccessible(aAccOrElmOrID); if (!acc) { return;
}
var accTree = aAccTree;
// Support of simplified accessible tree object.
accTree = normalizeAccTreeObj(accTree);
// Test accessible properties. for (var prop in accTree) { var msg = "Wrong value of property '" + prop + "' for " + prettyName(acc) + ".";
// nsIAccessible::indexInParent var indexInParent = -1; 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 nextSibling = null; 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 prevSibling = null; 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);
}
}
}
}
/** * Return true if accessible for the given node is in cache.
*/ function isAccessibleInCache(aNodeOrId) { var node = getNode(aNodeOrId); return !!gAccService.getAccessibleFromCache(node);
}
/** * Test accessible tree for defunct accessible. * * @param aAcc [in] the defunct accessible * @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!"
);
}
var msg = " doesn't fail for shut down accessible " + prettyName(aNodeOrId) + "!";
/** * Convert role to human readable string.
*/ function roleToString(aRole) { return gAccService.getStringRole(aRole);
}
/** * Convert states to human readable string.
*/ function statesToString(aStates, aExtraStates) { var list = gAccService.getStringStates(aStates, aExtraStates);
var str = ""; for (var index = 0; index < list.length - 1; index++) {
str += list.item(index) + ", ";
}
if (list.length) {
str += list.item(index);
}
return str;
}
/** * Convert event type to human readable string.
*/ function eventTypeToString(aEventType) { return gAccService.getStringEventType(aEventType);
}
/** * Convert relation type to human readable string.
*/ function relationTypeToString(aRelationType) { return gAccService.getStringRelationType(aRelationType);
}
function getLoadContext() { return window.docShell.QueryInterface(Ci.nsILoadContext);
}
/** * Return text from clipboard.
*/ function getTextFromClipboard() { var trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
Ci.nsITransferable
);
trans.init(getLoadContext()); if (!trans) { return"";
}
var str = {};
trans.getTransferData("text/plain", str);
if (str) {
str = str.value.QueryInterface(Ci.nsISupportsString);
} if (str) { return str.data;
}
return"";
}
/** * Extract DOMNode id from an accessible. If e10s is enabled, DOMNode is not * present in parent process but, if available, DOMNode id is attached to an * accessible object. * @param {nsIAccessible} accessible accessible * @return {String?} DOMNode id if available
*/ function getAccessibleDOMNodeID(accessible) { if (accessible instanceof nsIAccessibleDocument) { // 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. */
}
} try { return accessible.DOMNode.id;
} 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. */
} returnnull;
}
/** * Return pretty name for identifier, it may be ID, DOM node or accessible.
*/ function prettyName(aIdentifier) { if (aIdentifier instanceof Array) {
let msg = ""; for (var idx = 0; idx < aIdentifier.length; idx++) { if (msg != "") {
msg += ", ";
}
if (aIdentifier && typeof aIdentifier === "object") { var treeObj = normalizeAccTreeObj(aIdentifier); if ("role" in treeObj) { function stringifyTree(aObj) { var text = roleToString(aObj.role) + ": [ "; if ("children" in aObj) { for (var i = 0; i < aObj.children.length; i++) { var c = normalizeAccTreeObj(aObj.children[i]);
text += stringifyTree(c); if (i < aObj.children.length - 1) {
text += ", ";
}
}
} return text + "] ";
} return `{ ${stringifyTree(treeObj)} }`;
} return JSON.stringify(aIdentifier);
}
return" '" + aIdentifier + "' ";
}
/** * Shorten a long string if it exceeds MAX_TRIM_LENGTH. * @param aString the string to shorten. * @returns the shortened string.
*/ function shortenString(aString) { 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)
);
}
// ////////////////////////////////////////////////////////////////////////////// // General Utils // ////////////////////////////////////////////////////////////////////////////// /** * Return main chrome window (crosses chrome boundary)
*/ function getMainChromeWindow(aWindow) { return aWindow.browsingContext.topChromeWindow;
}
// ////////////////////////////////////////////////////////////////////////////// // Accessible general
function getNodePrettyName(aNode) { try { var tag = ""; if (aNode.nodeType == Node.DOCUMENT_NODE) {
tag = "document";
} else {
tag = aNode.localName; if (aNode.nodeType == Node.ELEMENT_NODE && aNode.hasAttribute("id")) {
tag += '@id="' + aNode.getAttribute("id") + '"';
}
}
return"'" + tag + " node', address: " + getObjAddress(aNode);
} catch (e) { return"' no node info '";
}
}
function getObjAddress(aObj) { var exp = /native\s*@\s*(0x[a-f0-9]+)/g; var match = exp.exec(aObj.toString()); if (match) { return match[1];
}
return aObj.toString();
}
function normalizeAccTreeObj(aObj) { var key = Object.keys(aObj)[0]; var roleName = "ROLE_" + key; if (roleName in nsIAccessibleRole) { return {
role: nsIAccessibleRole[roleName],
children: aObj[key],
};
} return aObj;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.