Merge mozilla-central to inbound a=merge on a CLOSED TREE

This commit is contained in:
Coroiu Cristina 2018-12-12 00:01:36 +02:00
commit 59f79d44b0
188 changed files with 2885 additions and 2915 deletions

View File

@ -36,6 +36,7 @@ uriloader/exthandler/**
uriloader/exthandler/tests/mochitest/**
widget/headless/tests/**
widget/tests/**
xpfe/**
# We currently have no js files in these directories, so we ignore them by
# default to aid ESLint's performance.
@ -50,7 +51,6 @@ mozglue/**
nsprpub/**
other-licenses/**
startupcache/**
xpfe/**
# These directories only contain crashtests, but we still skip the whole
# directory to aid performance.
@ -239,6 +239,7 @@ dom/xul/**
# Third-party
dom/canvas/test/webgl-conf/**
dom/imptests/**
dom/media/webaudio/test/blink/**
dom/media/webvtt/**
# Third-party
@ -255,6 +256,9 @@ intl/locale/**
intl/strres/**
intl/uconv/**
# Third-party
layout/mathml/imptests/**
# Exclude everything but self-hosted JS
js/ductwork/**
js/examples/**

View File

@ -1354,9 +1354,12 @@ pref("dom.debug.propagate_gesture_events_through_content", false);
// All the Geolocation preferences are here.
//
#ifndef EARLY_BETA_OR_EARLIER
pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
// MLS URL:
// pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
#else
// Use MLS on Nightly and early Beta.
pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
#endif
#ifdef XP_MACOSX
pref("geo.provider.use_corelocation", true);

View File

@ -231,22 +231,6 @@ function initPage() {
var errContainer = document.getElementById("errorContainer");
errContainer.remove();
if (className && className != "expertBadCert") {
// Associate a CSS class with the root of the page, if one was passed in,
// to allow custom styling.
// Not "expertBadCert" though, don't want to deal with the favicon
document.documentElement.className = className;
// Also, if they specified a CSS class, they must supply their own
// favicon. In order to trigger the browser to repaint though, we
// need to remove/add the link element.
var favicon = document.getElementById("favicon");
var faviconParent = favicon.parentNode;
faviconParent.removeChild(favicon);
favicon.setAttribute("href", "chrome://global/skin/icons/" + className + "_favicon.png");
faviconParent.appendChild(favicon);
}
if (err == "remoteXUL") {
// Remove the "Try again" button for remote XUL errors given that
// it is useless.

View File

@ -2122,13 +2122,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
}
// Set the direction of the popup based on the textbox (bug 649840).
// getComputedStyle causes a layout flush, so avoid calling it if a
// direction has already been set.
if (!this.style.direction) {
this.style.direction =
aElement.ownerGlobal.getComputedStyle(aElement).direction;
}
let popupDirection = this.style.direction;
let popupDirection = this.style.direction = (RTL_UI ? "rtl" : "ltr");
// Make the popup span the width of the window. First, set its width.
let documentRect =

View File

@ -258,9 +258,7 @@ class PageAction {
headerLabel.value = await this.getStrings(content.heading_text);
headerLink.setAttribute("href", SUMO_BASE_URL + content.info_icon.sumo_path);
const isRTL = this.window.getComputedStyle(notification).direction === "rtl";
const attribute = isRTL ? "left" : "right";
headerLink.setAttribute(attribute, 0);
headerLink.setAttribute(this.window.RTL_UI ? "left" : "right", 0);
headerImage.setAttribute("tooltiptext", await this.getStrings(content.info_icon.label, "tooltiptext"));
headerLink.onclick = () => this._sendTelemetry({message_id: id, bucket_id: content.bucket_id, event: "RATIONALE"});

View File

@ -627,6 +627,20 @@ var paymentDialogWrapper = {
this.sendMessageToContent("responseSent");
},
async onChangePayerAddress({payerAddressGUID}) {
if (payerAddressGUID) {
// If a payer address was de-selected e.g. the selected address was deleted, we'll
// just wait to send the address change when the payer address is eventually selected
// before clicking Pay since it's a required field.
let {
payerName,
payerEmail,
payerPhone,
} = await this._convertProfileAddressToPayerData(payerAddressGUID);
paymentSrv.changePayerDetail(this.request.requestId, payerName, payerEmail, payerPhone);
}
},
async onChangeShippingAddress({shippingAddressGUID}) {
if (shippingAddressGUID) {
// If a shipping address was de-selected e.g. the selected address was deleted, we'll
@ -733,6 +747,10 @@ var paymentDialogWrapper = {
this.initializeFrame();
break;
}
case "changePayerAddress": {
this.onChangePayerAddress(data);
break;
}
case "changeShippingAddress": {
this.onChangeShippingAddress(data);
break;

View File

@ -132,7 +132,17 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
paymentRequest.pay(data);
}
/**
* Called when the selectedShippingAddress or its properties are changed.
* @param {string} shippingAddressGUID
*/
changeShippingAddress(shippingAddressGUID) {
// Clear shipping address merchant errors when the shipping address changes.
let request = Object.assign({}, this.requestStore.getState().request);
request.paymentDetails = Object.assign({}, request.paymentDetails);
request.paymentDetails.shippingAddressErrors = {};
this.requestStore.setState({request});
paymentRequest.changeShippingAddress({
shippingAddressGUID,
});
@ -144,6 +154,36 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
});
}
/**
* Called when the selectedPaymentCard or its relevant properties or billingAddress are changed.
* @param {string} selectedPaymentCardGUID
*/
changePaymentMethod(selectedPaymentCardGUID) {
// Clear paymentMethod merchant errors when the paymentMethod or billingAddress changes.
let request = Object.assign({}, this.requestStore.getState().request);
request.paymentDetails = Object.assign({}, request.paymentDetails);
request.paymentDetails.paymentMethodErrors = null;
this.requestStore.setState({request});
// TODO: Bug 1477113 - Dispatch paymentmethodchange
}
/**
* Called when the selectedPayerAddress or its relevant properties are changed.
* @param {string} payerAddressGUID
*/
changePayerAddress(payerAddressGUID) {
// Clear payer address merchant errors when the payer address changes.
let request = Object.assign({}, this.requestStore.getState().request);
request.paymentDetails = Object.assign({}, request.paymentDetails);
request.paymentDetails.payerErrors = {};
this.requestStore.setState({request});
paymentRequest.changePayerAddress({
payerAddressGUID,
});
}
_isPayerRequested(paymentOptions) {
return paymentOptions.requestPayerName ||
paymentOptions.requestPayerEmail ||
@ -188,8 +228,9 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
*
* @param {object} state - See `PaymentsStore.setState`
*/
async setStateFromParent(state) {
async setStateFromParent(state) { // eslint-disable-line complexity
let oldAddresses = paymentRequest.getAddresses(this.requestStore.getState());
let oldBasicCards = paymentRequest.getBasicCards(this.requestStore.getState());
if (state.request) {
state = this._updateCompleteStatus(state);
}
@ -204,33 +245,67 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
selectedShippingOption,
} = state;
let addresses = paymentRequest.getAddresses(state);
let shippingOptions = state.request.paymentDetails.shippingOptions;
let shippingAddress = selectedShippingAddress && addresses[selectedShippingAddress];
let oldShippingAddress = selectedShippingAddress &&
oldAddresses[selectedShippingAddress];
let {paymentOptions} = state.request;
// Ensure `selectedShippingAddress` never refers to a deleted address.
// We also compare address timestamps to notify about changes
// made outside the payments UI.
if (shippingAddress) {
// invalidate the cached value if the address was modified
if (oldShippingAddress &&
shippingAddress.guid == oldShippingAddress.guid &&
shippingAddress.timeLastModified != oldShippingAddress.timeLastModified) {
delete this._cachedState.selectedShippingAddress;
if (paymentOptions.requestShipping) {
let shippingOptions = state.request.paymentDetails.shippingOptions;
let shippingAddress = selectedShippingAddress && addresses[selectedShippingAddress];
let oldShippingAddress = selectedShippingAddress &&
oldAddresses[selectedShippingAddress];
// Ensure `selectedShippingAddress` never refers to a deleted address.
// We also compare address timestamps to notify about changes
// made outside the payments UI.
if (shippingAddress) {
// invalidate the cached value if the address was modified
if (oldShippingAddress &&
shippingAddress.guid == oldShippingAddress.guid &&
shippingAddress.timeLastModified != oldShippingAddress.timeLastModified) {
delete this._cachedState.selectedShippingAddress;
}
} else if (selectedShippingAddress !== null) {
// null out the `selectedShippingAddress` property if it is undefined,
// or if the address it pointed to was removed from storage.
log.debug("resetting invalid/deleted shipping address");
this.requestStore.setState({
selectedShippingAddress: null,
});
}
// Ensure `selectedShippingOption` never refers to a deleted shipping option and
// matches the merchant's selected option if the user hasn't made a choice.
if (shippingOptions && (!selectedShippingOption ||
!shippingOptions.find(opt => opt.id == selectedShippingOption))) {
this._cachedState.selectedShippingOption = selectedShippingOption;
this.requestStore.setState({
// Use the DOM's computed selected shipping option:
selectedShippingOption: state.request.shippingOption,
});
}
}
let basicCards = paymentRequest.getBasicCards(state);
let oldPaymentMethod = selectedPaymentCard && oldBasicCards[selectedPaymentCard];
let paymentMethod = selectedPaymentCard && basicCards[selectedPaymentCard];
if (oldPaymentMethod && paymentMethod.guid == oldPaymentMethod.guid &&
paymentMethod.timeLastModified != oldPaymentMethod.timeLastModified) {
delete this._cachedState.selectedPaymentCard;
} else {
// Changes to the billing address record don't change the `timeLastModified`
// on the card record so we have to check for changes to the address separately.
let billingAddressGUID = paymentMethod && paymentMethod.billingAddressGUID;
let billingAddress = billingAddressGUID && addresses[billingAddressGUID];
let oldBillingAddress = billingAddressGUID && oldAddresses[billingAddressGUID];
if (oldBillingAddress && billingAddress &&
billingAddress.timeLastModified != oldBillingAddress.timeLastModified) {
delete this._cachedState.selectedPaymentCard;
}
} else if (selectedShippingAddress !== null) {
// null out the `selectedShippingAddress` property if it is undefined,
// or if the address it pointed to was removed from storage.
log.debug("resetting invalid/deleted shipping address");
this.requestStore.setState({
selectedShippingAddress: null,
});
}
// Ensure `selectedPaymentCard` never refers to a deleted payment card and refers
// to a payment card if one exists.
let basicCards = paymentRequest.getBasicCards(state);
if (!basicCards[selectedPaymentCard]) {
// Determining the initial selection is tracked in bug 1455789
this.requestStore.setState({
@ -239,23 +314,26 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
});
}
// Ensure `selectedShippingOption` never refers to a deleted shipping option and
// matches the merchant's selected option if the user hasn't made a choice.
if (shippingOptions && (!selectedShippingOption ||
!shippingOptions.find(option => option.id == selectedShippingOption))) {
this._cachedState.selectedShippingOption = selectedShippingOption;
this.requestStore.setState({
// Use the DOM's computed selected shipping option:
selectedShippingOption: state.request.shippingOption,
});
}
if (this._isPayerRequested(state.request.paymentOptions)) {
let payerAddress = selectedPayerAddress && addresses[selectedPayerAddress];
let oldPayerAddress = selectedPayerAddress && oldAddresses[selectedPayerAddress];
// Ensure `selectedPayerAddress` never refers to a deleted address and refers
// to an address if one exists.
if (!addresses[selectedPayerAddress]) {
this.requestStore.setState({
selectedPayerAddress: Object.keys(addresses)[0] || null,
});
if (oldPayerAddress && payerAddress && (
(paymentOptions.requestPayerName && payerAddress.name != oldPayerAddress.name) ||
(paymentOptions.requestPayerEmail && payerAddress.email != oldPayerAddress.email) ||
(paymentOptions.requestPayerPhone && payerAddress.tel != oldPayerAddress.tel)
)) {
// invalidate the cached value if the payer address fields were modified
delete this._cachedState.selectedPayerAddress;
}
// Ensure `selectedPayerAddress` never refers to a deleted address and refers
// to an address if one exists.
if (!addresses[selectedPayerAddress]) {
this.requestStore.setState({
selectedPayerAddress: Object.keys(addresses)[0] || null,
});
}
}
}
@ -354,8 +432,20 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
}
}
if (state.selectedPaymentCard != this._cachedState.selectedPaymentCard) {
this.changePaymentMethod(state.selectedPaymentCard);
}
if (this._isPayerRequested(state.request.paymentOptions)) {
if (state.selectedPayerAddress != this._cachedState.selectedPayerAddress) {
this.changePayerAddress(state.selectedPayerAddress);
}
}
this._cachedState.selectedShippingAddress = state.selectedShippingAddress;
this._cachedState.selectedShippingOption = state.selectedShippingOption;
this._cachedState.selectedPaymentCard = state.selectedPaymentCard;
this._cachedState.selectedPayerAddress = state.selectedPayerAddress;
}
render(state) {

View File

@ -200,6 +200,10 @@ var paymentRequest = {
this.sendMessageToChrome("changeShippingOption", data);
},
changePayerAddress(data) {
this.sendMessageToChrome("changePayerAddress", data);
},
/**
* Add/update an autofill storage record.
*

View File

@ -76,16 +76,31 @@ var PaymentTestUtils = {
content[eventName + "Promise"] =
new Promise(resolve => {
content.rq.addEventListener(eventName, () => {
info(`Received event: ${eventName}`);
resolve();
});
});
},
awaitPaymentRequestEventPromise: async ({eventName}) => {
/**
* Used for PaymentRequest and PaymentResponse event promises.
*/
awaitPaymentEventPromise: async ({eventName}) => {
await content[eventName + "Promise"];
return true;
},
promisePaymentResponseEvent: async ({eventName}) => {
let response = await content.showPromise;
content[eventName + "Promise"] =
new Promise(resolve => {
response.addEventListener(eventName, () => {
info(`Received event: ${eventName}`);
resolve();
});
});
},
updateWith: async ({eventName, details}) => {
/* globals ok */
if (details.error &&
@ -176,15 +191,15 @@ var PaymentTestUtils = {
doc.querySelector("address-picker[selected-state-key='selectedShippingAddress']");
let select = Cu.waiveXrays(addressPicker).dropdown.popupBox;
let option = select.querySelector(`[country="${country}"]`);
if (Cu.waiveXrays(doc.activeElement) == select) {
// If the <select> is already focused, blur and re-focus to reset the
// filter-as-you-type timer so that the synthesizeKey below will work
// correctly if this method was called recently.
select.blur();
}
select.focus();
// eslint-disable-next-line no-undef
EventUtils.synthesizeKey(option.label, {}, content.window);
content.fillField(select, option.value);
},
selectPayerAddressByGuid: guid => {
let doc = content.document;
let addressPicker =
doc.querySelector("address-picker[selected-state-key='selectedPayerAddress']");
let select = Cu.waiveXrays(addressPicker).dropdown.popupBox;
content.fillField(select, guid);
},
selectShippingAddressByGuid: guid => {
@ -192,16 +207,7 @@ var PaymentTestUtils = {
let addressPicker =
doc.querySelector("address-picker[selected-state-key='selectedShippingAddress']");
let select = Cu.waiveXrays(addressPicker).dropdown.popupBox;
let option = select.querySelector(`[guid="${guid}"]`);
if (Cu.waiveXrays(doc.activeElement) == select) {
// If the <select> is already focused, blur and re-focus to reset the
// filter-as-you-type timer so that the synthesizeKey below will work
// correctly if this method was called recently.
select.blur();
}
select.focus();
// eslint-disable-next-line no-undef
EventUtils.synthesizeKey(option.label, {}, content.window);
content.fillField(select, guid);
},
selectShippingOptionById: value => {
@ -209,33 +215,14 @@ var PaymentTestUtils = {
let optionPicker =
doc.querySelector("shipping-option-picker");
let select = Cu.waiveXrays(optionPicker).dropdown.popupBox;
let option = select.querySelector(`[value="${value}"]`);
if (Cu.waiveXrays(doc.activeElement) == select) {
// If the <select> is already focused, blur and re-focus to reset the
// filter-as-you-type timer so that the synthesizeKey below will work
// correctly if this method was called recently.
select.blur();
}
select.focus();
// eslint-disable-next-line no-undef
EventUtils.synthesizeKey(option.textContent, {}, content.window);
content.fillField(select, value);
},
selectPaymentOptionByGuid: guid => {
let doc = content.document;
let methodPicker = doc.querySelector("payment-method-picker");
let select = Cu.waiveXrays(methodPicker).dropdown.popupBox;
let option = select.querySelector(`[value="${guid}"]`);
if (Cu.waiveXrays(doc.activeElement) == select) {
// If the <select> is already focused, blur and re-focus to reset the
// filter-as-you-type timer so that the synthesizeKey below will work
// correctly if this method was called recently.
select.blur();
}
select.focus();
// just type the first few characters to select the right option
// eslint-disable-next-line no-undef
EventUtils.synthesizeKey(option.textContent.substring(0, 4), {}, content.window);
content.fillField(select, guid);
},
/**
@ -249,7 +236,7 @@ var PaymentTestUtils = {
let {requestStore} = Cu.waiveXrays(content.document.querySelector("payment-dialog"));
let {page} = requestStore.getState();
let button = content.document.querySelector(`#${page.id} button.primary`);
ok(!button.disabled, "Primary button should not be disabled when clicking it");
ok(!button.disabled, `#${page.id} primary button should not be disabled when clicking it`);
button.click();
},
@ -273,7 +260,15 @@ var PaymentTestUtils = {
*
* @returns {undefined}
*/
completePayment: () => {
completePayment: async () => {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
await PTU.DialogContentUtils.waitForState(content, (state) => {
return state.page.id == "payment-summary";
}, "Wait for change to payment-summary before clicking Pay");
let button = content.document.getElementById("pay");
ok(!button.disabled, "Pay button should not be disabled when clicking it");
button.click();
@ -532,7 +527,7 @@ var PaymentTestUtils = {
"postal-code": "02138",
country: "DE",
tel: "+16172535702",
email: "timbl@example.org",
email: "timbl@example.com",
},
/* Used as a temporary (not persisted in autofill storage) address in tests */
Temp: {

View File

@ -25,6 +25,7 @@ skip-if = debug && (os == 'mac' || os == 'linux') # bug 1465673
[browser_request_serialization.js]
[browser_request_shipping.js]
[browser_retry.js]
[browser_retry_fieldErrors.js]
[browser_shippingaddresschange_error.js]
[browser_show_dialog.js]
skip-if = os == 'win' && debug # bug 1418385

View File

@ -58,7 +58,7 @@ add_task(async function test_add_link() {
for (let options of testOptions) {
let shippingAddressChangePromise = ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
await manuallyAddShippingAddress(frame, newAddress, options);
await shippingAddressChangePromise;
@ -108,7 +108,7 @@ add_task(async function test_edit_link() {
let shippingAddressChangePromise = ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
const EXPECTED_ADDRESS = {
"given-name": "Jaws",
@ -556,7 +556,7 @@ add_task(async function test_private_persist_addresses() {
info("awaiting the shippingaddresschange event");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
await spawnPaymentDialogTask(frame, async (args) => {
let {address, tempAddressGuid} = args;

View File

@ -41,7 +41,7 @@ add_task(async function test_hiddenFieldNotSaved() {
let shippingAddressChangePromise = ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
let options = {
addLinkSelector: "address-picker.shipping-related .add-link",
@ -108,7 +108,7 @@ add_task(async function test_hiddenFieldRemovedWhenCountryChanged() {
let shippingAddressChangePromise = ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
await spawnPaymentDialogTask(frame, async (args) => {
let {

View File

@ -58,7 +58,7 @@ add_task(async function test_change_shipping() {
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
info("got shippingaddresschange event");
// verify update of shippingOptions
@ -177,7 +177,7 @@ add_task(async function test_default_shippingOptions_noneSelected() {
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
info("got shippingaddresschange event");
shippingOptions =
@ -236,7 +236,7 @@ add_task(async function test_default_shippingOptions_allSelected() {
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
info("got shippingaddresschange event");
shippingOptions =
@ -330,7 +330,7 @@ add_task(async function test_address_edit() {
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
addressOptions =
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.getShippingAddresses);

View File

@ -0,0 +1,543 @@
"use strict";
/**
* Test the merchant calling .retry() with field-specific errors.
*/
async function setup() {
await setupFormAutofillStorage();
await cleanupFormAutofillStorage();
// add 2 addresses and 2 cards to avoid the FTU sequence and test address errors
let prefilledGuids = await addSampleAddressesAndBasicCard(
[PTU.Addresses.TimBL, PTU.Addresses.TimBL2],
[PTU.BasicCards.JaneMasterCard, PTU.BasicCards.JohnDoe]);
info("associating card1 with a billing address");
await formAutofillStorage.creditCards.update(prefilledGuids.card1GUID, {
billingAddressGUID: prefilledGuids.address1GUID,
}, true);
info("associating card2 with a billing address");
await formAutofillStorage.creditCards.update(prefilledGuids.card2GUID, {
billingAddressGUID: prefilledGuids.address1GUID,
}, true);
return prefilledGuids;
}
add_task(async function test_retry_with_shipppingAddressErrors() {
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
todo(false, "Cannot test OS key store login on official builds.");
return;
}
await setup();
await BrowserTestUtils.withNewTab({
gBrowser,
url: BLANK_PAGE_URL,
}, async browser => {
let {win, frame} = await setupPaymentDialog(browser, {
methodData: [PTU.MethodData.basicCard],
details: Object.assign({}, PTU.Details.twoShippingOptions, PTU.Details.total60USD),
options: PTU.Options.requestShippingOption,
merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
});
await selectPaymentDialogShippingAddressByCountry(frame, "DE");
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.setSecurityCode, {
securityCode: "123",
});
info("clicking the button to try pay the 1st time");
await loginAndCompletePayment(frame);
let retryUpdatePromise = spawnPaymentDialogTask(frame, async function checkDialog() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "processing";
}, "Wait for completeStatus from pay button click");
is(state.request.completeStatus, "processing", "Check completeStatus is processing");
is(state.request.paymentDetails.shippingAddressErrors.country, undefined,
"Check country error string is empty");
ok(state.changesPrevented, "Changes prevented");
state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "";
}, "Wait for completeStatus from DOM update");
is(state.request.completeStatus, "", "Check completeStatus");
is(state.request.paymentDetails.shippingAddressErrors.country, "Can only ship to USA",
"Check country error string in state");
ok(!state.changesPrevented, "Changes no longer prevented");
is(state.page.id, "payment-summary", "Check still on payment-summary");
ok(content.document.querySelector("#payment-summary").innerText
.includes("Can only ship to USA"),
"Check error visibility on summary page");
ok(content.document.getElementById("pay").disabled,
"Pay button should be disabled until the field error is addressed");
});
// Add a handler to retry the payment above.
info("Tell merchant page to retry with a country error string");
let retryPromise = ContentTask.spawn(browser,
{
delayMs: 1000,
validationErrors: {
shippingAddress: {
country: "Can only ship to USA",
},
},
},
PTU.ContentTasks.addRetryHandler);
await retryUpdatePromise;
info("Changing to a US address to clear the error");
await selectPaymentDialogShippingAddressByCountry(frame, "US");
info("Tell merchant page to retry with a regionCode error string");
let retryPromise2 = ContentTask.spawn(browser,
{
delayMs: 1000,
validationErrors: {
shippingAddress: {
regionCode: "Can only ship to California",
},
},
},
PTU.ContentTasks.addRetryHandler);
await loginAndCompletePayment(frame);
await spawnPaymentDialogTask(frame, async function checkRegionError() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "";
}, "Wait for completeStatus from DOM update");
is(state.request.completeStatus, "", "Check completeStatus");
is(state.request.paymentDetails.shippingAddressErrors.regionCode,
"Can only ship to California",
"Check regionCode error string in state");
ok(!state.changesPrevented, "Changes no longer prevented");
is(state.page.id, "payment-summary", "Check still on payment-summary");
ok(content.document.querySelector("#payment-summary").innerText
.includes("Can only ship to California"),
"Check error visibility on summary page");
ok(content.document.getElementById("pay").disabled,
"Pay button should be disabled until the field error is addressed");
});
info("Changing the shipping state to CA without changing selectedShippingAddress");
await navigateToAddShippingAddressPage(frame, {
addLinkSelector: "address-picker[selected-state-key=\"selectedShippingAddress\"] .edit-link",
});
await fillInShippingAddressForm(frame, { "address-level1": "CA" });
await submitAddressForm(frame, null, {isEditing: true});
await loginAndCompletePayment(frame);
// We can only check the retry response after the closing as it only resolves upon complete.
let {retryException} = await retryPromise;
ok(!retryException, "Expect no exception to be thrown when calling retry()");
let {retryException2} = await retryPromise2;
ok(!retryException2, "Expect no exception to be thrown when calling retry()");
// Add a handler to complete the payment above.
info("acknowledging the completion from the merchant page");
let result = await ContentTask.spawn(browser, {}, PTU.ContentTasks.addCompletionHandler);
// Verify response has the expected properties
let expectedDetails = Object.assign({
"cc-security-code": "123",
}, PTU.BasicCards.JohnDoe);
checkPaymentMethodDetailsMatchesCard(result.response.details, expectedDetails,
"Check response payment details");
checkPaymentAddressMatchesStorageAddress(result.response.shippingAddress,
{...PTU.Addresses.TimBL, ...{"address-level1": "CA"}},
"Check response shipping address");
await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
});
});
add_task(async function test_retry_with_payerErrors() {
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
todo(false, "Cannot test OS key store login on official builds.");
return;
}
let prefilledGuids = await setup();
await BrowserTestUtils.withNewTab({
gBrowser,
url: BLANK_PAGE_URL,
}, async browser => {
let {win, frame} = await setupPaymentDialog(browser, {
methodData: [PTU.MethodData.basicCard],
details: PTU.Details.total60USD,
options: PTU.Options.requestPayerNameEmailAndPhone,
merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
});
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.setSecurityCode, {
securityCode: "123",
});
info("clicking the button to try pay the 1st time");
await loginAndCompletePayment(frame);
let retryUpdatePromise = spawnPaymentDialogTask(frame, async function checkDialog() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "processing";
}, "Wait for completeStatus from pay button click");
is(state.request.completeStatus, "processing", "Check completeStatus is processing");
is(state.request.paymentDetails.payerErrors.email, undefined,
"Check email error isn't present");
ok(state.changesPrevented, "Changes prevented");
state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "";
}, "Wait for completeStatus from DOM update");
is(state.request.completeStatus, "", "Check completeStatus");
is(state.request.paymentDetails.payerErrors.email, "You must use your employee email address",
"Check email error string in state");
ok(!state.changesPrevented, "Changes no longer prevented");
is(state.page.id, "payment-summary", "Check still on payment-summary");
ok(content.document.querySelector("#payment-summary").innerText
.includes("You must use your employee email address"),
"Check error visibility on summary page");
ok(content.document.getElementById("pay").disabled,
"Pay button should be disabled until the field error is addressed");
});
// Add a handler to retry the payment above.
info("Tell merchant page to retry with a country error string");
let retryPromise = ContentTask.spawn(browser,
{
delayMs: 1000,
validationErrors: {
payer: {
email: "You must use your employee email address",
},
},
},
PTU.ContentTasks.addRetryHandler);
await retryUpdatePromise;
info("Changing to a different email address to clear the error");
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.selectPayerAddressByGuid,
prefilledGuids.address1GUID);
info("Tell merchant page to retry with a phone error string");
let retryPromise2 = ContentTask.spawn(browser,
{
delayMs: 1000,
validationErrors: {
payer: {
phone: "Your phone number isn't valid",
},
},
},
PTU.ContentTasks.addRetryHandler);
await loginAndCompletePayment(frame);
await spawnPaymentDialogTask(frame, async function checkRegionError() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "";
}, "Wait for completeStatus from DOM update");
is(state.request.completeStatus, "", "Check completeStatus");
is(state.request.paymentDetails.payerErrors.phone,
"Your phone number isn't valid",
"Check regionCode error string in state");
ok(!state.changesPrevented, "Changes no longer prevented");
is(state.page.id, "payment-summary", "Check still on payment-summary");
ok(content.document.querySelector("#payment-summary").innerText
.includes("Your phone number isn't valid"),
"Check error visibility on summary page");
ok(content.document.getElementById("pay").disabled,
"Pay button should be disabled until the field error is addressed");
});
info("Changing the payer phone to be valid without changing selectedPayerAddress");
await navigateToAddAddressPage(frame, {
addLinkSelector: "address-picker[selected-state-key=\"selectedPayerAddress\"] .edit-link",
initialPageId: "payment-summary",
addressPageId: "payer-address-page",
});
let newPhoneNumber = "+16175555555";
await fillInPayerAddressForm(frame, { tel: newPhoneNumber });
await ContentTask.spawn(browser, {
eventName: "payerdetailchange",
}, PTU.ContentTasks.promisePaymentResponseEvent);
await submitAddressForm(frame, null, {isEditing: true});
await ContentTask.spawn(browser, {
eventName: "payerdetailchange",
}, PTU.ContentTasks.awaitPaymentEventPromise);
await loginAndCompletePayment(frame);
// We can only check the retry response after the closing as it only resolves upon complete.
let {retryException} = await retryPromise;
ok(!retryException, "Expect no exception to be thrown when calling retry()");
let {retryException2} = await retryPromise2;
ok(!retryException2, "Expect no exception to be thrown when calling retry()");
// Add a handler to complete the payment above.
info("acknowledging the completion from the merchant page");
let result = await ContentTask.spawn(browser, {}, PTU.ContentTasks.addCompletionHandler);
// Verify response has the expected properties
let expectedDetails = Object.assign({
"cc-security-code": "123",
}, PTU.BasicCards.JohnDoe);
checkPaymentMethodDetailsMatchesCard(result.response.details, expectedDetails,
"Check response payment details");
let {
"given-name": givenName,
"additional-name": additionalName,
"family-name": familyName,
email,
} = PTU.Addresses.TimBL;
is(result.response.payerName, `${givenName} ${additionalName} ${familyName}`,
"Check payer name");
is(result.response.payerEmail, email, "Check payer email");
is(result.response.payerPhone, newPhoneNumber, "Check payer phone");
await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
});
});
add_task(async function test_retry_with_paymentMethodErrors() {
if (!OSKeyStoreTestUtils.canTestOSKeyStoreLogin()) {
todo(false, "Cannot test OS key store login on official builds.");
return;
}
let prefilledGuids = await setup();
await BrowserTestUtils.withNewTab({
gBrowser,
url: BLANK_PAGE_URL,
}, async browser => {
let {win, frame} = await setupPaymentDialog(browser, {
methodData: [PTU.MethodData.basicCard],
details: PTU.Details.total60USD,
merchantTaskFn: PTU.ContentTasks.createAndShowRequest,
});
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.setSecurityCode, {
securityCode: "123",
});
info("clicking the button to try pay the 1st time");
await loginAndCompletePayment(frame);
let retryUpdatePromise = spawnPaymentDialogTask(frame, async function checkDialog() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "processing";
}, "Wait for completeStatus from pay button click");
is(state.request.completeStatus, "processing", "Check completeStatus is processing");
is(state.request.paymentDetails.paymentMethodErrors, null,
"Check no paymentMethod errors are present");
ok(state.changesPrevented, "Changes prevented");
state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "";
}, "Wait for completeStatus from DOM update");
is(state.request.completeStatus, "", "Check completeStatus");
is(state.request.paymentDetails.paymentMethodErrors.cardSecurityCode,
"Your CVV is incorrect",
"Check cardSecurityCode error string in state");
ok(!state.changesPrevented, "Changes no longer prevented");
is(state.page.id, "payment-summary", "Check still on payment-summary");
todo(content.document.querySelector("#payment-summary").innerText
.includes("Your CVV is incorrect"),
"Bug 1491815: Check error visibility on summary page");
todo(content.document.getElementById("pay").disabled,
"Bug 1491815: Pay button should be disabled until the field error is addressed");
});
// Add a handler to retry the payment above.
info("Tell merchant page to retry with a cardSecurityCode error string");
let retryPromise = ContentTask.spawn(browser,
{
delayMs: 1000,
validationErrors: {
paymentMethod: {
cardSecurityCode: "Your CVV is incorrect",
},
},
},
PTU.ContentTasks.addRetryHandler);
await retryUpdatePromise;
info("Changing to a different card to clear the error");
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.selectPaymentOptionByGuid,
prefilledGuids.card1GUID);
info("Tell merchant page to retry with a billing postalCode error string");
let retryPromise2 = ContentTask.spawn(browser,
{
delayMs: 1000,
validationErrors: {
paymentMethod: {
billingAddress: {
postalCode: "Your postal code isn't valid",
},
},
},
},
PTU.ContentTasks.addRetryHandler);
await loginAndCompletePayment(frame);
await spawnPaymentDialogTask(frame, async function checkPostalCodeError() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
let state = await PTU.DialogContentUtils.waitForState(content, ({request}) => {
return request.completeStatus === "";
}, "Wait for completeStatus from DOM update");
is(state.request.completeStatus, "", "Check completeStatus");
is(state.request.paymentDetails.paymentMethodErrors.billingAddress.postalCode,
"Your postal code isn't valid",
"Check postalCode error string in state");
ok(!state.changesPrevented, "Changes no longer prevented");
is(state.page.id, "payment-summary", "Check still on payment-summary");
todo(content.document.querySelector("#payment-summary").innerText
.includes("Your postal code isn't valid"),
"Bug 1491815: Check error visibility on summary page");
todo(content.document.getElementById("pay").disabled,
"Bug 1491815: Pay button should be disabled until the field error is addressed");
});
info("Changing the billingAddress postalCode to be valid without changing selectedPaymentCard");
await navigateToAddCardPage(frame, {
addLinkSelector: "payment-method-picker .edit-link",
});
await navigateToAddAddressPage(frame, {
addLinkSelector: ".billingAddressRow .edit-link",
initialPageId: "basic-card-page",
addressPageId: "billing-address-page",
});
let newPostalCode = "90210";
await fillInBillingAddressForm(frame, { "postal-code": newPostalCode });
await ContentTask.spawn(browser, {
eventName: "paymentmethodchange",
}, PTU.ContentTasks.promisePaymentResponseEvent);
await submitAddressForm(frame, null, {
isEditing: true,
nextPageId: "basic-card-page",
});
await spawnPaymentDialogTask(frame, async function checkErrorsCleared() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
await PTU.DialogContentUtils.waitForState(content, (state) => {
return state.request.paymentDetails.paymentMethodErrors == null;
},
"Check no paymentMethod errors are present");
});
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.clickPrimaryButton);
await spawnPaymentDialogTask(frame, async function checkErrorsCleared() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
await PTU.DialogContentUtils.waitForState(content, (state) => {
return state.request.paymentDetails.paymentMethodErrors == null;
},
"Check no card errors are present after save");
});
// TODO: Add an `await` here after bug 1477113.
ContentTask.spawn(browser, {
eventName: "paymentmethodchange",
}, PTU.ContentTasks.awaitPaymentEventPromise);
await loginAndCompletePayment(frame);
// We can only check the retry response after the closing as it only resolves upon complete.
let {retryException} = await retryPromise;
ok(!retryException, "Expect no exception to be thrown when calling retry()");
let {retryException2} = await retryPromise2;
ok(!retryException2, "Expect no exception to be thrown when calling retry()");
// Add a handler to complete the payment above.
info("acknowledging the completion from the merchant page");
let result = await ContentTask.spawn(browser, {}, PTU.ContentTasks.addCompletionHandler);
// Verify response has the expected properties
let expectedDetails = Object.assign({
"cc-security-code": "123",
}, PTU.BasicCards.JaneMasterCard);
let expectedBillingAddress = Object.assign({}, PTU.Addresses.TimBL, {
"postal-code": newPostalCode,
});
checkPaymentMethodDetailsMatchesCard(result.response.details, expectedDetails,
"Check response payment details");
checkPaymentAddressMatchesStorageAddress(result.response.details.billingAddress,
expectedBillingAddress,
"Check response billing address");
await BrowserTestUtils.waitForCondition(() => win.closed, "dialog should be closed");
});
});

View File

@ -34,7 +34,7 @@ add_task(async function test_show_error_on_addresschange() {
info("awaiting the shippingoptionchange event");
await ContentTask.spawn(browser, {
eventName: "shippingoptionchange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
await spawnPaymentDialogTask(frame, expectedText => {
let errorText = content.document.querySelector("header .page-error");
@ -56,7 +56,7 @@ add_task(async function test_show_error_on_addresschange() {
info("awaiting the shippingaddresschange event");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
await spawnPaymentDialogTask(frame, () => {
let errorText = content.document.querySelector("header .page-error");
@ -101,7 +101,7 @@ add_task(async function test_show_field_specific_error_on_addresschange() {
info("awaiting the shippingaddresschange event");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
await spawnPaymentDialogTask(frame, async () => {
let {
@ -160,6 +160,52 @@ add_task(async function test_show_field_specific_error_on_addresschange() {
}
});
info("setting up the event handler for a 2nd shippingaddresschange with a different error");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
details: Object.assign({},
{
shippingAddressErrors: {
phone: "Invalid phone number",
},
},
PTU.Details.noShippingOptions,
PTU.Details.total2USD),
}, PTU.ContentTasks.updateWith);
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.clickPrimaryButton);
await spawnPaymentDialogTask(frame, async function checkForNewErrors() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
await PTU.DialogContentUtils.waitForState(content, (state) => {
return state.page.id == "payment-summary" &&
state.request.paymentDetails.shippingAddressErrors.phone == "Invalid phone number";
}, "Check the new error is in state");
ok(content.document.querySelector("#payment-summary").innerText
.includes("Invalid phone number"),
"Check error visibility on summary page");
ok(content.document.getElementById("pay").disabled,
"Pay button should be disabled until the field error is addressed");
});
await navigateToAddShippingAddressPage(frame, {
addLinkSelector: "address-picker[selected-state-key=\"selectedShippingAddress\"] .edit-link",
});
await spawnPaymentDialogTask(frame, async function checkForNewErrorOnEdit() {
let addressForm = content.document.querySelector("#shipping-address-page");
is(addressForm.querySelectorAll(".error-text:not(:empty)").length, 1,
"Check one error shown");
});
await fillInShippingAddressForm(frame, {
tel: PTU.Addresses.TimBL2.tel,
});
info("setup updateWith to clear errors");
await ContentTask.spawn(browser, {
eventName: "shippingaddresschange",
@ -168,14 +214,13 @@ add_task(async function test_show_field_specific_error_on_addresschange() {
PTU.Details.total2USD),
}, PTU.ContentTasks.updateWith);
await spawnPaymentDialogTask(frame, async () => {
await spawnPaymentDialogTask(frame, PTU.DialogContentTasks.clickPrimaryButton);
await spawnPaymentDialogTask(frame, async function fixLastError() {
let {
PaymentTestUtils: PTU,
} = ChromeUtils.import("resource://testing-common/PaymentTestUtils.jsm", {});
info("saving corrections");
content.document.querySelector("#shipping-address-page .save-button").click();
await PTU.DialogContentUtils.waitForState(content, (state) => {
return state.page.id == "payment-summary";
}, "Check we're back on summary view");

View File

@ -128,7 +128,7 @@ add_task(async function test_show_completePayment2() {
await ContentTask.spawn(browser, {
eventName: "shippingoptionchange",
}, PTU.ContentTasks.awaitPaymentRequestEventPromise);
}, PTU.ContentTasks.awaitPaymentEventPromise);
info("got shippingoptionchange event");
info("select the shipping address");

View File

@ -431,7 +431,7 @@ async function navigateToAddAddressPage(frame, aOptions = {}) {
async function navigateToAddShippingAddressPage(frame, aOptions = {}) {
let options = Object.assign({
addLinkSelector: "address-picker[selected-state-key=\"selectedShippingAddress\"] a.add-link",
addLinkSelector: "address-picker[selected-state-key=\"selectedShippingAddress\"] .add-link",
initialPageId: "payment-summary",
addressPageId: "shipping-address-page",
}, aOptions);

View File

@ -548,7 +548,7 @@
arrowbox.style.transform = "translate(0, " + -offset + "px)";
// The assigned side stays the same regardless of direction.
var isRTL = (window.getComputedStyle(this).direction == "rtl");
let isRTL = this.matches(":-moz-locale-dir(rtl)");
if (position.indexOf("start_") == 0) {
container.dir = "reverse";

View File

@ -91,7 +91,7 @@
onsyncfrompreference="return gMainPane.readLinkTarget();"
onsynctopreference="return gMainPane.writeLinkTarget();"/>
<checkbox id="warnCloseMultiple" data-l10n-id="warn-on-quit-close-multiple-tabs"
<checkbox id="warnCloseMultiple" data-l10n-id="warn-on-close-multiple-tabs"
preference="browser.tabs.warnOnClose"/>
<checkbox id="warnOpenMany" data-l10n-id="warn-on-open-many-tabs"

View File

@ -198,7 +198,7 @@
data-l10n-id="do-not-track-learn-more"></label></label>
<radiogroup id="doNotTrackRadioGroup" aria-labelledby="doNotTrackDesc" preference="privacy.donottrackheader.enabled">
<radio value="true" data-l10n-id="do-not-track-option-always"/>
<radio value="false" data-l10n-id="do-not-track-option-default-content-blocking"/>
<radio value="false" data-l10n-id="do-not-track-option-default-content-blocking-known"/>
</radiogroup>
</vbox>
</vbox>

View File

@ -2,6 +2,6 @@
module.exports = {
"extends": [
"plugin:mozilla/browser-test"
"plugin:mozilla/chrome-test",
]
};

View File

@ -4,8 +4,8 @@
do-not-track-description = Send websites a “Do Not Track” signal that you dont want to be tracked
do-not-track-learn-more = Learn more
do-not-track-option-default-content-blocking =
.label = Only when { -brand-short-name } is set to block Detected Trackers
do-not-track-option-default-content-blocking-known =
.label = Only when { -brand-short-name } is set to block known trackers
do-not-track-option-always =
.label = Always
@ -178,8 +178,8 @@ open-new-link-as-tabs =
.label = Open links in tabs instead of new windows
.accesskey = w
warn-on-quit-close-multiple-tabs =
.label = Warn you when quitting and closing multiple tabs
warn-on-close-multiple-tabs =
.label = Warn you when closing multiple tabs
.accesskey = m
warn-on-open-many-tabs =

View File

@ -18,3 +18,8 @@
.tracking-protection-button > .button-box > .button-icon {
margin-inline-end: 5px;
}
/* This overrides color: -moz-buttonhovertext from toolbarbutton.css */
.identity-popup-content-blocking-category:hover {
color: inherit;
}

View File

@ -11,11 +11,10 @@ const protocol = require("devtools/shared/protocol");
/**
* The corresponding Front object for the CallWatcherActor.
*/
var CallWatcherFront =
exports.CallWatcherFront =
protocol.FrontClassWithSpec(callWatcherSpec, {
initialize: function(client, { callWatcherActor }) {
protocol.Front.prototype.initialize.call(this, client, { actor: callWatcherActor });
class CallWatcherFront extends protocol.FrontClassWithSpec(callWatcherSpec) {
constructor(client, { callWatcherActor }) {
super(client, { actor: callWatcherActor });
this.manage(this);
},
});
}
}
exports.CallWatcherFront = CallWatcherFront;

View File

@ -9,7 +9,6 @@ DIRS += [
BROWSER_CHROME_MANIFESTS += [
'new/test/mochitest/browser.ini',
'test/mochitest/browser.ini'
]
with Files('**'):

View File

@ -1,6 +0,0 @@
"use strict";
module.exports = {
// Extend from the shared list of defined globals for mochitests.
"extends": "../../../.eslintrc.mochitests.js"
};

View File

@ -1,27 +0,0 @@
[DEFAULT]
tags = devtools
subsuite = devtools
skip-if = (os == 'linux' && debug && bits == 32)
support-files =
doc_promise-get-allocation-stack.html
doc_promise-get-fulfillment-stack.html
doc_promise-get-rejection-stack.html
doc_terminate-on-tab-close.html
head.js
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
[browser_dbg_promises-allocation-stack.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_promises-chrome-allocation-stack.js]
uses-unsafe-cpows = true
skip-if = true # Bug 1177730
[browser_dbg_promises-fulfillment-stack.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_promises-rejection-stack.js]
uses-unsafe-cpows = true
skip-if = true
[browser_dbg_terminate-on-tab-close.js]
uses-unsafe-cpows = true
skip-if = true

View File

@ -1,87 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's allocation point.
*/
"use strict";
const TAB_URL = EXAMPLE_URL + "doc_promise-get-allocation-stack.html";
const { PromisesFront } = require("devtools/shared/fronts/promises");
var EventEmitter = require("devtools/shared/event-emitter");
function test() {
Task.spawn(function* () {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let options = {
source: TAB_URL,
line: 1
};
const [ tab, panel ] = yield initDebugger(TAB_URL, options);
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let { tabs } = yield listTabs(client);
let targetTab = findTab(tabs, TAB_URL);
yield attachTarget(client, targetTab);
yield testGetAllocationStack(client, targetTab, tab);
yield close(client);
yield closeDebuggerAndFinish(panel);
}).catch(error => {
ok(false, "Got an error: " + error.message + "\n" + error.stack);
});
}
function* testGetAllocationStack(client, form, tab) {
let front = PromisesFront(client, form);
yield front.attach();
yield front.listPromises();
// Get the grip for promise p
let onNewPromise = new Promise(resolve => {
EventEmitter.on(front, "new-promises", promises => {
for (let p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
callInTab(tab, "makePromises");
let grip = yield onNewPromise;
ok(grip, "Found our promise p");
let objectClient = new ObjectClient(client, grip);
ok(objectClient, "Got Object Client");
yield new Promise(resolve => {
objectClient.getPromiseAllocationStack(response => {
ok(response.allocationStack.length, "Got promise allocation stack.");
for (let stack of response.allocationStack) {
is(stack.source.url, TAB_URL, "Got correct source URL.");
is(stack.functionDisplayName, "makePromises",
"Got correct function display name.");
is(typeof stack.line, "number", "Expect stack line to be a number.");
is(typeof stack.column, "number",
"Expect stack column to be a number.");
}
resolve();
});
});
yield front.detach();
}

View File

@ -1,100 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's allocation point in the chrome
* process.
*/
"use strict";
const SOURCE_URL = "browser_dbg_promises-chrome-allocation-stack.js";
const PromisesFront = require("devtools/shared/fronts/promises");
var EventEmitter = require("devtools/shared/event-emitter");
const STACK_DATA = [
{ functionDisplayName: "test/</<" },
{ functionDisplayName: "testGetAllocationStack" },
];
function test() {
Task.spawn(function* () {
requestLongerTimeout(10);
DebuggerServer.init();
DebuggerServer.registerAllActors();
DebuggerServer.allowChromeProcess = true;
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let targetFront = yield client.mainRoot.getMainProcess();
yield targetFront.attach();
yield targetFront.attachThread();
yield testGetAllocationStack(client, chrome.form, () => {
let p = new Promise(() => {});
p.name = "p";
let q = p.then();
q.name = "q";
let r = p.catch(() => {});
r.name = "r";
});
yield close(client);
finish();
}).catch(error => {
ok(false, "Got an error: " + error.message + "\n" + error.stack);
});
}
function* testGetAllocationStack(client, form, makePromises) {
let front = PromisesFront(client, form);
yield front.attach();
yield front.listPromises();
// Get the grip for promise p
let onNewPromise = new Promise(resolve => {
EventEmitter.on(front, "new-promises", promises => {
for (let p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
makePromises();
let grip = yield onNewPromise;
ok(grip, "Found our promise p");
let objectClient = new ObjectClient(client, grip);
ok(objectClient, "Got Object Client");
yield new Promise(resolve => {
objectClient.getPromiseAllocationStack(response => {
ok(response.allocationStack.length, "Got promise allocation stack.");
for (let i = 0; i < STACK_DATA.length; i++) {
let data = STACK_DATA[i];
let stack = response.allocationStack[i];
ok(stack.source.url.startsWith("chrome:"), "Got a chrome source URL");
ok(stack.source.url.endsWith(SOURCE_URL), "Got correct source URL.");
is(stack.functionDisplayName, data.functionDisplayName,
"Got correct function display name.");
is(typeof stack.line, "number", "Expect stack line to be a number.");
is(typeof stack.column, "number",
"Expect stack column to be a number.");
}
resolve();
});
});
yield front.detach();
}

View File

@ -1,106 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's fulfillment point.
*/
"use strict";
const TAB_URL = EXAMPLE_URL + "doc_promise-get-fulfillment-stack.html";
const { PromisesFront } = require("devtools/shared/fronts/promises");
var EventEmitter = require("devtools/shared/event-emitter");
const TEST_DATA = [
{
functionDisplayName: "returnPromise/<",
line: 19,
column: 37
},
{
functionDisplayName: "returnPromise",
line: 19,
column: 14
},
{
functionDisplayName: "makePromise",
line: 14,
column: 15
},
];
function test() {
Task.spawn(function* () {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let options = {
source: TAB_URL,
line: 1
};
const [ tab, panel ] = yield initDebugger(TAB_URL, options);
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let { tabs } = yield listTabs(client);
let targetTab = findTab(tabs, TAB_URL);
yield attachTarget(client, targetTab);
yield testGetFulfillmentStack(client, targetTab, tab);
yield close(client);
yield closeDebuggerAndFinish(panel);
}).catch(error => {
ok(false, "Got an error: " + error.message + "\n" + error.stack);
});
}
function* testGetFulfillmentStack(client, form, tab) {
let front = PromisesFront(client, form);
yield front.attach();
yield front.listPromises();
// Get the grip for promise p
let onNewPromise = new Promise(resolve => {
EventEmitter.on(front, "new-promises", promises => {
for (let p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
callInTab(tab, "makePromise");
let grip = yield onNewPromise;
ok(grip, "Found our promise p");
let objectClient = new ObjectClient(client, grip);
ok(objectClient, "Got Object Client");
yield new Promise(resolve => {
objectClient.getPromiseFulfillmentStack(response => {
ok(response.fulfillmentStack.length, "Got promise allocation stack.");
for (let i = 0; i < TEST_DATA.length; i++) {
let stack = response.fulfillmentStack[i];
let data = TEST_DATA[i];
is(stack.source.url, TAB_URL, "Got correct source URL.");
is(stack.functionDisplayName, data.functionDisplayName,
"Got correct function display name.");
is(stack.line, data.line, "Got correct stack line number.");
is(stack.column, data.column, "Got correct stack column number.");
}
resolve();
});
});
yield front.detach();
}

View File

@ -1,113 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's rejection point.
*/
"use strict";
const TAB_URL = EXAMPLE_URL + "doc_promise-get-rejection-stack.html";
const { PromisesFront } = require("devtools/shared/fronts/promises");
var EventEmitter = require("devtools/shared/event-emitter");
// The code in the document above leaves an uncaught rejection. This is only
// reported to the testing framework if the code is loaded in the main process.
if (!gMultiProcessBrowser) {
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
PromiseTestUtils.expectUncaughtRejection(/hello/);
}
const TEST_DATA = [
{
functionDisplayName: "returnPromise/<",
line: 19,
column: 47
},
{
functionDisplayName: "returnPromise",
line: 19,
column: 14
},
{
functionDisplayName: "makePromise",
line: 14,
column: 15
},
];
function test() {
Task.spawn(function* () {
DebuggerServer.init();
DebuggerServer.registerAllActors();
let options = {
source: TAB_URL,
line: 1
};
const [ tab, panel ] = yield initDebugger(TAB_URL, options);
let client = new DebuggerClient(DebuggerServer.connectPipe());
yield connect(client);
let { tabs } = yield listTabs(client);
let targetTab = findTab(tabs, TAB_URL);
yield attachTarget(client, targetTab);
yield testGetRejectionStack(client, targetTab, tab);
yield close(client);
yield closeDebuggerAndFinish(panel);
}).catch(error => {
ok(false, "Got an error: " + error.message + "\n" + error.stack);
});
}
function* testGetRejectionStack(client, form, tab) {
let front = PromisesFront(client, form);
yield front.attach();
yield front.listPromises();
// Get the grip for promise p
let onNewPromise = new Promise(resolve => {
EventEmitter.on(front, "new-promises", promises => {
for (let p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
callInTab(tab, "makePromise");
let grip = yield onNewPromise;
ok(grip, "Found our promise p");
let objectClient = new ObjectClient(client, grip);
ok(objectClient, "Got Object Client");
yield new Promise(resolve => {
objectClient.getPromiseRejectionStack(response => {
ok(response.rejectionStack.length, "Got promise allocation stack.");
for (let i = 0; i < TEST_DATA.length; i++) {
let stack = response.rejectionStack[i];
let data = TEST_DATA[i];
is(stack.source.url, TAB_URL, "Got correct source URL.");
is(stack.functionDisplayName, data.functionDisplayName,
"Got correct function display name.");
is(stack.line, data.line, "Got correct stack line number.");
is(stack.column, data.column, "Got correct stack column number.");
}
resolve();
});
});
yield front.detach();
}

View File

@ -1,37 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that debuggee scripts are terminated on tab closure.
*/
// The following rejection should not be left uncaught. This test has been
// whitelisted until the issue is fixed.
if (!gMultiProcessBrowser) {
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
PromiseTestUtils.expectUncaughtRejection(/error\.message is undefined/);
}
const TAB_URL = EXAMPLE_URL + "doc_terminate-on-tab-close.html";
function test() {
let options = {
source: TAB_URL,
line: 1
};
initDebugger(TAB_URL, options).then(([aTab, aPanel]) => {
const gTab = aTab;
const gPanel = aPanel;
const gDebugger = gPanel.panelWin;
gDebugger.gThreadClient.addOneTimeListener("paused", () => {
resumeDebuggerThenCloseAndFinish(gPanel).then(function () {
ok(true, "should not throw after this point");
});
});
callInTab(gTab, "debuggerThenThrow");
});
}

View File

@ -1,20 +0,0 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Debugger test page</title>
</head>
<body>
<script type="text/javascript">
function debuggerThenThrow() {
debugger;
throw "unreachable";
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -473,7 +473,7 @@ ResponsiveUI.prototype = {
this.client = new DebuggerClient(DebuggerServer.connectPipe());
await this.client.connect();
const { tab } = await this.client.getTab();
this.emulationFront = EmulationFront(this.client, tab);
this.emulationFront = new EmulationFront(this.client, tab);
},
/**

View File

@ -791,12 +791,13 @@ var TestActor = exports.TestActor = protocol.ActorClassWithSpec(testSpec, {
},
});
var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSpec, {
initialize: function(client, { testActor }, toolbox) {
protocol.Front.prototype.initialize.call(this, client, { actor: testActor });
class TestActorFront extends protocol.FrontClassWithSpec(testSpec) {
constructor(client, { testActor }, toolbox) {
super(client, { actor: testActor });
this.manage(this);
this.toolbox = toolbox;
},
}
/**
* Zoom the current page to a given level.
@ -805,19 +806,17 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
* @return {Promise} The returned promise will only resolve when the
* highlighter has updated to the new zoom level.
*/
zoomPageTo: function(level, actorID = this.toolbox.highlighter.actorID) {
zoomPageTo(level, actorID = this.toolbox.highlighter.actorID) {
return this.changeZoomLevel(level, actorID);
},
}
/* eslint-disable max-len */
changeHighlightedNodeWaitForUpdate: protocol.custom(function(name, value, highlighter) {
changeHighlightedNodeWaitForUpdate(name, value, highlighter) {
/* eslint-enable max-len */
return this._changeHighlightedNodeWaitForUpdate(
return super.changeHighlightedNodeWaitForUpdate(
name, value, (highlighter || this.toolbox.highlighter).actorID
);
}, {
impl: "_changeHighlightedNodeWaitForUpdate",
}),
}
/**
* Get the value of an attribute on one of the highlighter's node.
@ -826,27 +825,25 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
* @param {Object} highlighter Optional custom highlither to target
* @return {String} value
*/
getHighlighterNodeAttribute: function(nodeID, name, highlighter) {
getHighlighterNodeAttribute(nodeID, name, highlighter) {
return this.getHighlighterAttribute(
nodeID, name, (highlighter || this.toolbox.highlighter).actorID
);
},
}
getHighlighterNodeTextContent: protocol.custom(function(nodeID, highlighter) {
return this._getHighlighterNodeTextContent(
getHighlighterNodeTextContent(nodeID, highlighter) {
return super.getHighlighterNodeTextContent(
nodeID, (highlighter || this.toolbox.highlighter).actorID
);
}, {
impl: "_getHighlighterNodeTextContent",
}),
}
/**
* Is the highlighter currently visible on the page?
*/
isHighlighting: function() {
isHighlighting() {
return this.getHighlighterNodeAttribute("box-model-elements", "hidden")
.then(value => value === null);
},
}
/**
* Assert that the box-model highlighter's current position corresponds to the
@ -871,7 +868,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
prefix + boxType + " point " + point + " y coordinate is correct");
}
}
},
}
/**
* Get the current rect of the border region of the box-model highlighter
@ -886,7 +883,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
width: p2.x - p1.x,
height: p4.y - p1.y,
};
},
}
/**
* Get the current positions and visibility of the various box-model highlighter
@ -911,7 +908,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
}
return ret;
},
}
/**
* Check that the box-model highlighter is currently highlighting the node matching the
@ -922,7 +919,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
async assertHighlightedNode(selector) {
const rect = await this.getNodeRect(selector);
return this.isNodeRectHighlighted(rect);
},
}
/**
* Check that the box-model highlighter is currently highlighting the text node that can
@ -935,7 +932,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
async assertHighlightedTextNode(parentSelector, childNodeIndex) {
const rect = await this.getTextNodeRect(parentSelector, childNodeIndex);
return this.isNodeRectHighlighted(rect);
},
}
/**
* Check that the box-model highlighter is currently highlighting the given rect.
@ -966,7 +963,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
isInside([right, top], points) &&
isInside([right, bottom], points) &&
isInside([left, bottom], points);
},
}
/**
* Get the coordinate (points attribute) from one of the polygon elements in the
@ -1002,7 +999,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
y: parseFloat(points[3][1]),
},
};
},
}
/**
* Is a given region polygon element of the box-model highlighter currently
@ -1011,7 +1008,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
async _isRegionHidden(region) {
const value = await this.getHighlighterNodeAttribute("box-model-" + region, "hidden");
return value !== null;
},
}
async _getGuideStatus(location) {
const id = "box-model-guide-" + location;
@ -1029,7 +1026,7 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
x2: x2,
y2: y2,
};
},
}
/**
* Get the coordinates of the rectangle that is defined by the 4 guides displayed
@ -1053,13 +1050,11 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
p3: {x: +rGuide.x1 + 1, y: +bGuide.y1 + 1},
p4: {x: lGuide.x1, y: +bGuide.y1 + 1},
};
},
}
waitForHighlighterEvent: protocol.custom(function(event) {
return this._waitForHighlighterEvent(event, this.toolbox.highlighter.actorID);
}, {
impl: "_waitForHighlighterEvent",
}),
waitForHighlighterEvent(event) {
return super.waitForHighlighterEvent(event, this.toolbox.highlighter.actorID);
}
/**
* Get the "d" attribute value for one of the box-model highlighter's region
@ -1092,8 +1087,9 @@ var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSp
}
return {d, points};
},
});
}
}
exports.TestActorFront = TestActorFront;
/**
* Check whether a point is included in a polygon.

View File

@ -97,7 +97,7 @@ How do you get an initial reference to the front? That's a bit tricky, but basi
Manually - If you're using a DebuggerClient instance, you can discover the actorID manually and create a Front for it:
let hello = HelloFront(this.client, { actor: <hello actorID> });
let hello = new HelloFront(this.client, { actor: <hello actorID> });
Magically - Once you have an initial reference to a protocol.js object, it can return other protocol.js objects and fronts will automatically be created.

View File

@ -11,6 +11,9 @@ support-files =
doc_force_gc.html
doc_innerHTML.html
doc_perf.html
doc_promise-get-allocation-stack.html
doc_promise-get-fulfillment-stack.html
doc_promise-get-rejection-stack.html
error-actor.js
grid.html
inspectedwindow-reload-target.sjs
@ -102,3 +105,7 @@ skip-if = (verify && debug && (os == 'mac' || os == 'linux'))
[browser_stylesheets_nested-iframes.js]
[browser_register_actor.js]
[browser_webextension_inspected_window.js]
[browser_dbg_promises-allocation-stack.js]
[browser_dbg_promises-chrome-allocation-stack.js]
[browser_dbg_promises-fulfillment-stack.js]
[browser_dbg_promises-rejection-stack.js]

View File

@ -0,0 +1,68 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's allocation point.
*/
"use strict";
const TAB_URL = URL_ROOT + "doc_promise-get-allocation-stack.html";
const ObjectClient = require("devtools/shared/client/object-client");
add_task(async function test() {
const browser = await addTab(TAB_URL);
const tab = gBrowser.getTabForBrowser(browser);
const target = await TargetFactory.forTab(tab);
await target.attach();
await testGetAllocationStack(tab, target);
await target.destroy();
});
async function testGetAllocationStack(tab, target) {
const front = await target.getFront("promises");
await front.attach();
await front.listPromises();
// Get the grip for promise p
const onNewPromise = new Promise(resolve => {
front.on("new-promises", promises => {
for (const p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
await ContentTask.spawn(tab.linkedBrowser, {}, () => {
content.wrappedJSObject.makePromises();
});
const form = await onNewPromise;
ok(form, "Found our promise p");
const objectClient = new ObjectClient(target.client, form);
ok(objectClient, "Got Object Client");
const response = await objectClient.getPromiseAllocationStack();
ok(response.allocationStack.length, "Got promise allocation stack.");
for (const stack of response.allocationStack) {
is(stack.source.url, TAB_URL, "Got correct source URL.");
is(stack.functionDisplayName, "makePromises",
"Got correct function display name.");
is(typeof stack.line, "number", "Expect stack line to be a number.");
is(typeof stack.column, "number",
"Expect stack column to be a number.");
}
await front.detach();
}

View File

@ -0,0 +1,94 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's allocation point in the chrome
* process.
*/
"use strict";
const SOURCE_URL = "browser_dbg_promises-chrome-allocation-stack.js";
const ObjectClient = require("devtools/shared/client/object-client");
const STACK_DATA = [
{ functionDisplayName: "test/<" },
{ functionDisplayName: "testGetAllocationStack" },
];
add_task(async function test() {
requestLongerTimeout(10);
DebuggerServer.init();
DebuggerServer.registerAllActors();
DebuggerServer.allowChromeProcess = true;
const client = new DebuggerClient(DebuggerServer.connectPipe());
await client.connect();
const targetFront = await client.mainRoot.getMainProcess();
const target = await TargetFactory.forRemoteTab({
client,
activeTab: targetFront,
chrome: true,
});
await target.attach();
await testGetAllocationStack(client, target, () => {
const p = new Promise(() => {});
p.name = "p";
const q = p.then();
q.name = "q";
const r = p.catch(() => {});
r.name = "r";
});
await target.destroy();
});
async function testGetAllocationStack(client, target, makePromises) {
const front = await target.getFront("promises");
await front.attach();
await front.listPromises();
// Get the grip for promise p
const onNewPromise = new Promise(resolve => {
front.on("new-promises", promises => {
for (const p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
makePromises();
const form = await onNewPromise;
ok(form, "Found our promise p");
const objectClient = new ObjectClient(client, form);
ok(objectClient, "Got Object Client");
const response = await objectClient.getPromiseAllocationStack();
ok(response.allocationStack.length, "Got promise allocation stack.");
for (let i = 0; i < STACK_DATA.length; i++) {
const data = STACK_DATA[i];
const stack = response.allocationStack[i];
ok(stack.source.url.startsWith("chrome:"), "Got a chrome source URL");
ok(stack.source.url.endsWith(SOURCE_URL), "Got correct source URL.");
is(stack.functionDisplayName, data.functionDisplayName,
"Got correct function display name.");
is(typeof stack.line, "number", "Expect stack line to be a number.");
is(typeof stack.column, "number",
"Expect stack column to be a number.");
}
await front.detach();
}

View File

@ -0,0 +1,86 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's fulfillment point.
*/
"use strict";
const TAB_URL = URL_ROOT + "doc_promise-get-fulfillment-stack.html";
const ObjectClient = require("devtools/shared/client/object-client");
const TEST_DATA = [
{
functionDisplayName: "returnPromise/<",
line: 21,
column: 37,
},
{
functionDisplayName: "returnPromise",
line: 21,
column: 14,
},
{
functionDisplayName: "makePromise",
line: 16,
column: 17,
},
];
add_task(async () => {
const browser = await addTab(TAB_URL);
const tab = gBrowser.getTabForBrowser(browser);
const target = await TargetFactory.forTab(tab);
await target.attach();
await testGetFulfillmentStack(tab, target);
await target.destroy();
});
async function testGetFulfillmentStack(tab, target) {
const front = await target.getFront("promises");
await front.attach();
await front.listPromises();
// Get the grip for promise p
const onNewPromise = new Promise(resolve => {
front.on("new-promises", promises => {
for (const p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
content.wrappedJSObject.makePromise();
});
const form = await onNewPromise;
ok(form, "Found our promise p");
const objectClient = new ObjectClient(target.client, form);
ok(objectClient, "Got Object Client");
const response = await objectClient.getPromiseFulfillmentStack();
ok(response.fulfillmentStack.length, "Got promise allocation stack.");
for (let i = 0; i < TEST_DATA.length; i++) {
const stack = response.fulfillmentStack[i];
const data = TEST_DATA[i];
is(stack.source.url, TAB_URL, "Got correct source URL.");
is(stack.functionDisplayName, data.functionDisplayName,
"Got correct function display name.");
is(stack.line, data.line, "Got correct stack line number.");
is(stack.column, data.column, "Got correct stack column number.");
}
await front.detach();
}

View File

@ -0,0 +1,93 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can get a stack to a promise's rejection point.
*/
"use strict";
const TAB_URL = URL_ROOT + "doc_promise-get-rejection-stack.html";
const ObjectClient = require("devtools/shared/client/object-client");
// The code in the document above leaves an uncaught rejection. This is only
// reported to the testing framework if the code is loaded in the main process.
if (!gMultiProcessBrowser) {
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
PromiseTestUtils.expectUncaughtRejection(/hello/);
}
const TEST_DATA = [
{
functionDisplayName: "returnPromise/<",
line: 21,
column: 47,
},
{
functionDisplayName: "returnPromise",
line: 21,
column: 14,
},
{
functionDisplayName: "makePromise",
line: 16,
column: 17,
},
];
add_task(async () => {
const browser = await addTab(TAB_URL);
const tab = gBrowser.getTabForBrowser(browser);
const target = await TargetFactory.forTab(tab);
await target.attach();
await testGetRejectionStack(tab, target);
await target.destroy();
});
async function testGetRejectionStack(tab, target) {
const front = await target.getFront("promises");
await front.attach();
await front.listPromises();
// Get the grip for promise p
const onNewPromise = new Promise(resolve => {
front.on("new-promises", promises => {
for (const p of promises) {
if (p.preview.ownProperties.name &&
p.preview.ownProperties.name.value === "p") {
resolve(p);
}
}
});
});
await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
content.wrappedJSObject.makePromise();
});
const form = await onNewPromise;
ok(form, "Found our promise p");
const objectClient = new ObjectClient(target.client, form);
ok(objectClient, "Got Object Client");
const response = await objectClient.getPromiseRejectionStack();
ok(response.rejectionStack.length, "Got promise allocation stack.");
for (let i = 0; i < TEST_DATA.length; i++) {
const stack = response.rejectionStack[i];
const data = TEST_DATA[i];
is(stack.source.url, TAB_URL, "Got correct source URL.");
is(stack.functionDisplayName, data.functionDisplayName,
"Got correct function display name.");
is(stack.line, data.line, "Got correct stack line number.");
is(stack.column, data.column, "Got correct stack column number.");
}
await front.detach();
}

View File

@ -29,11 +29,11 @@ add_task(async function() {
const { client } = target;
const form = targetFront.targetForm;
const inContentFront = InContentFront(client, form);
const inContentFront = new InContentFront(client, form);
const isInContent = await inContentFront.isInContent();
ok(isInContent, "ContentActor really runs in the content process");
const formSpawn = await inContentFront.spawnInParent(ACTOR_URL);
const inParentFront = InParentFront(client, formSpawn);
const inParentFront = new InParentFront(client, formSpawn);
const {
args,
isInParent,

View File

@ -10,12 +10,15 @@
<body>
<script type="text/javascript">
"use strict";
// eslint-disable-next-line no-unused-vars
function makePromises() {
var p = new Promise(() => {});
const p = new Promise(() => {});
p.name = "p";
var q = p.then();
const q = p.then();
q.name = "q";
var r = p.catch(() => {});
const r = p.catch(() => {});
r.name = "r";
}
</script>

View File

@ -10,8 +10,10 @@
<body>
<script type="text/javascript">
"use strict";
// eslint-disable-next-line no-unused-vars
function makePromise() {
var p = returnPromise();
const p = returnPromise();
p.name = "p";
}

View File

@ -10,8 +10,10 @@
<body>
<script type="text/javascript">
"use strict";
// eslint-disable-next-line no-unused-vars
function makePromise() {
var p = returnPromise();
const p = returnPromise();
p.name = "p";
}

View File

@ -6,6 +6,7 @@
"use strict";
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec } = protocol;
const { DebuggerServerConnection } = require("devtools/server/main");
const Services = require("Services");
@ -51,13 +52,14 @@ exports.InContentActor = protocol.ActorClassWithSpec(inContentSpec, {
},
});
exports.InContentFront = protocol.FrontClassWithSpec(inContentSpec, {
initialize: function(client, tabForm) {
protocol.Front.prototype.initialize.call(this, client);
class InContentFront extends FrontClassWithSpec(inContentSpec) {
constructor(client, tabForm) {
super(client, tabForm);
this.actorID = tabForm.inContentActor;
this.manage(this);
},
});
}
}
exports.InContentFront = InContentFront;
const inParentSpec = protocol.generateActorSpec({
typeName: "inParent",
@ -91,10 +93,11 @@ exports.InParentActor = protocol.ActorClassWithSpec(inParentSpec, {
},
});
exports.InParentFront = protocol.FrontClassWithSpec(inParentSpec, {
initialize: function(client, tabForm) {
protocol.Front.prototype.initialize.call(this, client);
class InParentFront extends FrontClassWithSpec(inParentSpec) {
constructor(client, tabForm) {
super(client, tabForm);
this.actorID = tabForm.inParentActor;
this.manage(this);
},
});
}
}
exports.InParentFront = InParentFront;

View File

@ -3,7 +3,7 @@
"use strict";
var {RetVal, Actor, ActorClassWithSpec, Front, FrontClassWithSpec,
var {RetVal, Actor, ActorClassWithSpec, FrontClassWithSpec,
generateActorSpec} = require("devtools/shared/protocol");
var Services = require("Services");
@ -31,12 +31,13 @@ exports.LazyActor = ActorClassWithSpec(lazySpec, {
Services.obs.notifyObservers(null, "actor", "loaded");
exports.LazyFront = FrontClassWithSpec(lazySpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client);
class LazyFront extends FrontClassWithSpec(lazySpec) {
constructor(client, form) {
super(client, form);
this.actorID = form.lazyActor;
client.addActorPool(this);
this.manage(this);
},
});
}
}
exports.LazyFront = LazyFront;

View File

@ -27,7 +27,7 @@ add_task(async function() {
});
async function testAttach(client, parent) {
const promises = PromisesFront(client, parent);
const promises = new PromisesFront(client, parent);
try {
await promises.detach();

View File

@ -34,7 +34,7 @@ add_task(async function() {
async function testListPromises(client, form, makePromise) {
const resolution = SECRET + Math.random();
const promise = makePromise(resolution);
const front = PromisesFront(client, form);
const front = new PromisesFront(client, form);
await front.attach();

View File

@ -35,7 +35,7 @@ add_task(async function() {
});
async function testNewPromisesEvent(client, form, makePromise) {
const front = PromisesFront(client, form);
const front = new PromisesFront(client, form);
const resolution = "MyLittleSecret" + Math.random();
let found = false;

View File

@ -42,7 +42,7 @@ add_task(async function() {
async function testPromisesSettled(client, form, makeResolvePromise,
makeRejectPromise) {
const front = PromisesFront(client, form);
const front = new PromisesFront(client, form);
const resolution = "MyLittleSecret" + Math.random();
await front.attach();

View File

@ -50,7 +50,7 @@ add_task(async function() {
});
async function testGetDependentPromises(client, form, makePromises) {
const front = PromisesFront(client, form);
const front = new PromisesFront(client, form);
await front.attach();
await front.listPromises();

View File

@ -45,7 +45,7 @@ add_task(async function() {
});
async function testPromiseCreationTimestamp(client, form, makePromise) {
const front = PromisesFront(client, form);
const front = new PromisesFront(client, form);
const resolution = "MyLittleSecret" + Math.random();
await front.attach();

View File

@ -48,7 +48,7 @@ add_task(async function() {
});
async function testGetTimeToSettle(client, form, makePromises) {
const front = PromisesFront(client, form);
const front = new PromisesFront(client, form);
await front.attach();
await front.listPromises();

View File

@ -37,7 +37,7 @@ add_task(async function() {
});
async function testGetTimeToSettle(client, form, makePromise) {
const front = PromisesFront(client, form);
const front = new PromisesFront(client, form);
const resolution = "MyLittleSecret" + Math.random();
let found = false;

View File

@ -46,14 +46,14 @@ var RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
var RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize: function(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root owns itself.
this.manage(this);
},
});
}
}
function run_test() {
DebuggerServer.createRootActor = RootActor;
@ -64,7 +64,7 @@ function run_test() {
let rootFront;
client.connect().then(([applicationType, traits]) => {
rootFront = RootFront(client);
rootFront = new RootFront(client);
rootFront.simpleReturn().then(() => {
ok(false, "Connection was aborted, request shouldn't resolve");

View File

@ -90,14 +90,14 @@ var RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
var RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize: function(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root owns itself.
this.manage(this);
},
});
}
}
function run_test() {
DebuggerServer.createRootActor = RootActor;
@ -108,7 +108,7 @@ function run_test() {
let rootFront;
client.connect().then(([applicationType, traits]) => {
rootFront = RootFront(client);
rootFront = new RootFront(client);
const calls = [];
let sequence = 0;

View File

@ -8,7 +8,7 @@
* Test simple requests using the protocol helpers.
*/
var protocol = require("devtools/shared/protocol");
var {preEvent, types, Arg, RetVal} = protocol;
var {types, Arg, RetVal} = protocol;
var EventEmitter = require("devtools/shared/event-emitter");
@ -162,46 +162,51 @@ var ChildActor = protocol.ActorClassWithSpec(childSpec, {
release: function() { },
});
var ChildFront = protocol.FrontClassWithSpec(childSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
},
class ChildFront extends protocol.FrontClassWithSpec(childSpec) {
constructor(client, form) {
super(client, form);
destroy: function() {
this.before("event1", this.onEvent1.bind(this));
this.before("event2", this.onEvent2a.bind(this));
this.on("event2", this.onEvent2b.bind(this));
}
destroy() {
this.destroyed = true;
protocol.Front.prototype.destroy.call(this);
},
super.destroy();
}
marshallPool: function() {
marshallPool() {
return this.parent();
},
}
toString: function() {
toString() {
return "[child front " + this.childID + "]";
},
}
form: function(form, detail) {
form(form, detail) {
if (detail === "actorid") {
return;
}
this.childID = form.childID;
this.detail = form.detail;
},
}
onEvent1: preEvent("event1", function(a, b, c) {
onEvent1(a, b, c) {
this.event1arg3 = c;
}),
}
onEvent2a: preEvent("event2", function(a, b, c) {
onEvent2a(a, b, c) {
return Promise.resolve().then(() => {
this.event2arg3 = c;
});
}),
}
onEvent2b: preEvent("event2", function(a, b, c) {
onEvent2b(a, b, c) {
this.event2arg2 = b;
}),
});
}
}
protocol.registerFront(ChildFront);
types.addDictType("manyChildrenDict", {
child5: "childActor",
@ -301,39 +306,36 @@ var RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
var RootFront = protocol.FrontClassWithSpec(rootSpec, {
toString: function() {
return "[root front]";
},
initialize: function(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root actor owns itself.
this.manage(this);
},
}
getTemporaryChild: protocol.custom(function(id) {
toString() {
return "[root front]";
}
getTemporaryChild(id) {
if (!this._temporaryHolder) {
this._temporaryHolder = new protocol.Front(this.conn);
this._temporaryHolder.actorID = this.actorID + "_temp";
this.manage(this._temporaryHolder);
}
return this._getTemporaryChild(id);
}, {
impl: "_getTemporaryChild",
}),
return super.getTemporaryChild(id);
}
clearTemporaryChildren: protocol.custom(function() {
clearTemporaryChildren() {
if (!this._temporaryHolder) {
return Promise.resolve(undefined);
}
this._temporaryHolder.destroy();
delete this._temporaryHolder;
return this._clearTemporaryChildren();
}, {
impl: "_clearTemporaryChildren",
}),
});
return super.clearTemporaryChildren();
}
}
function run_test() {
DebuggerServer.createRootActor = (conn => {
@ -349,7 +351,7 @@ function run_test() {
"traits": []});
Assert.equal(applicationType, "xpcshell-tests");
const rootFront = RootFront(client);
const rootFront = new RootFront(client);
let childFront = null;
const expectRootChildren = size => {

View File

@ -34,15 +34,16 @@ var ChildActor = protocol.ActorClassWithSpec(childSpec, {
},
});
var ChildFront = protocol.FrontClassWithSpec(childSpec, {
initialize(client) {
protocol.Front.prototype.initialize.call(this, client);
},
class ChildFront extends protocol.FrontClassWithSpec(childSpec) {
constructor(client) {
super(client);
}
form(v, ctx, detail) {
this.extra = v.extra;
},
});
}
}
protocol.registerFront(ChildFront);
const rootSpec = protocol.generateActorSpec({
typeName: "root",
@ -127,19 +128,19 @@ var RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
var RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root owns itself.
this.manage(this);
},
}
form(v, ctx, detail) {
this.lastForm = v;
},
});
}
}
const run_test = Test(async function() {
DebuggerServer.createRootActor = (conn => {
@ -158,7 +159,7 @@ const run_test = Test(async function() {
// So override it again with test one before asserting.
protocol.types.registeredTypes.get("root").actorSpec = rootSpec;
const rootFront = RootFront(conn);
const rootFront = new RootFront(conn);
// Trigger some methods that return forms.
let retval = await rootFront.getDefault();

View File

@ -85,14 +85,15 @@ var RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
var RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize: function(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root owns itself.
this.manage(this);
},
});
}
}
function run_test() {
DebuggerServer.createRootActor = (conn => {
@ -112,7 +113,7 @@ function run_test() {
};
client.connect().then(([applicationType, traits]) => {
rootFront = RootFront(client);
rootFront = new RootFront(client);
// Root actor has no children yet.
expectRootChildren(0);

View File

@ -69,23 +69,24 @@ const RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
const ChildFront = protocol.FrontClassWithSpec(childSpec, {
class ChildFront extends protocol.FrontClassWithSpec(childSpec) {
form(form, detail) {
if (detail === "actorid") {
return;
}
this.childID = form.childID;
},
});
}
}
protocol.registerFront(ChildFront);
const RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root owns itself.
this.manage(this);
},
});
}
}
add_task(async function run_test() {
DebuggerServer.createRootActor = RootActor;

View File

@ -150,14 +150,14 @@ var RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
var RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize: function(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root owns itself.
this.manage(this);
},
});
}
}
function run_test() {
DebuggerServer.createRootActor = (conn => {
@ -166,10 +166,7 @@ function run_test() {
DebuggerServer.init();
Assert.throws(() => {
const badActor = protocol.ActorClassWithSpec({}, {
missing: protocol.preEvent("missing-event", function() {
}),
});
const badActor = protocol.ActorClassWithSpec({}, {});
void badActor;
}, /Actor specification must have a typeName member/);
@ -192,7 +189,7 @@ function run_test() {
"traits": []});
Assert.equal(applicationType, "xpcshell-tests");
rootFront = RootFront(client);
rootFront = new RootFront(client);
rootFront.simpleReturn().then(ret => {
trace.expectSend({"type": "simpleReturn", "to": "<actorid>"});

View File

@ -47,14 +47,14 @@ var RootActor = protocol.ActorClassWithSpec(rootSpec, {
},
});
var RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize: function(client) {
class RootFront extends protocol.FrontClassWithSpec(rootSpec) {
constructor(client) {
super(client);
this.actorID = "root";
protocol.Front.prototype.initialize.call(this, client);
// Root owns itself.
this.manage(this);
},
});
}
}
function run_test() {
if (!Services.prefs.getBoolPref("javascript.options.asyncstack")) {
@ -70,7 +70,7 @@ function run_test() {
let rootFront;
client.connect().then(function onConnect() {
rootFront = RootFront(client);
rootFront = new RootFront(client);
rootFront.simpleReturn().then(() => {
let stack = Components.stack;

View File

@ -49,7 +49,7 @@ function test_lazy_api() {
Assert.ok("lazyActor" in response);
const {LazyFront} = require("xpcshell-test/registertestactors-lazy");
const front = LazyFront(client, response);
const front = new LazyFront(client, response);
front.hello().then(onRequest);
}
function onRequest(response) {

View File

@ -4,10 +4,8 @@
"use strict";
const {
custom,
Front,
FrontClassWithSpec,
preEvent,
registerFront,
} = require("devtools/shared/protocol.js");
const {
accessibleSpec,
@ -16,58 +14,69 @@ const {
} = require("devtools/shared/specs/accessibility");
const events = require("devtools/shared/event-emitter");
const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
initialize(client, form) {
Front.prototype.initialize.call(this, client, form);
},
class AccessibleFront extends FrontClassWithSpec(accessibleSpec) {
constructor(client, form) {
super(client, form);
this.before("name-change", this.nameChange.bind(this));
this.before("value-change", this.valueChange.bind(this));
this.before("description-change", this.descriptionChange.bind(this));
this.before("shortcut-change", this.shortcutChange.bind(this));
this.before("reorder", this.reorder.bind(this));
this.before("text-change", this.textChange.bind(this));
this.before("index-in-parent-change", this.indexInParentChange.bind(this));
this.before("states-change", this.statesChange.bind(this));
this.before("actions-change", this.actionsChange.bind(this));
this.before("attributes-change", this.attributesChange.bind(this));
}
marshallPool() {
return this.parent();
},
}
get role() {
return this._form.role;
},
}
get name() {
return this._form.name;
},
}
get value() {
return this._form.value;
},
}
get description() {
return this._form.description;
},
}
get keyboardShortcut() {
return this._form.keyboardShortcut;
},
}
get childCount() {
return this._form.childCount;
},
}
get domNodeType() {
return this._form.domNodeType;
},
}
get indexInParent() {
return this._form.indexInParent;
},
}
get states() {
return this._form.states;
},
}
get actions() {
return this._form.actions;
},
}
get attributes() {
return this._form.attributes;
},
}
form(form, detail) {
if (detail === "actorid") {
@ -77,117 +86,126 @@ const AccessibleFront = FrontClassWithSpec(accessibleSpec, {
this.actorID = form.actor;
this._form = form;
},
}
nameChange: preEvent("name-change", function(name, parent, walker) {
nameChange(name, parent, walker) {
this._form.name = name;
// Name change event affects the tree rendering, we fire this event on
// accessibility walker as the point of interaction for UI.
if (walker) {
events.emit(walker, "name-change", this, parent);
}
}),
}
valueChange: preEvent("value-change", function(value) {
valueChange(value) {
this._form.value = value;
}),
}
descriptionChange: preEvent("description-change", function(description) {
descriptionChange(description) {
this._form.description = description;
}),
}
shortcutChange: preEvent("shortcut-change", function(keyboardShortcut) {
shortcutChange(keyboardShortcut) {
this._form.keyboardShortcut = keyboardShortcut;
}),
}
reorder: preEvent("reorder", function(childCount, walker) {
reorder(childCount, walker) {
this._form.childCount = childCount;
// Reorder event affects the tree rendering, we fire this event on
// accessibility walker as the point of interaction for UI.
if (walker) {
events.emit(walker, "reorder", this);
}
}),
}
textChange: preEvent("text-change", function(walker) {
textChange(walker) {
// Text event affects the tree rendering, we fire this event on
// accessibility walker as the point of interaction for UI.
if (walker) {
events.emit(walker, "text-change", this);
}
}),
}
indexInParentChange: preEvent("index-in-parent-change", function(indexInParent) {
indexInParentChange(indexInParent) {
this._form.indexInParent = indexInParent;
}),
}
statesChange: preEvent("states-change", function(states) {
statesChange(states) {
this._form.states = states;
}),
}
actionsChange: preEvent("actions-change", function(actions) {
actionsChange(actions) {
this._form.actions = actions;
}),
}
attributesChange: preEvent("attributes-change", function(attributes) {
attributesChange(attributes) {
this._form.attributes = attributes;
}),
});
}
}
const AccessibleWalkerFront = FrontClassWithSpec(accessibleWalkerSpec, {
accessibleDestroy: preEvent("accessible-destroy", function(accessible) {
class AccessibleWalkerFront extends FrontClassWithSpec(accessibleWalkerSpec) {
constructor(client, form) {
super(client, form);
this.before("accessible-destroy", this.accessibleDestroy.bind(this));
}
accessibleDestroy(accessible) {
accessible.destroy();
}),
}
form(json) {
this.actorID = json.actor;
},
}
pick: custom(function(doFocus) {
pick(doFocus) {
if (doFocus) {
return this.pickAndFocus();
}
return this._pick();
}, {
impl: "_pick",
}),
});
return super.pick();
}
}
const AccessibilityFront = FrontClassWithSpec(accessibilitySpec, {
initialize(client, form) {
Front.prototype.initialize.call(this, client, form);
class AccessibilityFront extends FrontClassWithSpec(accessibilitySpec) {
constructor(client, form) {
super(client, form);
this.actorID = form.accessibilityActor;
this.manage(this);
},
bootstrap: custom(function() {
return this._bootstrap().then(state => {
this.before("init", this.init.bind(this));
this.before("shutdown", this.shutdown.bind(this));
this.before("can-be-enabled-change", this.canBeEnabled.bind(this));
this.before("can-be-disabled-change", this.canBeDisabled.bind(this));
}
bootstrap() {
return super.bootstrap().then(state => {
this.enabled = state.enabled;
this.canBeEnabled = state.canBeEnabled;
this.canBeDisabled = state.canBeDisabled;
});
}, {
impl: "_bootstrap",
}),
}
init: preEvent("init", function() {
init() {
this.enabled = true;
}),
}
shutdown: preEvent("shutdown", function() {
shutdown() {
this.enabled = false;
}),
}
canBeEnabled: preEvent("can-be-enabled-change", function(canBeEnabled) {
canBeEnabled(canBeEnabled) {
this.canBeEnabled = canBeEnabled;
}),
}
canBeDisabled: preEvent("can-be-disabled-change", function(canBeDisabled) {
canBeDisabled(canBeDisabled) {
this.canBeDisabled = canBeDisabled;
}),
});
}
}
exports.AccessibleFront = AccessibleFront;
registerFront(AccessibleFront);
exports.AccessibleWalkerFront = AccessibleWalkerFront;
registerFront(AccessibleWalkerFront);
exports.AccessibilityFront = AccessibilityFront;
registerFront(AccessibilityFront);

View File

@ -6,18 +6,18 @@
const { components } = require("chrome");
const Services = require("Services");
const { actorActorSpec, actorRegistrySpec } = require("devtools/shared/specs/actor-registry");
const protocol = require("devtools/shared/protocol");
const { custom } = protocol;
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
const ActorActorFront = protocol.FrontClassWithSpec(actorActorSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
},
});
class ActorActorFront extends FrontClassWithSpec(actorActorSpec) {
constructor(client, form) {
super(client, form);
}
}
exports.ActorActorFront = ActorActorFront;
registerFront(ActorActorFront);
function request(uri) {
return new Promise((resolve, reject) => {
@ -46,22 +46,21 @@ function request(uri) {
});
}
const ActorRegistryFront = protocol.FrontClassWithSpec(actorRegistrySpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client,
class ActorRegistryFront extends FrontClassWithSpec(actorRegistrySpec) {
constructor(client, form) {
super(client,
{ actor: form.actorRegistryActor });
this.manage(this);
},
}
registerActor: custom(function(uri, options) {
registerActor(uri, options) {
return request(uri, options)
.then(sourceText => {
return this._registerActor(sourceText, uri, options);
return super.registerActor(sourceText, uri, options);
});
}, {
impl: "_registerActor",
}),
});
}
}
exports.ActorRegistryFront = ActorRegistryFront;
registerFront(ActorRegistryFront);

View File

@ -4,14 +4,15 @@
"use strict";
const {addonsSpec} = require("devtools/shared/specs/addon/addons");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const AddonsFront = protocol.FrontClassWithSpec(addonsSpec, {
initialize: function(client, {addonsActor}) {
protocol.Front.prototype.initialize.call(this, client);
class AddonsFront extends FrontClassWithSpec(addonsSpec) {
constructor(client, {addonsActor}) {
super(client);
this.actorID = addonsActor;
this.manage(this);
},
});
}
}
exports.AddonsFront = AddonsFront;
registerFront(AddonsFront);

View File

@ -7,21 +7,20 @@ const {
webExtensionInspectedWindowSpec,
} = require("devtools/shared/specs/addon/webextension-inspected-window");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
/**
* The corresponding Front object for the WebExtensionInspectedWindowActor.
*/
const WebExtensionInspectedWindowFront = protocol.FrontClassWithSpec(
webExtensionInspectedWindowSpec,
{
initialize: function(client, { webExtensionInspectedWindowActor }) {
protocol.Front.prototype.initialize.call(this, client, {
actor: webExtensionInspectedWindowActor,
});
this.manage(this);
},
class WebExtensionInspectedWindowFront extends
FrontClassWithSpec(webExtensionInspectedWindowSpec) {
constructor(client, { webExtensionInspectedWindowActor }) {
super(client, {
actor: webExtensionInspectedWindowActor,
});
this.manage(this);
}
);
}
exports.WebExtensionInspectedWindowFront = WebExtensionInspectedWindowFront;
registerFront(WebExtensionInspectedWindowFront);

View File

@ -4,35 +4,34 @@
"use strict";
const {
Front,
FrontClassWithSpec,
custom,
preEvent,
registerFront,
} = require("devtools/shared/protocol");
const {
animationPlayerSpec,
animationsSpec,
} = require("devtools/shared/specs/animation");
const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
initialize: function(conn, form, detail, ctx) {
Front.prototype.initialize.call(this, conn, form, detail, ctx);
class AnimationPlayerFront extends FrontClassWithSpec(animationPlayerSpec) {
constructor(conn, form, detail, ctx) {
super(conn, form, detail, ctx);
this.state = {};
},
this.before("changed", this.onChanged.bind(this));
}
form: function(form, detail) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
this.state = this.initialState;
},
}
destroy: function() {
Front.prototype.destroy.call(this);
},
destroy() {
super.destroy();
}
/**
* If the AnimationsActor was given a reference to the WalkerActor previously
@ -44,7 +43,7 @@ const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
}
return this.conn.getActor(this._form.animationTargetNodeActorID);
},
}
/**
* Getter for the initial state of the player. Up to date states can be
@ -74,16 +73,16 @@ const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
currentTimeAtCreated: this._form.currentTimeAtCreated,
absoluteValues: this.calculateAbsoluteValues(this._form),
};
},
}
/**
* Executed when the AnimationPlayerActor emits a "changed" event. Used to
* update the local knowledge of the state.
*/
onChanged: preEvent("changed", function(partialState) {
onChanged(partialState) {
const {state} = this.reconstructState(partialState);
this.state = state;
}),
}
/**
* Refresh the current state of this animation on the client from information
@ -94,24 +93,22 @@ const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
if (this.currentStateHasChanged) {
this.state = data;
}
},
}
/**
* getCurrentState interceptor re-constructs incomplete states since the actor
* only sends the values that have changed.
*/
getCurrentState: custom(function() {
getCurrentState() {
this.currentStateHasChanged = false;
return this._getCurrentState().then(partialData => {
return super.getCurrentState().then(partialData => {
const {state, hasChanged} = this.reconstructState(partialData);
this.currentStateHasChanged = hasChanged;
return state;
});
}, {
impl: "_getCurrentState",
}),
}
reconstructState: function(data) {
reconstructState(data) {
let hasChanged = false;
for (const key in this.state) {
@ -124,7 +121,7 @@ const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
data.absoluteValues = this.calculateAbsoluteValues(data);
return {state: data, hasChanged};
},
}
calculateAbsoluteValues(data) {
const {
@ -198,20 +195,22 @@ const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
startTime: absoluteStartTime,
startTimeAtCreated: absoluteStartTimeAtCreated,
};
},
});
}
}
exports.AnimationPlayerFront = AnimationPlayerFront;
registerFront(AnimationPlayerFront);
const AnimationsFront = FrontClassWithSpec(animationsSpec, {
initialize: function(client, {animationsActor}) {
Front.prototype.initialize.call(this, client, {actor: animationsActor});
class AnimationsFront extends FrontClassWithSpec(animationsSpec) {
constructor(client, {animationsActor}) {
super(client, {actor: animationsActor});
this.manage(this);
},
}
destroy: function() {
Front.prototype.destroy.call(this);
},
});
destroy() {
super.destroy();
}
}
exports.AnimationsFront = AnimationsFront;
registerFront(AnimationsFront);

View File

@ -12,37 +12,35 @@ const {
DRAW_CALLS,
INTERESTING_CALLS,
} = require("devtools/shared/specs/canvas");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const promise = require("promise");
/**
* The corresponding Front object for the FrameSnapshotActor.
*/
const FrameSnapshotFront = protocol.FrontClassWithSpec(frameSnapshotSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
class FrameSnapshotFront extends FrontClassWithSpec(frameSnapshotSpec) {
constructor(client, form) {
super(client, form);
this._animationFrameEndScreenshot = null;
this._cachedScreenshots = new WeakMap();
},
}
/**
* This implementation caches the animation frame end screenshot to optimize
* frontend requests to `generateScreenshotFor`.
*/
getOverview: protocol.custom(function() {
return this._getOverview().then(data => {
getOverview() {
return super.getOverview().then(data => {
this._animationFrameEndScreenshot = data.screenshot;
return data;
});
}, {
impl: "_getOverview",
}),
}
/**
* This implementation saves a roundtrip to the backend if the screenshot
* was already generated and retrieved once.
*/
generateScreenshotFor: protocol.custom(function(functionCall) {
generateScreenshotFor(functionCall) {
if (CanvasFront.ANIMATION_GENERATORS.has(functionCall.name) ||
CanvasFront.LOOP_GENERATORS.has(functionCall.name)) {
return promise.resolve(this._animationFrameEndScreenshot);
@ -51,25 +49,24 @@ const FrameSnapshotFront = protocol.FrontClassWithSpec(frameSnapshotSpec, {
if (cachedScreenshot) {
return cachedScreenshot;
}
const screenshot = this._generateScreenshotFor(functionCall);
const screenshot = super.generateScreenshotFor(functionCall);
this._cachedScreenshots.set(functionCall, screenshot);
return screenshot;
}, {
impl: "_generateScreenshotFor",
}),
});
}
}
exports.FrameSnapshotFront = FrameSnapshotFront;
registerFront(FrameSnapshotFront);
/**
* The corresponding Front object for the CanvasActor.
*/
const CanvasFront = protocol.FrontClassWithSpec(canvasSpec, {
initialize: function(client, { canvasActor }) {
protocol.Front.prototype.initialize.call(this, client, { actor: canvasActor });
class CanvasFront extends FrontClassWithSpec(canvasSpec) {
constructor(client, { canvasActor }) {
super(client, { actor: canvasActor });
this.manage(this);
},
});
}
}
/**
* Constants.
@ -89,3 +86,4 @@ CanvasFront.INVALID_SNAPSHOT_IMAGE = {
};
exports.CanvasFront = CanvasFront;
registerFront(CanvasFront);

View File

@ -4,21 +4,22 @@
"use strict";
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const {changesSpec} = require("devtools/shared/specs/changes");
/**
* ChangesFront, the front object for the ChangesActor
*/
const ChangesFront = protocol.FrontClassWithSpec(changesSpec, {
initialize: function(client, {changesActor}) {
protocol.Front.prototype.initialize.call(this, client, {actor: changesActor});
class ChangesFront extends FrontClassWithSpec(changesSpec) {
constructor(client, {changesActor}) {
super(client, {actor: changesActor});
this.manage(this);
},
}
destroy: function() {
protocol.Front.prototype.destroy.call(this);
},
});
destroy() {
super.destroy();
}
}
exports.ChangesFront = ChangesFront;
registerFront(ChangesFront);

View File

@ -9,7 +9,7 @@ loader.lazyRequireGetter(this, "CSS_PROPERTIES_DB",
loader.lazyRequireGetter(this, "cssColors",
"devtools/shared/css/color-db", true);
const { FrontClassWithSpec, Front } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
/**
@ -42,12 +42,12 @@ var cachedCssProperties = new WeakMap();
* interface that provides synchronous methods for finding out what CSS
* properties the current server supports.
*/
const CssPropertiesFront = FrontClassWithSpec(cssPropertiesSpec, {
initialize: function(client, { cssPropertiesActor }) {
Front.prototype.initialize.call(this, client, {actor: cssPropertiesActor});
class CssPropertiesFront extends FrontClassWithSpec(cssPropertiesSpec) {
constructor(client, { cssPropertiesActor }) {
super(client, {actor: cssPropertiesActor});
this.manage(this);
},
});
}
}
/**
* Query the feature supporting status in the featureSet.
@ -359,3 +359,4 @@ module.exports = {
initCssProperties,
isCssVariable,
};
registerFront(CssPropertiesFront);

View File

@ -4,8 +4,7 @@
"use strict";
const {cssUsageSpec} = require("devtools/shared/specs/csscoverage");
const protocol = require("devtools/shared/protocol");
const {custom} = protocol;
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/shared/locales/csscoverage.properties");
@ -32,14 +31,15 @@ var chromeWindow;
/**
* Front for CSSUsageActor
*/
const CSSUsageFront = protocol.FrontClassWithSpec(cssUsageSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
class CSSUsageFront extends FrontClassWithSpec(cssUsageSpec) {
constructor(client, form) {
super(client, form);
this.actorID = form.cssUsageActor;
this.manage(this);
},
this.before("state-change", this._onStateChange.bind(this));
}
_onStateChange: protocol.preEvent("state-change", function(ev) {
_onStateChange(ev) {
isRunning = ev.isRunning;
ev.target = target;
@ -70,38 +70,35 @@ const CSSUsageFront = protocol.FrontClassWithSpec(cssUsageSpec, {
gDevTools.showToolbox(target, "styleeditor");
target = undefined;
}
}),
}
/**
* Server-side start is above. Client-side start adds a notification box
*/
start: custom(function(newChromeWindow, newTarget, noreload = false) {
start(newChromeWindow, newTarget, noreload = false) {
target = newTarget;
chromeWindow = newChromeWindow;
return this._start(noreload);
}, {
impl: "_start",
}),
return super.start(noreload);
}
/**
* Server-side start is above. Client-side start adds a notification box
*/
toggle: custom(function(newChromeWindow, newTarget) {
toggle(newChromeWindow, newTarget) {
target = newTarget;
chromeWindow = newChromeWindow;
return this._toggle();
}, {
impl: "_toggle",
}),
return super.toggle();
}
/**
* We count STARTING and STOPPING as 'running'
*/
isRunning: function() {
isRunning() {
return isRunning;
},
});
}
}
exports.CSSUsageFront = CSSUsageFront;
registerFront(CSSUsageFront);

View File

@ -5,17 +5,17 @@
const {Cu} = require("chrome");
const {deviceSpec} = require("devtools/shared/specs/device");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const defer = require("devtools/shared/defer");
const DeviceFront = protocol.FrontClassWithSpec(deviceSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client);
class DeviceFront extends FrontClassWithSpec(deviceSpec) {
constructor(client, form) {
super(client);
this.actorID = form.deviceActor;
this.manage(this);
},
}
screenshotToBlob: function() {
screenshotToBlob() {
return this.screenshotToDataURL().then(longstr => {
return longstr.string().then(dataURL => {
const deferred = defer();
@ -33,7 +33,8 @@ const DeviceFront = protocol.FrontClassWithSpec(deviceSpec, {
return deferred.promise;
});
});
},
});
}
}
exports.DeviceFront = DeviceFront;
registerFront(DeviceFront);

View File

@ -3,22 +3,23 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const { emulationSpec } = require("devtools/shared/specs/emulation");
/**
* The corresponding Front object for the EmulationActor.
*/
const EmulationFront = FrontClassWithSpec(emulationSpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client);
class EmulationFront extends FrontClassWithSpec(emulationSpec) {
constructor(client, form) {
super(client);
this.actorID = form.emulationActor;
this.manage(this);
},
}
destroy: function() {
Front.prototype.destroy.call(this);
},
});
destroy() {
super.destroy();
}
}
exports.EmulationFront = EmulationFront;
registerFront(EmulationFront);

View File

@ -3,17 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const { framerateSpec } = require("devtools/shared/specs/framerate");
/**
* The corresponding Front object for the FramerateActor.
*/
var FramerateFront = exports.FramerateFront = FrontClassWithSpec(framerateSpec, {
initialize: function(client, { framerateActor }) {
Front.prototype.initialize.call(this, client, { actor: framerateActor });
class FramerateFront extends FrontClassWithSpec(framerateSpec) {
constructor(client, { framerateActor }) {
super(client, { actor: framerateActor });
this.manage(this);
},
});
}
}
exports.FramerateFront = FramerateFront;
registerFront(FramerateFront);

View File

@ -4,21 +4,21 @@
"use strict";
const { functionCallSpec } = require("devtools/shared/specs/function-call");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
/**
* The corresponding Front object for the FunctionCallActor.
*/
const FunctionCallFront = protocol.FrontClassWithSpec(functionCallSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
},
class FunctionCallFront extends FrontClassWithSpec(functionCallSpec) {
constructor(client, form) {
super(client, form);
}
/**
* Adds some generic information directly to this instance,
* to avoid extra roundtrips.
*/
form: function(form) {
form(form) {
this.actorID = form.actor;
this.type = form.type;
this.name = form.name;
@ -28,10 +28,11 @@ const FunctionCallFront = protocol.FrontClassWithSpec(functionCallSpec, {
this.callerPreview = form.callerPreview;
this.argsPreview = form.argsPreview;
this.resultPreview = form.resultPreview;
},
});
}
}
exports.FunctionCallFront = FunctionCallFront;
registerFront(FunctionCallFront);
/**
* Constants.

View File

@ -3,30 +3,33 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { FrontClassWithSpec, custom } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const flags = require("devtools/shared/flags");
const {
customHighlighterSpec,
highlighterSpec,
} = require("devtools/shared/specs/highlighters");
const HighlighterFront = FrontClassWithSpec(highlighterSpec, {
isNodeFrontHighlighted: false,
class HighlighterFront extends FrontClassWithSpec(highlighterSpec) {
constructor(client, form) {
super(client, form);
this.isNodeFrontHighlighted = false;
}
// Update the object given a form representation off the wire.
form: function(json) {
form(json) {
this.actorID = json.actor;
// FF42+ HighlighterActors starts exposing custom form, with traits object
this.traits = json.traits || {};
},
}
pick: custom(function(doFocus) {
if (doFocus && this.pickAndFocus) {
return this.pickAndFocus();
pick(doFocus) {
if (doFocus && super.pickAndFocus) {
return super.pickAndFocus();
}
return this._pick();
}, {
impl: "_pick",
}),
return super.pick();
}
/**
* Show the box model highlighter on a node in the content page.
@ -36,7 +39,7 @@ const HighlighterFront = FrontClassWithSpec(highlighterSpec, {
* @param {Object} options
* @return A promise that resolves when the node has been highlighted
*/
highlight: async function(nodeFront, options = {}) {
async highlight(nodeFront, options = {}) {
if (!nodeFront) {
return;
}
@ -44,7 +47,7 @@ const HighlighterFront = FrontClassWithSpec(highlighterSpec, {
this.isNodeFrontHighlighted = true;
await this.showBoxModel(nodeFront, options);
this.emit("node-highlight", nodeFront);
},
}
/**
* Hide the highlighter.
@ -55,7 +58,7 @@ const HighlighterFront = FrontClassWithSpec(highlighterSpec, {
* markup view, which is when this param is passed to true
* @return a promise that resolves when the highlighter is hidden
*/
unhighlight: async function(forceHide = false) {
async unhighlight(forceHide = false) {
forceHide = forceHide || !flags.testing;
if (this.isNodeFrontHighlighted && forceHide) {
@ -64,31 +67,33 @@ const HighlighterFront = FrontClassWithSpec(highlighterSpec, {
}
this.emit("node-unhighlight");
},
});
}
}
exports.HighlighterFront = HighlighterFront;
registerFront(HighlighterFront);
const CustomHighlighterFront = FrontClassWithSpec(customHighlighterSpec, {
_isShown: false,
class CustomHighlighterFront extends FrontClassWithSpec(customHighlighterSpec) {
constructor(client, form) {
super(client, form);
show: custom(function(...args) {
this._isShown = true;
return this._show(...args);
}, {
impl: "_show",
}),
hide: custom(function() {
this._isShown = false;
return this._hide();
}, {
impl: "_hide",
}),
}
isShown: function() {
show(...args) {
this._isShown = true;
return super.show(...args);
}
hide() {
this._isShown = false;
return super.hide();
}
isShown() {
return this._isShown;
},
});
}
}
exports.CustomHighlighterFront = CustomHighlighterFront;
registerFront(CustomHighlighterFront);

View File

@ -11,11 +11,9 @@ const SHOW_ALL_ANONYMOUS_CONTENT_PREF = "devtools.inspector.showAllAnonymousCont
const SHOW_UA_SHADOW_ROOTS_PREF = "devtools.inspector.showUserAgentShadowRoots";
const {
Front,
FrontClassWithSpec,
custom,
preEvent,
types,
registerFront,
} = require("devtools/shared/protocol.js");
const {
inspectorSpec,
@ -34,39 +32,41 @@ loader.lazyRequireGetter(this, "flags",
/**
* Client side of the DOM walker.
*/
const WalkerFront = FrontClassWithSpec(walkerSpec, {
// Set to true if cleanup should be requested after every mutation list.
autoCleanup: true,
class WalkerFront extends FrontClassWithSpec(walkerSpec) {
/**
* This is kept for backward-compatibility reasons with older remote target.
* Targets previous to bug 916443
*/
pick: custom(function() {
return this._pick().then(response => {
pick() {
return super.pick().then(response => {
return response.node;
});
}, {impl: "_pick"}),
}
initialize: function(client, form) {
constructor(client, form) {
super(client, form);
this._createRootNodePromise();
Front.prototype.initialize.call(this, client, form);
this._orphaned = new Set();
this._retainedOrphans = new Set();
},
destroy: function() {
Front.prototype.destroy.call(this);
},
// Set to true if cleanup should be requested after every mutation list.
this.autoCleanup = true;
this.before("new-mutations", this.onMutations.bind(this));
}
destroy() {
super.destroy();
}
// Update the object given a form representation off the wire.
form: function(json) {
form(json) {
this.actorID = json.actor;
this.rootNode = types.getType("domnode").read(json.root, this);
this._rootNodeDeferred.resolve(this.rootNode);
// FF42+ the actor starts exposing traits
this.traits = json.traits || {};
},
}
/**
* Clients can use walker.rootNode to get the current root node of the
@ -74,20 +74,20 @@ const WalkerFront = FrontClassWithSpec(walkerSpec, {
* method returns a promise that will resolve to the root node when it is
* set.
*/
getRootNode: function() {
getRootNode() {
return this._rootNodeDeferred.promise;
},
}
/**
* Create the root node promise, triggering the "new-root" notification
* on resolution.
*/
_createRootNodePromise: function() {
_createRootNodePromise() {
this._rootNodeDeferred = defer();
this._rootNodeDeferred.promise.then(() => {
this.emit("new-root");
});
},
}
/**
* When reading an actor form off the wire, we want to hook it up to its
@ -97,14 +97,14 @@ const WalkerFront = FrontClassWithSpec(walkerSpec, {
* a bare-bones stand-in node. The stand-in node will be updated
* with a real form by the end of the deserialization.
*/
ensureDOMNodeFront: function(id) {
ensureDOMNodeFront(id) {
const front = this.get(id);
if (front) {
return front;
}
return types.getType("domnode").read({ actor: id }, this, "standin");
},
}
/**
* See the documentation for WalkerActor.prototype.retainNode for
@ -126,84 +126,68 @@ const WalkerFront = FrontClassWithSpec(walkerSpec, {
* semantics by setting our local retained flag on the node only AFTER
* a SUCCESSFUL retainNode call.
*/
retainNode: custom(function(node) {
return this._retainNode(node).then(() => {
retainNode(node) {
return super.retainNode(node).then(() => {
node.retained = true;
});
}, {
impl: "_retainNode",
}),
}
unretainNode: custom(function(node) {
return this._unretainNode(node).then(() => {
unretainNode(node) {
return super.unretainNode(node).then(() => {
node.retained = false;
if (this._retainedOrphans.has(node)) {
this._retainedOrphans.delete(node);
this._releaseFront(node);
}
});
}, {
impl: "_unretainNode",
}),
}
releaseNode: custom(function(node, options = {}) {
releaseNode(node, options = {}) {
// NodeFront.destroy will destroy children in the ownership tree too,
// mimicking what the server will do here.
const actorID = node.actorID;
this._releaseFront(node, !!options.force);
return this._releaseNode({ actorID: actorID });
}, {
impl: "_releaseNode",
}),
return super.releaseNode({ actorID: actorID });
}
findInspectingNode: custom(function() {
return this._findInspectingNode().then(response => {
findInspectingNode() {
return super.findInspectingNode().then(response => {
return response.node;
});
}, {
impl: "_findInspectingNode",
}),
}
querySelector: custom(function(queryNode, selector) {
return this._querySelector(queryNode, selector).then(response => {
querySelector(queryNode, selector) {
return super.querySelector(queryNode, selector).then(response => {
return response.node;
});
}, {
impl: "_querySelector",
}),
}
gripToNodeFront: async function(grip) {
async gripToNodeFront(grip) {
const response = await this.getNodeActorFromObjectActor(grip.actor);
const nodeFront = response ? response.node : null;
if (!nodeFront) {
throw new Error("The ValueGrip passed could not be translated to a NodeFront");
}
return nodeFront;
},
}
getNodeActorFromWindowID: custom(function(windowID) {
return this._getNodeActorFromWindowID(windowID).then(response => {
getNodeActorFromWindowID(windowID) {
return super.getNodeActorFromWindowID(windowID).then(response => {
return response ? response.node : null;
});
}, {
impl: "_getNodeActorFromWindowID",
}),
}
getStyleSheetOwnerNode: custom(function(styleSheetActorID) {
return this._getStyleSheetOwnerNode(styleSheetActorID).then(response => {
getStyleSheetOwnerNode(styleSheetActorID) {
return super.getStyleSheetOwnerNode(styleSheetActorID).then(response => {
return response ? response.node : null;
});
}, {
impl: "_getStyleSheetOwnerNode",
}),
}
getNodeFromActor: custom(function(actorID, path) {
return this._getNodeFromActor(actorID, path).then(response => {
getNodeFromActor(actorID, path) {
return super.getNodeFromActor(actorID, path).then(response => {
return response ? response.node : null;
});
}, {
impl: "_getNodeFromActor",
}),
}
/*
* Incrementally search the document for a given string.
@ -216,9 +200,9 @@ const WalkerFront = FrontClassWithSpec(walkerSpec, {
* @param {Object} options
* - "reverse": search backwards
*/
search: custom(async function(query, options = { }) {
async search(query, options = { }) {
const searchData = this.searchData = this.searchData || { };
const result = await this._search(query, options);
const result = await super.search(query, options);
const nodeList = result.list;
// If this is a new search, start at the beginning.
@ -249,11 +233,9 @@ const WalkerFront = FrontClassWithSpec(walkerSpec, {
resultsLength: nodeList.length,
resultsIndex: searchData.index,
};
}, {
impl: "_search",
}),
}
_releaseFront: function(node, force) {
_releaseFront(node, force) {
if (node.retained && !force) {
node.reparent(null);
this._retainedOrphans.add(node);
@ -273,13 +255,13 @@ const WalkerFront = FrontClassWithSpec(walkerSpec, {
// All children will have been removed from the node by this point.
node.reparent(null);
node.destroy();
},
}
/**
* Get any unprocessed mutation records and process them.
*/
getMutations: custom(function(options = {}) {
return this._getMutations(options).then(mutations => {
getMutations(options = {}) {
return super.getMutations(options).then(mutations => {
const emitMutations = [];
for (const change of mutations) {
// The target is only an actorID, get the associated front.
@ -422,44 +404,42 @@ const WalkerFront = FrontClassWithSpec(walkerSpec, {
this.emit("mutations", emitMutations);
});
}, {
impl: "_getMutations",
}),
}
/**
* Handle the `new-mutations` notification by fetching the
* available mutation records.
*/
onMutations: preEvent("new-mutations", function() {
onMutations() {
// Fetch and process the mutations.
this.getMutations({cleanup: this.autoCleanup}).catch(() => {});
}),
}
isLocal: function() {
isLocal() {
return !!this.conn._transport._serverConnection;
},
}
removeNode: custom(async function(node) {
async removeNode(node) {
const previousSibling = await this.previousSibling(node);
const nextSibling = await this._removeNode(node);
const nextSibling = await super.removeNode(node);
return {
previousSibling: previousSibling,
nextSibling: nextSibling,
};
}, {
impl: "_removeNode",
}),
});
}
}
exports.WalkerFront = WalkerFront;
registerFront(WalkerFront);
/**
* Client side of the inspector actor, which is used to create
* inspector-related actors, including the walker.
*/
var InspectorFront = FrontClassWithSpec(inspectorSpec, {
initialize: async function(client, tabForm) {
Front.prototype.initialize.call(this, client);
class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
constructor(client, tabForm) {
super(client, tabForm);
this.actorID = tabForm.inspectorActor;
this._client = client;
this._highlighters = new Map();
@ -467,17 +447,19 @@ var InspectorFront = FrontClassWithSpec(inspectorSpec, {
// XXX: This is the first actor type in its hierarchy to use the protocol
// library, so we're going to self-own on the client side for now.
this.manage(this);
}
// async initialization
// async initialization
async initialize() {
await Promise.all([
this._getWalker(),
this._getHighlighter(),
]);
this.selection = new Selection(this.walker);
},
}
_getWalker: async function() {
async _getWalker() {
const showAllAnonymousContent = Services.prefs.getBoolPref(
SHOW_ALL_ANONYMOUS_CONTENT_PREF);
const showUserAgentShadowRoots = Services.prefs.getBoolPref(
@ -486,18 +468,18 @@ var InspectorFront = FrontClassWithSpec(inspectorSpec, {
showAllAnonymousContent,
showUserAgentShadowRoots,
});
},
}
_getHighlighter: async function() {
async _getHighlighter() {
const autohide = !flags.testing;
this.highlighter = await this.getHighlighter(autohide);
},
}
hasHighlighter(type) {
return this._highlighters.has(type);
},
}
destroy: function() {
destroy() {
// Selection isn't a Front and so isn't managed by InspectorFront
// and has to be destroyed manually
this.selection.destroy();
@ -505,41 +487,40 @@ var InspectorFront = FrontClassWithSpec(inspectorSpec, {
// automatically destroyed. But we have to clear the `_highlighters`
// Map as well as explicitly call `finalize` request on all of them.
this.destroyHighlighters();
Front.prototype.destroy.call(this);
},
super.destroy();
}
destroyHighlighters: function() {
destroyHighlighters() {
for (const type of this._highlighters.keys()) {
if (this._highlighters.has(type)) {
this._highlighters.get(type).finalize();
this._highlighters.delete(type);
}
}
},
}
getKnownHighlighter: function(type) {
getKnownHighlighter(type) {
return this._highlighters.get(type);
},
}
getOrCreateHighlighterByType: async function(type) {
async getOrCreateHighlighterByType(type) {
let front = this._highlighters.get(type);
if (!front) {
front = await this.getHighlighterByType(type);
this._highlighters.set(type, front);
}
return front;
},
}
pickColorFromPage: custom(async function(options) {
await this._pickColorFromPage(options);
async pickColorFromPage(options) {
await super.pickColorFromPage(options);
if (options && options.fromMenu) {
telemetry.getHistogramById(TELEMETRY_EYEDROPPER_OPENED_MENU).add(true);
} else {
telemetry.getHistogramById(TELEMETRY_EYEDROPPER_OPENED).add(true);
}
}, {
impl: "_pickColorFromPage",
}),
});
}
}
exports.InspectorFront = InspectorFront;
registerFront(InspectorFront);

View File

@ -4,7 +4,7 @@
"use strict";
const { FrontClassWithSpec } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const {
flexboxSpec,
flexItemSpec,
@ -12,14 +12,14 @@ const {
layoutSpec,
} = require("devtools/shared/specs/layout");
const FlexboxFront = FrontClassWithSpec(flexboxSpec, {
form: function(form, detail) {
class FlexboxFront extends FrontClassWithSpec(flexboxSpec) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
},
}
/**
* In some cases, the FlexboxActor already knows the NodeActor ID of the node where the
@ -31,31 +31,31 @@ const FlexboxFront = FrontClassWithSpec(flexboxSpec, {
}
return this.conn.getActor(this._form.containerNodeActorID);
},
}
/**
* Get the computed style properties for the flex container.
*/
get properties() {
return this._form.properties;
},
});
}
}
const FlexItemFront = FrontClassWithSpec(flexItemSpec, {
form: function(form, detail) {
class FlexItemFront extends FrontClassWithSpec(flexItemSpec) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
},
}
/**
* Get the flex item sizing data.
*/
get flexItemSizing() {
return this._form.flexItemSizing;
},
}
/**
* In some cases, the FlexItemActor already knows the NodeActor ID of the node where the
@ -67,31 +67,31 @@ const FlexItemFront = FrontClassWithSpec(flexItemSpec, {
}
return this.conn.getActor(this._form.nodeActorID);
},
}
/**
* Get the computed style properties for the flex item.
*/
get computedStyle() {
return this._form.computedStyle;
},
}
/**
* Get the style properties for the flex item.
*/
get properties() {
return this._form.properties;
},
});
}
}
const GridFront = FrontClassWithSpec(gridSpec, {
form: function(form, detail) {
class GridFront extends FrontClassWithSpec(gridSpec) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
},
}
/**
* In some cases, the GridActor already knows the NodeActor ID of the node where the
@ -103,7 +103,7 @@ const GridFront = FrontClassWithSpec(gridSpec, {
}
return this.conn.getActor(this._form.containerNodeActorID);
},
}
/**
* Get the text direction of the grid container.
@ -115,14 +115,14 @@ const GridFront = FrontClassWithSpec(gridSpec, {
}
return this._form.direction;
},
}
/**
* Getter for the grid fragments data.
*/
get gridFragments() {
return this._form.gridFragments;
},
}
/**
* Get the writing mode of the grid container.
@ -134,12 +134,17 @@ const GridFront = FrontClassWithSpec(gridSpec, {
}
return this._form.writingMode;
},
});
}
}
const LayoutFront = FrontClassWithSpec(layoutSpec, {});
class LayoutFront extends FrontClassWithSpec(layoutSpec) {
}
exports.FlexboxFront = FlexboxFront;
registerFront(FlexboxFront);
exports.FlexItemFront = FlexItemFront;
registerFront(FlexItemFront);
exports.GridFront = GridFront;
registerFront(GridFront);
exports.LayoutFront = LayoutFront;
registerFront(LayoutFront);

View File

@ -4,21 +4,21 @@
"use strict";
const { memorySpec } = require("devtools/shared/specs/memory");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm", true);
loader.lazyRequireGetter(this, "HeapSnapshotFileUtils",
"devtools/shared/heapsnapshot/HeapSnapshotFileUtils");
const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
class MemoryFront extends FrontClassWithSpec(memorySpec) {
constructor(client, form) {
super(client, form);
this._client = client;
this.actorID = form.memoryActor;
this.heapSnapshotFileActorID = null;
this.manage(this);
},
}
/**
* Save a heap snapshot, transfer it from the server to the client if the
@ -38,8 +38,8 @@ const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
*
* @returns Promise<String>
*/
saveHeapSnapshot: protocol.custom(async function(options = {}) {
const snapshotId = await this._saveHeapSnapshotImpl(options.boundaries);
async saveHeapSnapshot(options = {}) {
const snapshotId = await super.saveHeapSnapshot(options.boundaries);
if (!options.forceCopy &&
(await HeapSnapshotFileUtils.haveHeapSnapshotTempFile(snapshotId))) {
@ -47,9 +47,7 @@ const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
}
return this.transferHeapSnapshot(snapshotId);
}, {
impl: "_saveHeapSnapshotImpl",
}),
}
/**
* Given that we have taken a heap snapshot with the given id, transfer the
@ -60,7 +58,7 @@ const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
*
* @returns Promise<String>
*/
transferHeapSnapshot: protocol.custom(async function(snapshotId) {
async transferHeapSnapshot(snapshotId) {
if (!this.heapSnapshotFileActorID) {
const form = await this._client.mainRoot.rootForm;
this.heapSnapshotFileActorID = form.heapSnapshotFileActor;
@ -99,7 +97,8 @@ const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
// Otherwise, rethrow the error
throw e;
}
}),
});
}
}
exports.MemoryFront = MemoryFront;
registerFront(MemoryFront);

View File

@ -4,10 +4,9 @@
"use strict";
const {
Front,
FrontClassWithSpec,
custom,
types,
registerFront,
} = require("devtools/shared/protocol.js");
const {
@ -26,42 +25,39 @@ const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__";
/**
* Client side of a node list as returned by querySelectorAll()
*/
const NodeListFront = FrontClassWithSpec(nodeListSpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client, form);
},
class NodeListFront extends FrontClassWithSpec(nodeListSpec) {
constructor(client, form) {
super(client, form);
}
destroy: function() {
Front.prototype.destroy.call(this);
},
destroy() {
super.destroy();
}
marshallPool: function() {
marshallPool() {
return this.parent();
},
}
// Update the object given a form representation off the wire.
form: function(json) {
form(json) {
this.length = json.length;
},
}
item: custom(function(index) {
return this._item(index).then(response => {
item(index) {
return super.item(index).then(response => {
return response.node;
});
}, {
impl: "_item",
}),
}
items: custom(function(start, end) {
return this._items(start, end).then(response => {
items(start, end) {
return super.items(start, end).then(response => {
return response.nodes;
});
}, {
impl: "_items",
}),
});
}
}
exports.NodeListFront = NodeListFront;
registerFront(NodeListFront);
/**
* Convenience API for building a list of attribute modifications
@ -118,8 +114,9 @@ class AttributeModificationList {
* the parent node from clients, but the `children` request should be used
* to traverse children.
*/
const NodeFront = FrontClassWithSpec(nodeSpec, {
initialize: function(conn, form, detail, ctx) {
class NodeFront extends FrontClassWithSpec(nodeSpec) {
constructor(conn, form, detail, ctx) {
super(conn, form, detail, ctx);
// The parent node
this._parent = null;
// The first child of this node.
@ -128,20 +125,19 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
this._next = null;
// The previous sibling of this node.
this._prev = null;
Front.prototype.initialize.call(this, conn, form, detail, ctx);
},
}
/**
* Destroy a node front. The node must have been removed from the
* ownership tree before this is called, unless the whole walker front
* is being destroyed.
*/
destroy: function() {
Front.prototype.destroy.call(this);
},
destroy() {
super.destroy();
}
// Update the object given a form representation off the wire.
form: function(form, detail, ctx) {
form(form, detail, ctx) {
if (detail === "actorid") {
this.actorID = form;
return;
@ -177,22 +173,22 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
} else {
this.inlineTextChild = undefined;
}
},
}
/**
* Returns the parent NodeFront for this NodeFront.
*/
parentNode: function() {
parentNode() {
return this._parent;
},
}
/**
* Returns the NodeFront corresponding to the parentNode of this NodeFront, or the
* NodeFront corresponding to the host element for shadowRoot elements.
*/
parentOrHost: function() {
parentOrHost() {
return this.isShadowRoot ? this.host : this._parent;
},
}
/**
* Process a mutation entry as returned from the walker's `getMutations`
@ -200,7 +196,7 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
* themselves (character data and attribute changes), the walker itself
* will keep the ownership tree up to date.
*/
updateMutation: function(change) {
updateMutation(change) {
if (change.type === "attributes") {
// We'll need to lazily reparse the attributes after this change.
this._attrMap = undefined;
@ -236,140 +232,140 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
} else if (change.type === "events") {
this._form.hasEventListeners = change.hasEventListeners;
}
},
}
// Some accessors to make NodeFront feel more like a Node
get id() {
return this.getAttribute("id");
},
}
get nodeType() {
return this._form.nodeType;
},
}
get namespaceURI() {
return this._form.namespaceURI;
},
}
get nodeName() {
return this._form.nodeName;
},
}
get displayName() {
const {displayName, nodeName} = this._form;
// Keep `nodeName.toLowerCase()` for backward compatibility
return displayName || nodeName.toLowerCase();
},
}
get doctypeString() {
return "<!DOCTYPE " + this._form.name +
(this._form.publicId ? " PUBLIC \"" + this._form.publicId + "\"" : "") +
(this._form.systemId ? " \"" + this._form.systemId + "\"" : "") +
">";
},
}
get baseURI() {
return this._form.baseURI;
},
}
get className() {
return this.getAttribute("class") || "";
},
}
get hasChildren() {
return this._form.numChildren > 0;
},
}
get numChildren() {
return this._form.numChildren;
},
}
get hasEventListeners() {
return this._form.hasEventListeners;
},
}
get isBeforePseudoElement() {
return this._form.isBeforePseudoElement;
},
}
get isAfterPseudoElement() {
return this._form.isAfterPseudoElement;
},
}
get isPseudoElement() {
return this.isBeforePseudoElement || this.isAfterPseudoElement;
},
}
get isAnonymous() {
return this._form.isAnonymous;
},
}
get isInHTMLDocument() {
return this._form.isInHTMLDocument;
},
}
get tagName() {
return this.nodeType === nodeConstants.ELEMENT_NODE ? this.nodeName : null;
},
}
get isDocumentElement() {
return !!this._form.isDocumentElement;
},
}
get isShadowRoot() {
return this._form.isShadowRoot;
},
}
get shadowRootMode() {
return this._form.shadowRootMode;
},
}
get isShadowHost() {
return this._form.isShadowHost;
},
}
get customElementLocation() {
return this._form.customElementLocation;
},
}
get isDirectShadowHostChild() {
return this._form.isDirectShadowHostChild;
},
}
// doctype properties
get name() {
return this._form.name;
},
}
get publicId() {
return this._form.publicId;
},
}
get systemId() {
return this._form.systemId;
},
}
getAttribute: function(name) {
getAttribute(name) {
const attr = this._getAttribute(name);
return attr ? attr.value : null;
},
hasAttribute: function(name) {
}
hasAttribute(name) {
this._cacheAttributes();
return (name in this._attrMap);
},
}
get hidden() {
const cls = this.getAttribute("class");
return cls && cls.indexOf(HIDDEN_CLASS) > -1;
},
}
get attributes() {
return this._form.attrs;
},
}
get pseudoClassLocks() {
return this._form.pseudoClassLocks || [];
},
hasPseudoClassLock: function(pseudo) {
}
hasPseudoClassLock(pseudo) {
return this.pseudoClassLocks.some(locked => locked === pseudo);
},
}
get displayType() {
return this._form.displayType;
},
}
get isDisplayed() {
return this._form.isDisplayed;
},
}
get isTreeDisplayed() {
let parent = this;
@ -380,29 +376,27 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
parent = parent.parentNode();
}
return true;
},
}
getNodeValue: custom(function() {
getNodeValue() {
// backward-compatibility: if nodevalue is null and shortValue is defined, the actual
// value of the node needs to be fetched on the server.
if (this._form.nodeValue === null && this._form.shortValue) {
return this._getNodeValue();
return super.getNodeValue();
}
const str = this._form.nodeValue || "";
return promise.resolve(new SimpleStringFront(str));
}, {
impl: "_getNodeValue",
}),
}
/**
* Return a new AttributeModificationList for this node.
*/
startModifyingAttributes: function() {
startModifyingAttributes() {
return new AttributeModificationList(this);
},
}
_cacheAttributes: function() {
_cacheAttributes() {
if (typeof this._attrMap != "undefined") {
return;
}
@ -410,19 +404,19 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
for (const attr of this.attributes) {
this._attrMap[attr.name] = attr;
}
},
}
_getAttribute: function(name) {
_getAttribute(name) {
this._cacheAttributes();
return this._attrMap[name] || undefined;
},
}
/**
* Set this node's parent. Note that the children saved in
* this tree are unordered and incomplete, so shouldn't be used
* instead of a `children` request.
*/
reparent: function(parent) {
reparent(parent) {
if (this._parent === parent) {
return;
}
@ -448,18 +442,18 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
this._next._prev = this;
}
parent._child = this;
},
}
/**
* Return all the known children of this node.
*/
treeChildren: function() {
treeChildren() {
const ret = [];
for (let child = this._child; child != null; child = child._next) {
ret.push(child);
}
return ret;
},
}
/**
* Do we use a local target?
@ -468,16 +462,16 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
* This will, one day, be removed. External code should
* not need to know if the target is remote or not.
*/
isLocalToBeDeprecated: function() {
isLocalToBeDeprecated() {
return !!this.conn._transport._serverConnection;
},
}
/**
* Get a Node for the given node front. This only works locally,
* and is only intended as a stopgap during the transition to the remote
* protocol. If you depend on this you're likely to break soon.
*/
rawNode: function(rawNode) {
rawNode(rawNode) {
if (!this.isLocalToBeDeprecated()) {
console.warn("Tried to use rawNode on a remote connection.");
return null;
@ -490,7 +484,8 @@ const NodeFront = FrontClassWithSpec(nodeSpec, {
return null;
}
return actor.rawNode;
},
});
}
}
exports.NodeFront = NodeFront;
registerFront(NodeFront);

View File

@ -3,13 +3,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { FrontClassWithSpec, Front } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const { perfSpec } = require("devtools/shared/specs/perf");
exports.PerfFront = FrontClassWithSpec(perfSpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client, form);
class PerfFront extends FrontClassWithSpec(perfSpec) {
constructor(client, form) {
super(client, form);
this.actorID = form.perfActor;
this.manage(this);
},
});
}
}
registerFront(PerfFront);

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
loader.lazyRequireGetter(this, "PerformanceIO",
@ -17,9 +17,8 @@ loader.lazyRequireGetter(this, "RecordingUtils",
* This can be used on older Profiler implementations, but the methods cannot
* be changed -- you must introduce a new method, and detect the server.
*/
const PerformanceRecordingFront = FrontClassWithSpec(performanceRecordingSpec,
Object.assign({
form: function(form, detail) {
class PerformanceRecordingFront extends FrontClassWithSpec(performanceRecordingSpec) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
@ -49,20 +48,20 @@ Object.assign({
this._markers = this._markers.sort((a, b) => (a.start > b.start));
this._markersSorted = true;
}
},
}
initialize: function(client, form, config) {
Front.prototype.initialize.call(this, client, form);
constructor(client, form, config) {
super(client, form);
this._markers = [];
this._frames = [];
this._memory = [];
this._ticks = [];
this._allocations = { sites: [], timestamps: [], frames: [], sizes: [] };
},
}
destroy: function() {
Front.prototype.destroy.call(this);
},
destroy() {
super.destroy();
}
/**
* Saves the current recording to a file.
@ -70,15 +69,15 @@ Object.assign({
* @param nsIFile file
* The file to stream the data into.
*/
exportRecording: function(file) {
exportRecording(file) {
const recordingData = this.getAllData();
return PerformanceIO.saveRecordingToFile(recordingData, file);
},
}
/**
* Fired whenever the PerformanceFront emits markers, memory or ticks.
*/
_addTimelineData: function(eventName, data) {
_addTimelineData(eventName, data) {
const config = this.getConfiguration();
switch (eventName) {
@ -144,9 +143,18 @@ Object.assign({
break;
}
}
},
}
toString: () => "[object PerformanceRecordingFront]",
}, PerformanceRecordingCommon));
toString() {
return "[object PerformanceRecordingFront]";
}
}
// PerformanceRecordingFront also needs to inherit from PerformanceRecordingCommon
// but as ES classes don't support multiple inheritance, we are overriding the
// prototype with PerformanceRecordingCommon methods.
Object.defineProperties(PerformanceRecordingFront.prototype,
Object.getOwnPropertyDescriptors(PerformanceRecordingCommon));
exports.PerformanceRecordingFront = PerformanceRecordingFront;
registerFront(PerformanceRecordingFront);

View File

@ -4,7 +4,7 @@
"use strict";
const { Cu } = require("chrome");
const { Front, FrontClassWithSpec, custom, preEvent } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const { PerformanceRecordingFront } = require("devtools/shared/fronts/performance-recording");
const { performanceSpec } = require("devtools/shared/specs/performance");
@ -13,30 +13,31 @@ loader.lazyRequireGetter(this, "PerformanceIO",
loader.lazyRequireGetter(this, "getSystemInfo",
"devtools/shared/system", true);
const PerformanceFront = FrontClassWithSpec(performanceSpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client, form);
class PerformanceFront extends FrontClassWithSpec(performanceSpec) {
constructor(client, form) {
super(client, form);
this.actorID = form.performanceActor;
this.manage(this);
},
destroy: function() {
Front.prototype.destroy.call(this);
},
this.before("profiler-status", this._onProfilerStatus.bind(this));
this.before("timeline-data", this._onTimelineEvent.bind(this));
}
destroy() {
super.destroy();
}
/**
* Conenct to the server, and handle once-off tasks like storing traits
* or system info.
*/
connect: custom(async function() {
async connect() {
const systemClient = await getSystemInfo();
const { traits } = await this._connect({ systemClient });
const { traits } = await super.connect({ systemClient });
this._traits = traits;
return this._traits;
}, {
impl: "_connect",
}),
}
get traits() {
if (!this._traits) {
@ -44,7 +45,7 @@ const PerformanceFront = FrontClassWithSpec(performanceSpec, {
"calling `connect()`.");
}
return this._traits;
},
}
/**
* Pass in a PerformanceRecording and get a normalized value from 0 to 1 of how much
@ -53,7 +54,7 @@ const PerformanceFront = FrontClassWithSpec(performanceSpec, {
* @param {PerformanceRecording} recording
* @return {number?}
*/
getBufferUsageForRecording: function(recording) {
getBufferUsageForRecording(recording) {
if (!recording.isRecording()) {
return void 0;
}
@ -82,7 +83,7 @@ const PerformanceFront = FrontClassWithSpec(performanceSpec, {
}
return percent;
},
}
/**
* Loads a recording from a file.
@ -91,7 +92,7 @@ const PerformanceFront = FrontClassWithSpec(performanceSpec, {
* The file to import the data from.
* @return {Promise<PerformanceRecordingFront>}
*/
importRecording: function(file) {
importRecording(file) {
return PerformanceIO.loadRecordingFromFile(file).then(recordingData => {
const model = new PerformanceRecordingFront();
model._imported = true;
@ -108,26 +109,27 @@ const PerformanceFront = FrontClassWithSpec(performanceSpec, {
model._systemClient = recordingData.systemClient;
return model;
});
},
}
/**
* Store profiler status when the position has been update so we can
* calculate recording's buffer percentage usage after emitting the event.
*/
_onProfilerStatus: preEvent("profiler-status", function(data) {
_onProfilerStatus(data) {
this._currentBufferStatus = data;
}),
}
/**
* For all PerformanceRecordings that are recording, and needing realtime markers,
* apply the timeline data to the front PerformanceRecording (so we only have one event
* for each timeline data chunk as they could be shared amongst several recordings).
*/
_onTimelineEvent: preEvent("timeline-data", function(type, data, recordings) {
_onTimelineEvent(type, data, recordings) {
for (const recording of recordings) {
recording._addTimelineData(type, data);
}
}),
});
}
}
exports.PerformanceFront = PerformanceFront;
registerFront(PerformanceFront);

View File

@ -4,14 +4,15 @@
"use strict";
const {preferenceSpec} = require("devtools/shared/specs/preference");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const PreferenceFront = protocol.FrontClassWithSpec(preferenceSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client);
class PreferenceFront extends FrontClassWithSpec(preferenceSpec) {
constructor(client, form) {
super(client);
this.actorID = form.preferenceActor;
this.manage(this);
},
});
}
}
exports.PreferenceFront = PreferenceFront;
registerFront(PreferenceFront);

View File

@ -4,24 +4,25 @@
"use strict";
const {
Front,
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { promisesSpec } = require("devtools/shared/specs/promises");
/**
* PromisesFront, the front for the PromisesActor.
*/
const PromisesFront = FrontClassWithSpec(promisesSpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client, form);
class PromisesFront extends FrontClassWithSpec(promisesSpec) {
constructor(client, form) {
super(client, form);
this.actorID = form.promisesActor;
this.manage(this);
},
}
destroy: function() {
Front.prototype.destroy.call(this);
},
});
destroy() {
super.destroy();
}
}
exports.PromisesFront = PromisesFront;
registerFront(PromisesFront);

View File

@ -5,25 +5,26 @@
"use strict";
const {reflowSpec} = require("devtools/shared/specs/reflow");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
/**
* Usage example of the reflow front:
*
* let front = ReflowFront(toolbox.target.client, toolbox.target.form);
* let front = new ReflowFront(toolbox.target.client, toolbox.target.form);
* front.on("reflows", this._onReflows);
* front.start();
* // now wait for events to come
*/
const ReflowFront = protocol.FrontClassWithSpec(reflowSpec, {
initialize: function(client, {reflowActor}) {
protocol.Front.prototype.initialize.call(this, client, {actor: reflowActor});
class ReflowFront extends FrontClassWithSpec(reflowSpec) {
constructor(client, {reflowActor}) {
super(client, {actor: reflowActor});
this.manage(this);
},
}
destroy: function() {
protocol.Front.prototype.destroy.call(this);
},
});
destroy() {
super.destroy();
}
}
exports.ReflowFront = ReflowFront;
registerFront(ReflowFront);

View File

@ -5,16 +5,15 @@
const {Ci} = require("chrome");
const {rootSpec} = require("devtools/shared/specs/root");
const protocol = require("devtools/shared/protocol");
const {custom} = protocol;
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "getFront", "devtools/shared/protocol", true);
loader.lazyRequireGetter(this, "BrowsingContextTargetFront", "devtools/shared/fronts/targets/browsing-context", true);
loader.lazyRequireGetter(this, "ContentProcessTargetFront", "devtools/shared/fronts/targets/content-process", true);
const RootFront = protocol.FrontClassWithSpec(rootSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, { actor: form.from });
class RootFront extends FrontClassWithSpec(rootSpec) {
constructor(client, form) {
super(client, { actor: form.from });
this.applicationType = form.applicationType;
this.traits = form.traits;
@ -34,7 +33,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
this.fronts = new Map();
this._client = client;
},
}
/**
* Retrieve all service worker registrations as well as workers from the parent and
@ -51,7 +50,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
* - {Array} other
* Array of WorkerTargetActor forms, containing other workers.
*/
listAllWorkers: async function() {
async listAllWorkers() {
let registrations = [];
let workers = [];
@ -132,7 +131,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
});
return result;
},
}
/**
* Fetch the ParentProcessTargetActor for the main process.
@ -142,13 +141,13 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
*/
getMainProcess() {
return this.getProcess(0);
},
}
getProcess: custom(async function(id) {
async getProcess(id) {
// Do not use specification automatic marshalling as getProcess may return
// two different type: ParentProcessTargetActor or ContentProcessTargetActor.
// Also, we do want to memoize the fronts and return already existing ones.
const { form } = await this._getProcess(id);
const { form } = await super.getProcess(id);
let front = this.actor(form.actor);
if (front) {
return front;
@ -167,9 +166,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
this.manage(front);
return front;
}, {
impl: "_getProcess",
}),
}
/**
* Fetch the target actor for the currently selected tab, or for a specific
@ -183,7 +180,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
* If nothing is specified, returns the actor for the currently
* selected tab.
*/
getTab: custom(async function(filter) {
async getTab(filter) {
const packet = {};
if (filter) {
if (typeof (filter.outerWindowID) == "number") {
@ -210,10 +207,8 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
}
}
return this._getTab(packet);
}, {
impl: "_getTab",
}),
return super.getTab(packet);
}
/**
* Fetch the target front for a given add-on.
@ -227,7 +222,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
const addons = await this.listAddons();
const addonTargetFront = addons.find(addon => addon.id === id);
return addonTargetFront;
},
}
/**
* Test request that returns the object passed as first argument.
@ -239,7 +234,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
echo(packet) {
packet.type = "echo";
return this.request(packet);
},
}
/*
* This function returns a protocol.js Front for any root actor.
@ -257,6 +252,7 @@ const RootFront = protocol.FrontClassWithSpec(rootSpec, {
front = getFront(this._client, typeName, rootForm);
this.fronts.set(typeName, front);
return front;
},
});
}
}
exports.RootFront = RootFront;
registerFront(RootFront);

View File

@ -5,19 +5,20 @@
const {screenshotSpec} = require("devtools/shared/specs/screenshot");
const saveScreenshot = require("devtools/shared/screenshot/save");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const ScreenshotFront = protocol.FrontClassWithSpec(screenshotSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client);
class ScreenshotFront extends FrontClassWithSpec(screenshotSpec) {
constructor(client, form) {
super(client);
this.actorID = form.screenshotActor;
this.manage(this);
},
}
async captureAndSave(window, args) {
const screenshot = await this.capture(args);
return saveScreenshot(window, args, screenshot);
},
});
}
}
exports.ScreenshotFront = ScreenshotFront;
registerFront(ScreenshotFront);

View File

@ -3,11 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const protocol = require("devtools/shared/protocol");
const specs = require("devtools/shared/specs/storage");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const { childSpecs, storageSpec } = require("devtools/shared/specs/storage");
for (const childSpec of Object.values(specs.childSpecs)) {
protocol.FrontClassWithSpec(childSpec, {
for (const childSpec of Object.values(childSpecs)) {
class ChildStorageFront extends FrontClassWithSpec(childSpec) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
@ -17,16 +17,18 @@ for (const childSpec of Object.values(specs.childSpecs)) {
this.actorID = form.actor;
this.hosts = form.hosts;
return null;
},
});
}
}
registerFront(ChildStorageFront);
}
const StorageFront = protocol.FrontClassWithSpec(specs.storageSpec, {
initialize(client, tabForm) {
protocol.Front.prototype.initialize.call(this, client);
class StorageFront extends FrontClassWithSpec(storageSpec) {
constructor(client, tabForm) {
super(client);
this.actorID = tabForm.storageActor;
this.manage(this);
},
});
}
}
exports.StorageFront = StorageFront;
registerFront(StorageFront);

View File

@ -6,27 +6,27 @@
const {DebuggerServer} = require("devtools/server/main");
const promise = require("promise");
const {longStringSpec, SimpleStringFront} = require("devtools/shared/specs/string");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const LongStringFront = protocol.FrontClassWithSpec(longStringSpec, {
initialize: function(client) {
protocol.Front.prototype.initialize.call(this, client);
},
class LongStringFront extends FrontClassWithSpec(longStringSpec) {
constructor(client) {
super(client);
}
destroy: function() {
destroy() {
this.initial = null;
this.length = null;
this.strPromise = null;
protocol.Front.prototype.destroy.call(this);
},
super.destroy();
}
form: function(form) {
form(form) {
this.actorID = form.actor;
this.initial = form.initial;
this.length = form.length;
},
}
string: function() {
string() {
if (!this.strPromise) {
const promiseRest = (thusFar) => {
if (thusFar.length === this.length) {
@ -40,8 +40,10 @@ const LongStringFront = protocol.FrontClassWithSpec(longStringSpec, {
this.strPromise = promiseRest(this.initial);
}
return this.strPromise;
},
});
}
}
exports.LongStringFront = LongStringFront;
registerFront(LongStringFront);
exports.SimpleStringFront = SimpleStringFront;
registerFront(SimpleStringFront);

View File

@ -4,10 +4,8 @@
"use strict";
const {
Front,
FrontClassWithSpec,
custom,
preEvent,
registerFront,
} = require("devtools/shared/protocol");
const {
pageStyleSpec,
@ -21,57 +19,55 @@ loader.lazyRequireGetter(this, "RuleRewriter",
/**
* PageStyleFront, the front object for the PageStyleActor
*/
const PageStyleFront = FrontClassWithSpec(pageStyleSpec, {
initialize: function(conn, form, ctx, detail) {
Front.prototype.initialize.call(this, conn, form, ctx, detail);
class PageStyleFront extends FrontClassWithSpec(pageStyleSpec) {
constructor(conn, form, ctx, detail) {
super(conn, form, ctx, detail);
this.inspector = this.parent();
},
}
form: function(form, detail) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
},
}
destroy: function() {
Front.prototype.destroy.call(this);
},
destroy() {
super.destroy();
}
get walker() {
return this.inspector.walker;
},
}
get supportsAuthoredStyles() {
return this._form.traits && this._form.traits.authoredStyles;
},
}
get supportsFontStretchLevel4() {
return this._form.traits && this._form.traits.fontStretchLevel4;
},
}
get supportsFontStyleLevel4() {
return this._form.traits && this._form.traits.fontStyleLevel4;
},
}
get supportsFontVariations() {
return this._form.traits && this._form.traits.fontVariations;
},
}
get supportsFontWeightLevel4() {
return this._form.traits && this._form.traits.fontWeightLevel4;
},
}
getMatchedSelectors: custom(function(node, property, options) {
return this._getMatchedSelectors(node, property, options).then(ret => {
getMatchedSelectors(node, property, options) {
return super.getMatchedSelectors(node, property, options).then(ret => {
return ret.matched;
});
}, {
impl: "_getMatchedSelectors",
}),
}
getApplied: custom(async function(node, options = {}) {
async getApplied(node, options = {}) {
// If the getApplied method doesn't recreate the style cache itself, this
// means a call to cssLogic.highlight is required before trying to access
// the applied rules. Issue a request to getLayout if this is the case.
@ -79,42 +75,41 @@ const PageStyleFront = FrontClassWithSpec(pageStyleSpec, {
if (!this._form.traits || !this._form.traits.getAppliedCreatesStyleCache) {
await this.getLayout(node);
}
const ret = await this._getApplied(node, options);
const ret = await super.getApplied(node, options);
return ret.entries;
}, {
impl: "_getApplied",
}),
}
addNewRule: custom(function(node, pseudoClasses) {
addNewRule(node, pseudoClasses) {
let addPromise;
if (this.supportsAuthoredStyles) {
addPromise = this._addNewRule(node, pseudoClasses, true);
addPromise = super.addNewRule(node, pseudoClasses, true);
} else {
addPromise = this._addNewRule(node, pseudoClasses);
addPromise = super.addNewRule(node, pseudoClasses);
}
return addPromise.then(ret => {
return ret.entries[0];
});
}, {
impl: "_addNewRule",
}),
});
}
}
exports.PageStyleFront = PageStyleFront;
registerFront(PageStyleFront);
/**
* StyleRuleFront, the front for the StyleRule actor.
*/
const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
initialize: function(client, form, ctx, detail) {
Front.prototype.initialize.call(this, client, form, ctx, detail);
},
class StyleRuleFront extends FrontClassWithSpec(styleRuleSpec) {
constructor(client, form, ctx, detail) {
super(client, form, ctx, detail);
destroy: function() {
Front.prototype.destroy.call(this);
},
this.before("location-changed", this._locationChangedPre.bind(this));
}
form: function(form, detail) {
destroy() {
super.destroy();
}
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
@ -124,16 +119,16 @@ const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
if (this._mediaText) {
this._mediaText = null;
}
},
}
/**
* Ensure _form is updated when location-changed is emitted.
*/
_locationChangedPre: preEvent("location-changed", function(line, column) {
_locationChangedPre(line, column) {
this._clearOriginalLocation();
this._form.line = line;
this._form.column = column;
}),
}
/**
* Return a new RuleModificationList or RuleRewriter for this node.
@ -145,43 +140,43 @@ const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
* This is needed by the RuleRewriter.
* @return {RuleModificationList}
*/
startModifyingProperties: function(cssProperties) {
startModifyingProperties(cssProperties) {
if (this.canSetRuleText) {
return new RuleRewriter(cssProperties.isKnown, this, this.authoredText);
}
return new RuleModificationList(this);
},
}
get type() {
return this._form.type;
},
}
get line() {
return this._form.line || -1;
},
}
get column() {
return this._form.column || -1;
},
}
get cssText() {
return this._form.cssText;
},
}
get authoredText() {
return this._form.authoredText || this._form.cssText;
},
}
get declarations() {
return this._form.declarations || [];
},
}
get keyText() {
return this._form.keyText;
},
}
get name() {
return this._form.name;
},
}
get selectors() {
return this._form.selectors;
},
}
get media() {
return this._form.media;
},
}
get mediaText() {
if (!this._form.media) {
return null;
@ -191,19 +186,19 @@ const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
}
this._mediaText = this.media.join(", ");
return this._mediaText;
},
}
get parentRule() {
return this.conn.getActor(this._form.parentRule);
},
}
get parentStyleSheet() {
return this.conn.getActor(this._form.parentStyleSheet);
},
}
get element() {
return this.conn.getActor(this._form.element);
},
}
get href() {
if (this._form.href) {
@ -211,16 +206,16 @@ const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
}
const sheet = this.parentStyleSheet;
return sheet ? sheet.href : "";
},
}
get nodeHref() {
const sheet = this.parentStyleSheet;
return sheet ? sheet.nodeHref : "";
},
}
get canSetRuleText() {
return this._form.traits && this._form.traits.canSetRuleText;
},
}
get location() {
return {
@ -229,13 +224,13 @@ const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
line: this.line,
column: this.column,
};
},
}
_clearOriginalLocation: function() {
_clearOriginalLocation() {
this._originalLocation = null;
},
}
getOriginalLocation: function() {
getOriginalLocation() {
if (this._originalLocation) {
return promise.resolve(this._originalLocation);
}
@ -262,33 +257,30 @@ const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
this._originalLocation = location;
return location;
});
},
}
modifySelector: custom(async function(node, value) {
async modifySelector(node, value) {
let response;
if (this.canSetRuleText) {
response = await this._modifySelector(node, value, true);
response = await super.modifySelector(node, value, true);
} else {
response = await this._modifySelector(node, value);
response = await super.modifySelector(node, value);
}
if (response.ruleProps) {
response.ruleProps = response.ruleProps.entries[0];
}
return response;
}, {
impl: "_modifySelector",
}),
}
setRuleText: custom(function(newText, modifications) {
setRuleText(newText, modifications) {
this._form.authoredText = newText;
return this._setRuleText(newText, modifications);
}, {
impl: "_setRuleText",
}),
});
return super.setRuleText(newText, modifications);
}
}
exports.StyleRuleFront = StyleRuleFront;
registerFront(StyleRuleFront);
/**
* Convenience API for building a list of attribute modifications

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const {
mediaRuleSpec,
styleSheetSpec,
@ -19,102 +19,103 @@ loader.lazyRequireGetter(this, "getIndentationFromString",
/**
* Corresponding client-side front for a MediaRuleActor.
*/
const MediaRuleFront = FrontClassWithSpec(mediaRuleSpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client, form);
class MediaRuleFront extends FrontClassWithSpec(mediaRuleSpec) {
constructor(client, form) {
super(client, form);
this._onMatchesChange = this._onMatchesChange.bind(this);
this.on("matches-change", this._onMatchesChange);
},
}
_onMatchesChange: function(matches) {
_onMatchesChange(matches) {
this._form.matches = matches;
},
}
form: function(form, detail) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
},
}
get mediaText() {
return this._form.mediaText;
},
}
get conditionText() {
return this._form.conditionText;
},
}
get matches() {
return this._form.matches;
},
}
get line() {
return this._form.line || -1;
},
}
get column() {
return this._form.column || -1;
},
}
get parentStyleSheet() {
return this.conn.getActor(this._form.parentStyleSheet);
},
});
}
}
exports.MediaRuleFront = MediaRuleFront;
registerFront(MediaRuleFront);
/**
* StyleSheetFront is the client-side counterpart to a StyleSheetActor.
*/
const StyleSheetFront = FrontClassWithSpec(styleSheetSpec, {
initialize: function(conn, form) {
Front.prototype.initialize.call(this, conn, form);
class StyleSheetFront extends FrontClassWithSpec(styleSheetSpec) {
constructor(conn, form) {
super(conn, form);
this._onPropertyChange = this._onPropertyChange.bind(this);
this.on("property-change", this._onPropertyChange);
},
}
destroy: function() {
destroy() {
this.off("property-change", this._onPropertyChange);
Front.prototype.destroy.call(this);
},
super.destroy();
}
_onPropertyChange: function(property, value) {
_onPropertyChange(property, value) {
this._form[property] = value;
},
}
form: function(form, detail) {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
},
}
get href() {
return this._form.href;
},
}
get nodeHref() {
return this._form.nodeHref;
},
}
get disabled() {
return !!this._form.disabled;
},
}
get title() {
return this._form.title;
},
}
get isSystem() {
return this._form.system;
},
}
get styleSheetIndex() {
return this._form.styleSheetIndex;
},
}
get ruleCount() {
return this._form.ruleCount;
},
}
get sourceMapURL() {
return this._form.sourceMapURL;
},
}
/**
* Get the indentation to use for edits to this style sheet.
@ -122,7 +123,7 @@ const StyleSheetFront = FrontClassWithSpec(styleSheetSpec, {
* @return {Promise} A promise that will resolve to a string that
* should be used to indent a block in this style sheet.
*/
guessIndentation: function() {
guessIndentation() {
const prefIndent = getIndentationFromPrefs();
if (prefIndent) {
const {indentUnit, indentWithTabs} = prefIndent;
@ -137,20 +138,22 @@ const StyleSheetFront = FrontClassWithSpec(styleSheetSpec, {
return indentWithTabs ? "\t" : " ".repeat(indentUnit);
}.bind(this))();
},
});
}
}
exports.StyleSheetFront = StyleSheetFront;
registerFront(StyleSheetFront);
/**
* The corresponding Front object for the StyleSheetsActor.
*/
const StyleSheetsFront = FrontClassWithSpec(styleSheetsSpec, {
initialize: function(client, tabForm) {
Front.prototype.initialize.call(this, client);
class StyleSheetsFront extends FrontClassWithSpec(styleSheetsSpec) {
constructor(client, tabForm) {
super(client);
this.actorID = tabForm.styleSheetsActor;
this.manage(this);
},
});
}
}
exports.StyleSheetsFront = StyleSheetsFront;
registerFront(StyleSheetsFront);

