mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-08 12:22:34 +00:00
2b036e45c5
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D35962 --HG-- extra : source : c0948f31e520ca087279cf429ca5f1db5a8341b8
213 lines
6.4 KiB
JavaScript
213 lines
6.4 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* This module implements a number of utility functions that can be loaded
|
|
* into content scope.
|
|
*
|
|
* All asynchronous helper methods should return promises, rather than being
|
|
* callback based.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
var EXPORTED_SYMBOLS = ["ContentTaskUtils"];
|
|
|
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
const { clearInterval, setInterval, setTimeout } = ChromeUtils.import(
|
|
"resource://gre/modules/Timer.jsm"
|
|
);
|
|
|
|
var ContentTaskUtils = {
|
|
/**
|
|
* Checks if a DOM element is hidden.
|
|
*
|
|
* @param {Element} element
|
|
* The element which is to be checked.
|
|
*
|
|
* @return {boolean}
|
|
*/
|
|
is_hidden(element) {
|
|
var style = element.ownerGlobal.getComputedStyle(element);
|
|
if (style.display == "none") {
|
|
return true;
|
|
}
|
|
if (style.visibility != "visible") {
|
|
return true;
|
|
}
|
|
|
|
// Hiding a parent element will hide all its children
|
|
if (element.parentNode != element.ownerDocument) {
|
|
return ContentTaskUtils.is_hidden(element.parentNode);
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Checks if a DOM element is visible.
|
|
*
|
|
* @param {Element} element
|
|
* The element which is to be checked.
|
|
*
|
|
* @return {boolean}
|
|
*/
|
|
is_visible(element) {
|
|
var style = element.ownerGlobal.getComputedStyle(element);
|
|
if (style.display == "none") {
|
|
return false;
|
|
}
|
|
if (style.visibility != "visible") {
|
|
return false;
|
|
}
|
|
|
|
// Hiding a parent element will hide all its children
|
|
if (element.parentNode != element.ownerDocument) {
|
|
return ContentTaskUtils.is_visible(element.parentNode);
|
|
}
|
|
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Will poll a condition function until it returns true.
|
|
*
|
|
* @param condition
|
|
* A condition function that must return true or false. If the
|
|
* condition ever throws, this is also treated as a false.
|
|
* @param msg
|
|
* The message to use when the returned promise is rejected.
|
|
* This message will be extended with additional information
|
|
* about the number of tries or the thrown exception.
|
|
* @param interval
|
|
* The time interval to poll the condition function. Defaults
|
|
* to 100ms.
|
|
* @param maxTries
|
|
* The number of times to poll before giving up and rejecting
|
|
* if the condition has not yet returned true. Defaults to 50
|
|
* (~5 seconds for 100ms intervals)
|
|
* @return Promise
|
|
* Resolves when condition is true.
|
|
* Rejects if timeout is exceeded or condition ever throws.
|
|
*/
|
|
waitForCondition(condition, msg, interval = 100, maxTries = 50) {
|
|
return new Promise((resolve, reject) => {
|
|
let tries = 0;
|
|
let intervalID = setInterval(() => {
|
|
if (tries >= maxTries) {
|
|
clearInterval(intervalID);
|
|
msg += ` - timed out after ${maxTries} tries.`;
|
|
reject(msg);
|
|
return;
|
|
}
|
|
|
|
let conditionPassed = false;
|
|
try {
|
|
conditionPassed = condition();
|
|
} catch (e) {
|
|
msg += ` - threw exception: ${e}`;
|
|
clearInterval(intervalID);
|
|
reject(msg);
|
|
return;
|
|
}
|
|
|
|
if (conditionPassed) {
|
|
clearInterval(intervalID);
|
|
resolve(conditionPassed);
|
|
}
|
|
tries++;
|
|
}, interval);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Waits for an event to be fired on a specified element.
|
|
*
|
|
* Usage:
|
|
* let promiseEvent = ContentTasKUtils.waitForEvent(element, "eventName");
|
|
* // Do some processing here that will cause the event to be fired
|
|
* // ...
|
|
* // Now yield until the Promise is fulfilled
|
|
* let receivedEvent = yield promiseEvent;
|
|
*
|
|
* @param {Element} subject
|
|
* The element that should receive the event.
|
|
* @param {string} eventName
|
|
* Name of the event to listen to.
|
|
* @param {bool} capture [optional]
|
|
* True to use a capturing listener.
|
|
* @param {function} checkFn [optional]
|
|
* Called with the Event object as argument, should return true if the
|
|
* event is the expected one, or false if it should be ignored and
|
|
* listening should continue. If not specified, the first event with
|
|
* the specified name resolves the returned promise.
|
|
*
|
|
* @note Because this function is intended for testing, any error in checkFn
|
|
* will cause the returned promise to be rejected instead of waiting for
|
|
* the next event, since this is probably a bug in the test.
|
|
*
|
|
* @returns {Promise}
|
|
* @resolves The Event object.
|
|
*/
|
|
waitForEvent(subject, eventName, capture, checkFn, wantsUntrusted = false) {
|
|
return new Promise((resolve, reject) => {
|
|
subject.addEventListener(
|
|
eventName,
|
|
function listener(event) {
|
|
try {
|
|
if (checkFn && !checkFn(event)) {
|
|
return;
|
|
}
|
|
subject.removeEventListener(eventName, listener, capture);
|
|
setTimeout(() => resolve(event), 0);
|
|
} catch (ex) {
|
|
try {
|
|
subject.removeEventListener(eventName, listener, capture);
|
|
} catch (ex2) {
|
|
// Maybe the provided object does not support removeEventListener.
|
|
}
|
|
setTimeout(() => reject(ex), 0);
|
|
}
|
|
},
|
|
capture,
|
|
wantsUntrusted
|
|
);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Gets an instance of the `EventUtils` helper module for usage in
|
|
* content tasks. See https://searchfox.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/EventUtils.js
|
|
*
|
|
* @param content
|
|
* The `content` global object from your content task.
|
|
*
|
|
* @returns an EventUtils instance.
|
|
*/
|
|
getEventUtils(content) {
|
|
if (content._EventUtils) {
|
|
return content._EventUtils;
|
|
}
|
|
|
|
let EventUtils = (content._EventUtils = {});
|
|
|
|
EventUtils.window = {};
|
|
EventUtils.parent = EventUtils.window;
|
|
/* eslint-disable camelcase */
|
|
EventUtils._EU_Ci = Ci;
|
|
EventUtils._EU_Cc = Cc;
|
|
/* eslint-enable camelcase */
|
|
// EventUtils' `sendChar` function relies on the navigator to synthetize events.
|
|
EventUtils.navigator = content.navigator;
|
|
EventUtils.KeyboardEvent = content.KeyboardEvent;
|
|
|
|
Services.scriptloader.loadSubScript(
|
|
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
|
|
EventUtils
|
|
);
|
|
|
|
return EventUtils;
|
|
},
|
|
};
|