View File

@ -4,18 +4,17 @@
"use strict";
const {addonTargetSpec} = require("devtools/shared/specs/targets/addon");
const protocol = require("devtools/shared/protocol");
const {custom} = protocol;
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "BrowsingContextTargetFront", "devtools/shared/fronts/targets/browsing-context", true);
const AddonTargetFront = protocol.FrontClassWithSpec(addonTargetSpec, {
initialize: function(client) {
protocol.Front.prototype.initialize.call(this, client);
class AddonTargetFront extends FrontClassWithSpec(addonTargetSpec) {
constructor(client) {
super(client);
this.client = client;
this.traits = {};
},
}
form(json) {
this.actorID = json.actor;
@ -32,7 +31,7 @@ const AddonTargetFront = protocol.FrontClassWithSpec(addonTargetSpec, {
}
this[name] = json[name];
}
},
}
isLegacyTemporaryExtension() {
if (!this.type) {
@ -45,7 +44,7 @@ const AddonTargetFront = protocol.FrontClassWithSpec(addonTargetSpec, {
this.temporarilyInstalled &&
!this.isWebExtension &&
!this.isAPIExtension;
},
}
/**
* Returns the actual target front for web extensions.
@ -56,34 +55,31 @@ const AddonTargetFront = protocol.FrontClassWithSpec(addonTargetSpec, {
* inherits from BrowsingContextTargetActor. This connect method is used to retrive
* the final target actor to use.
*/
connect: custom(async function() {
const { form } = await this._connect();
async connect() {
const { form } = await super.connect();
const front = new BrowsingContextTargetFront(this.client, form);
this.manage(front);
return front;
}, {
impl: "_connect",
}),
}
attach: custom(async function() {
const response = await this._attach();
async attach() {
const response = await super.attach();
this.threadActor = response.threadActor;
return response;
}, {
impl: "_attach",
}),
}
reconfigure: function() {
reconfigure() {
// Toolbox and options panel are calling this method but Addon Target can't be
// reconfigured. So we ignore this call here.
return Promise.resolve();
},
}
attachThread: function() {
attachThread() {
return this.client.attachThread(this.threadActor);
},
});
}
}
exports.AddonTargetFront = AddonTargetFront;
registerFront(AddonTargetFront);

View File

@ -4,15 +4,13 @@
"use strict";
const {browsingContextTargetSpec} = require("devtools/shared/specs/targets/browsing-context");
const protocol = require("devtools/shared/protocol");
const {custom} = protocol;
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
const BrowsingContextTargetFront =
protocol.FrontClassWithSpec(browsingContextTargetSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
class BrowsingContextTargetFront extends FrontClassWithSpec(browsingContextTargetSpec) {
constructor(client, form) {
super(client, form);
this.thread = null;
@ -28,7 +26,7 @@ protocol.FrontClassWithSpec(browsingContextTargetSpec, {
// Save the full form for Target class usage
// Do not use `form` name to avoid colliding with protocol.js's `form` method
this.targetForm = form;
},
}
/**
* Attach to a thread actor.
@ -37,7 +35,7 @@ protocol.FrontClassWithSpec(browsingContextTargetSpec, {
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
*/
attachThread: function(options = {}) {
attachThread(options = {}) {
if (this.thread) {
return Promise.resolve([{}, this.thread]);
}
@ -52,36 +50,32 @@ protocol.FrontClassWithSpec(browsingContextTargetSpec, {
this.client.registerClient(this.thread);
return [response, this.thread];
});
},
}
attach: custom(async function() {
const response = await this._attach();
async attach() {
const response = await super.attach();
this._threadActor = response.threadActor;
this.configureOptions.javascriptEnabled = response.javascriptEnabled;
this.traits = response.traits || {};
return response;
}, {
impl: "_attach",
}),
}
reconfigure: custom(async function({ options }) {
const response = await this._reconfigure({ options });
async reconfigure({ options }) {
const response = await super.reconfigure({ options });
if (typeof options.javascriptEnabled != "undefined") {
this.configureOptions.javascriptEnabled = options.javascriptEnabled;
}
return response;
}, {
impl: "_reconfigure",
}),
}
detach: custom(async function() {
async detach() {
let response;
try {
response = await this._detach();
response = await super.detach();
} catch (e) {
console.warn(
`Error while detaching the browsing context target front: ${e.message}`);
@ -98,9 +92,8 @@ protocol.FrontClassWithSpec(browsingContextTargetSpec, {
this.destroy();
return response;
}, {
impl: "_detach",
}),
});
}
}
exports.BrowsingContextTargetFront = BrowsingContextTargetFront;
registerFront(BrowsingContextTargetFront);

View File

@ -4,11 +4,11 @@
"use strict";
const {contentProcessTargetSpec} = require("devtools/shared/specs/targets/content-process");
const protocol = require("devtools/shared/protocol");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
const ContentProcessTargetFront = protocol.FrontClassWithSpec(contentProcessTargetSpec, {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
class ContentProcessTargetFront extends FrontClassWithSpec(contentProcessTargetSpec) {
constructor(client, form) {
super(client, form);
this.client = client;
this.chromeDebugger = form.chromeDebugger;
@ -18,17 +18,18 @@ const ContentProcessTargetFront = protocol.FrontClassWithSpec(contentProcessTarg
this.targetForm = form;
this.traits = {};
},
}
attachThread() {
return this.client.attachThread(this.chromeDebugger);
},
}
reconfigure: function() {
reconfigure() {
// Toolbox and options panel are calling this method but Worker Target can't be
// reconfigured. So we ignore this call here.
return Promise.resolve();
},
});
}
}
exports.ContentProcessTargetFront = ContentProcessTargetFront;
registerFront(ContentProcessTargetFront);

View File

@ -4,14 +4,13 @@
"use strict";
const {workerTargetSpec} = require("devtools/shared/specs/targets/worker");
const protocol = require("devtools/shared/protocol");
const {custom} = protocol;
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
const WorkerTargetFront = protocol.FrontClassWithSpec(workerTargetSpec, {
initialize: function(client) {
protocol.Front.prototype.initialize.call(this, client);
class WorkerTargetFront extends FrontClassWithSpec(workerTargetSpec) {
constructor(client) {
super(client);
this.thread = null;
this.traits = {};
@ -23,7 +22,7 @@ const WorkerTargetFront = protocol.FrontClassWithSpec(workerTargetSpec, {
this.destroy = this.destroy.bind(this);
this.on("close", this.destroy);
},
}
form(json) {
this.actorID = json.actor;
@ -35,13 +34,13 @@ const WorkerTargetFront = protocol.FrontClassWithSpec(workerTargetSpec, {
this.type = json.type;
this.scope = json.scope;
this.fetch = json.fetch;
},
}
get isClosed() {
return this._isClosed;
},
}
destroy: function() {
destroy() {
this.off("close", this.destroy);
this._isClosed = true;
@ -51,11 +50,11 @@ const WorkerTargetFront = protocol.FrontClassWithSpec(workerTargetSpec, {
this.unmanage(this);
protocol.Front.prototype.destroy.call(this);
},
super.destroy();
}
attach: custom(async function() {
const response = await this._attach();
async attach() {
const response = await super.attach();
this.url = response.url;
@ -67,33 +66,29 @@ const WorkerTargetFront = protocol.FrontClassWithSpec(workerTargetSpec, {
this.threadActor = connectResponse.threadActor;
return response;
}, {
impl: "_attach",
}),
}
detach: custom(async function() {
async detach() {
if (this.isClosed) {
return {};
}
let response;
try {
response = await this._detach();
response = await super.detach();
} catch (e) {
console.warn(`Error while detaching the worker target front: ${e.message}`);
}
this.destroy();
return response;
}, {
impl: "_detach",
}),
}
reconfigure: function() {
reconfigure() {
// Toolbox and options panel are calling this method but Worker Target can't be
// reconfigured. So we ignore this call here.
return Promise.resolve();
},
}
attachThread: async function(options = {}) {
async attachThread(options = {}) {
if (this.thread) {
const response = [{
type: "connected",
@ -112,8 +107,8 @@ const WorkerTargetFront = protocol.FrontClassWithSpec(workerTargetSpec, {
this.client.registerClient(this.thread);
return [attachResponse, this.thread];
},
});
}
}
exports.WorkerTargetFront = WorkerTargetFront;
registerFront(WorkerTargetFront);

Some files were not shown because too many files have changed in this diff Show More