зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to mozilla-inbound. r=merge a=merge
This commit is contained in:
Коммит
444f7c3600
2
.flake8
2
.flake8
|
@ -2,3 +2,5 @@
|
|||
# See http://pep8.readthedocs.io/en/latest/intro.html#configuration
|
||||
ignore = E121, E123, E126, E129, E133, E226, E241, E242, E704, W503, E402
|
||||
max-line-length = 99
|
||||
exclude =
|
||||
testing/mochitest/pywebsocket,
|
||||
|
|
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1340910 - clobber required for Brotli 0.6.0 update due to changes in exported headers.
|
||||
Bug 1395286 - Fix packaging error for Android builds, presumably due to bug 1255404 and/or bug 863246.
|
||||
|
|
|
@ -339,6 +339,7 @@ var BrowserPageActions = {
|
|||
_makeUrlbarButtonNode(action) {
|
||||
let buttonNode = document.createElement("image");
|
||||
buttonNode.classList.add("urlbar-icon", "urlbar-page-action");
|
||||
buttonNode.setAttribute("role", "button");
|
||||
if (action.tooltip) {
|
||||
buttonNode.setAttribute("tooltiptext", action.tooltip);
|
||||
}
|
||||
|
@ -721,7 +722,7 @@ var BrowserPageActionFeedback = {
|
|||
// The timeout value used here allows the panel to stay open for
|
||||
// 1 second after the text transition (duration=120ms) has finished.
|
||||
setTimeout(() => {
|
||||
this.panelNode.hidePopup();
|
||||
this.panelNode.hidePopup(true);
|
||||
}, Services.prefs.getIntPref("browser.pageActions.feedbackTimeoutMS", 1120));
|
||||
},
|
||||
};
|
||||
|
|
|
@ -881,11 +881,13 @@
|
|||
</hbox>
|
||||
<image id="page-report-button"
|
||||
class="urlbar-icon urlbar-page-action"
|
||||
role="button"
|
||||
hidden="true"
|
||||
tooltiptext="&pageReportIcon.tooltip;"
|
||||
onmousedown="gPopupBlockerObserver.onReportButtonMousedown(event);"/>
|
||||
<image id="reader-mode-button"
|
||||
class="urlbar-icon urlbar-page-action"
|
||||
role="button"
|
||||
hidden="true"
|
||||
onclick="ReaderParent.buttonClick(event);"/>
|
||||
<toolbarbutton id="urlbar-zoom-button"
|
||||
|
@ -895,19 +897,23 @@
|
|||
<box id="pageActionSeparator" class="urlbar-page-action"/>
|
||||
<image id="pageActionButton"
|
||||
class="urlbar-icon urlbar-page-action"
|
||||
role="button"
|
||||
tooltiptext="&pageActionButton.tooltip;"
|
||||
onclick="BrowserPageActions.mainButtonClicked(event);"/>
|
||||
<hbox id="star-button-box"
|
||||
hidden="true"
|
||||
class="urlbar-icon-wrapper urlbar-page-action"
|
||||
role="button"
|
||||
context="pageActionPanelContextMenu"
|
||||
oncontextmenu="BrowserPageActions.onContextMenu(event);"
|
||||
onclick="BrowserPageActions.bookmark.onUrlbarNodeClicked(event);">
|
||||
<image id="star-button"
|
||||
class="urlbar-icon"
|
||||
role="button"
|
||||
observes="bookmarkThisPageBroadcaster"/>
|
||||
<hbox id="star-button-animatable-box">
|
||||
<image id="star-button-animatable-image"
|
||||
role="button"
|
||||
observes="bookmarkThisPageBroadcaster"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
add_task(async function() {
|
||||
// When about:home is set to Activity Stream, there are no 'narrow' attributes
|
||||
// therefore for this test, we want to ensure we're using the original about:home
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["browser.newtabpage.activity-stream.aboutHome.enabled", false]
|
||||
]});
|
||||
let newWindow = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
let resizedPromise = BrowserTestUtils.waitForEvent(newWindow, "resize");
|
||||
|
|
|
@ -445,7 +445,7 @@ this.tabs = class extends ExtensionAPI {
|
|||
}
|
||||
if (updateProperties.muted !== null) {
|
||||
if (nativeTab.muted != updateProperties.muted) {
|
||||
nativeTab.toggleMuteAudio(extension.uuid);
|
||||
nativeTab.toggleMuteAudio(extension.id);
|
||||
}
|
||||
}
|
||||
if (updateProperties.pinned !== null) {
|
||||
|
|
|
@ -115,8 +115,7 @@ add_task(async function() {
|
|||
for (let obj of [nonMuted.changeInfo, nonMuted.tab, muted.changeInfo, muted.tab]) {
|
||||
browser.test.assertEq("extension", obj.mutedInfo.reason, "Mute state changed by extension");
|
||||
|
||||
// FIXME: browser.runtime.id is currently broken.
|
||||
browser.test.assertEq(browser.i18n.getMessage("@@extension_id"),
|
||||
browser.test.assertEq(browser.runtime.id,
|
||||
obj.mutedInfo.extensionId,
|
||||
"Mute state changed by extension");
|
||||
}
|
||||
|
@ -128,8 +127,7 @@ add_task(async function() {
|
|||
|
||||
browser.test.assertEq("extension", tab.mutedInfo.reason, "Mute state changed by extension");
|
||||
|
||||
// FIXME: browser.runtime.id is currently broken.
|
||||
browser.test.assertEq(browser.i18n.getMessage("@@extension_id"),
|
||||
browser.test.assertEq(browser.runtime.id,
|
||||
tab.mutedInfo.extensionId,
|
||||
"Mute state changed by extension");
|
||||
|
||||
|
|
|
@ -1602,10 +1602,27 @@ var PlacesControllerDragHelper = {
|
|||
// Adjust insertion index to prevent reversal of dragged items. When you
|
||||
// drag multiple elts upward: need to increment index or each successive
|
||||
// elt will be inserted at the same index, each above the previous.
|
||||
let dragginUp = insertionPoint.itemId == unwrapped.parent &&
|
||||
index < (await PlacesUtils.bookmarks.fetch(unwrapped.itemGuid)).index;
|
||||
if (index != -1 && dragginUp)
|
||||
if (index != -1 && unwrapped.itemGuid) {
|
||||
// Note: we use the parent from the existing bookmark as the sidebar
|
||||
// gives us an unwrapped.parent that is actually a query and not the real
|
||||
// parent.
|
||||
let existingBookmark = await PlacesUtils.bookmarks.fetch(unwrapped.itemGuid);
|
||||
let dragginUp = parentGuid == existingBookmark.parentGuid &&
|
||||
index < existingBookmark.index;
|
||||
|
||||
if (dragginUp) {
|
||||
index += movedCount++;
|
||||
} else if (PlacesUIUtils.useAsyncTransactions) {
|
||||
if (index == existingBookmark.index) {
|
||||
// We're moving to the same index, so there's nothing for us to do.
|
||||
continue;
|
||||
}
|
||||
// If we're dragging down, we need to go one lower to insert at
|
||||
// the real point as moving the element changes the index of
|
||||
// everything below by 1.
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
// If dragging over a tag container we should tag the item.
|
||||
if (insertionPoint.isTag) {
|
||||
|
@ -1638,7 +1655,11 @@ var PlacesControllerDragHelper = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we actually have something to add, if we don't it probably wasn't
|
||||
// valid, or it was moving to the same location, so just ignore it.
|
||||
if (!transactions.length) {
|
||||
return;
|
||||
}
|
||||
if (PlacesUIUtils.useAsyncTransactions) {
|
||||
await PlacesTransactions.batch(transactions);
|
||||
} else {
|
||||
|
|
|
@ -28,6 +28,7 @@ support-files =
|
|||
[browser_click_bookmarks_on_toolbar.js]
|
||||
[browser_cutting_bookmarks.js]
|
||||
subsuite = clipboard
|
||||
[browser_controller_onDrop.js]
|
||||
[browser_copy_folder_tree.js]
|
||||
[browser_copy_query_without_tree.js]
|
||||
subsuite = clipboard
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* global sinon */
|
||||
Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
|
||||
|
||||
const sandbox = sinon.sandbox.create();
|
||||
|
||||
var bookmarks;
|
||||
var bookmarkIds;
|
||||
|
||||
add_task(async function setup() {
|
||||
registerCleanupFunction(async function() {
|
||||
sandbox.restore();
|
||||
delete window.sinon;
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesTestUtils.clearHistory();
|
||||
});
|
||||
|
||||
sandbox.stub(PlacesUIUtils, "getTransactionForData");
|
||||
sandbox.stub(PlacesTransactions, "batch");
|
||||
|
||||
bookmarks = await PlacesUtils.bookmarks.insertTree({
|
||||
guid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
children: [{
|
||||
title: "bm1",
|
||||
url: "http://example1.com"
|
||||
}, {
|
||||
title: "bm2",
|
||||
url: "http://example2.com"
|
||||
}, {
|
||||
title: "bm3",
|
||||
url: "http://example3.com"
|
||||
}]
|
||||
});
|
||||
|
||||
bookmarkIds = await PlacesUtils.promiseManyItemIds([
|
||||
bookmarks[0].guid,
|
||||
bookmarks[1].guid,
|
||||
bookmarks[2].guid,
|
||||
]);
|
||||
});
|
||||
|
||||
async function run_drag_test(startBookmarkIndex, insertionIndex,
|
||||
realInsertionIndex, expectTransactionCreated = true) {
|
||||
// Reset the stubs so that previous test runs don't count against us.
|
||||
PlacesUIUtils.getTransactionForData.reset();
|
||||
PlacesTransactions.batch.reset();
|
||||
|
||||
let dragBookmark = bookmarks[startBookmarkIndex];
|
||||
|
||||
await withSidebarTree("bookmarks", async (tree) => {
|
||||
tree.selectItems([PlacesUtils.unfiledBookmarksFolderId]);
|
||||
PlacesUtils.asContainer(tree.selectedNode).containerOpen = true;
|
||||
|
||||
// Simulating a drag-drop with a tree view turns out to be really difficult
|
||||
// as you can't get a node for the source/target. Hence, we fake the
|
||||
// insertion point and drag data and call the function direct.
|
||||
let ip = new InsertionPoint({
|
||||
parentId: await PlacesUtils.promiseItemId(PlacesUtils.bookmarks.unfiledGuid),
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
index: insertionIndex,
|
||||
orientation: Ci.nsITreeView.DROP_ON
|
||||
});
|
||||
|
||||
let bookmarkWithId = JSON.stringify(Object.assign({
|
||||
id: bookmarkIds.get(dragBookmark.guid),
|
||||
itemGuid: dragBookmark.guid,
|
||||
parent: PlacesUtils.unfiledBookmarksFolderId,
|
||||
}, dragBookmark));
|
||||
|
||||
let dt = {
|
||||
dropEffect: "move",
|
||||
mozCursor: "auto",
|
||||
mozItemCount: 1,
|
||||
types: [ PlacesUtils.TYPE_X_MOZ_PLACE ],
|
||||
mozTypesAt(i) {
|
||||
return this.types;
|
||||
},
|
||||
mozGetDataAt(i) {
|
||||
return bookmarkWithId;
|
||||
}
|
||||
};
|
||||
|
||||
await PlacesControllerDragHelper.onDrop(ip, dt);
|
||||
|
||||
if (!expectTransactionCreated) {
|
||||
Assert.ok(PlacesUIUtils.getTransactionForData.notCalled,
|
||||
"Should not have created transaction data");
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.ok(PlacesUIUtils.getTransactionForData.calledOnce,
|
||||
"Should have called getTransactionForData at least once.");
|
||||
|
||||
let args = PlacesUIUtils.getTransactionForData.args[0];
|
||||
|
||||
Assert.deepEqual(args[0], JSON.parse(bookmarkWithId),
|
||||
"Should have called getTransactionForData with the correct unwrapped bookmark");
|
||||
Assert.equal(args[1], PlacesUtils.TYPE_X_MOZ_PLACE,
|
||||
"Should have called getTransactionForData with the correct flavor");
|
||||
Assert.equal(args[2], PlacesUtils.bookmarks.unfiledGuid,
|
||||
"Should have called getTransactionForData with the correct parent guid");
|
||||
Assert.equal(args[3], realInsertionIndex,
|
||||
"Should have called getTransactionForData with the correct index");
|
||||
Assert.equal(args[4], false,
|
||||
"Should have called getTransactionForData with a move");
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_simple_move_down() {
|
||||
// When we move items down the list, we'll get a drag index that is one higher
|
||||
// than where we actually want to insert to - as the item is being moved up,
|
||||
// everything shifts down one. Hence the index to pass to the transaction should
|
||||
// be one less than the supplied index.
|
||||
await run_drag_test(0, 2, 1);
|
||||
});
|
||||
|
||||
add_task(async function test_simple_move_up() {
|
||||
// When we move items up the list, we want the matching index to be passed to
|
||||
// the transaction as there's no changes below the item in the list.
|
||||
await run_drag_test(2, 0, 0);
|
||||
});
|
||||
|
||||
add_task(async function test_simple_move_to_same() {
|
||||
// If we move to the same index, then we don't expect any transactions to be
|
||||
// created.
|
||||
await run_drag_test(1, 1, 1, false);
|
||||
});
|
|
@ -230,6 +230,7 @@ function search(aQuery, aAttribute, aSubquery, aSubAttribute) {
|
|||
let attributeValue = element.getAttribute(aAttribute);
|
||||
if (attributeValue == aQuery) {
|
||||
if (!element.classList.contains("header") &&
|
||||
element.localName !== "preferences" &&
|
||||
aSubquery && aSubAttribute) {
|
||||
let subAttributeValue = element.getAttribute(aSubAttribute);
|
||||
element.hidden = subAttributeValue != aSubquery;
|
||||
|
|
|
@ -45,6 +45,49 @@ add_task(async function() {
|
|||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
// Test opening to a subcategory displays the correct values for preferences
|
||||
add_task(async function() {
|
||||
// Skip if crash reporting isn't enabled since the checkbox will be missing.
|
||||
if (!AppConstants.MOZ_CRASHREPORTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.crashReports.unsubmittedCheck.autoSubmit", true]],
|
||||
});
|
||||
await openPreferencesViaOpenPreferencesAPI("privacy-reports", {leaveOpen: true});
|
||||
|
||||
let doc = gBrowser.contentDocument;
|
||||
ok(
|
||||
doc.querySelector("#automaticallySubmitCrashesBox").checked,
|
||||
"Checkbox for automatically submitting crashes should be checked when the pref is true and only Reports are requested"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
// Skip if crash reporting isn't enabled since the checkbox will be missing.
|
||||
if (!AppConstants.MOZ_CRASHREPORTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.crashReports.unsubmittedCheck.autoSubmit", false]],
|
||||
});
|
||||
await openPreferencesViaOpenPreferencesAPI("privacy-reports", {leaveOpen: true});
|
||||
|
||||
let doc = gBrowser.contentDocument;
|
||||
ok(
|
||||
!doc.querySelector("#automaticallySubmitCrashesBox").checked,
|
||||
"Checkbox for automatically submitting crashes should not be checked when the pref is false only Reports are requested"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
|
||||
function openPreferencesViaHash(aPane) {
|
||||
return new Promise(resolve => {
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
// This test checks that the Session Restore "Restore Previous Session"
|
||||
// button on about:home is disabled in private mode
|
||||
add_task(async function test_no_sessionrestore_button() {
|
||||
// Activity Stream page does not have a restore session button.
|
||||
// We want to run this test only when Activity Stream is disabled from about:home.
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
["browser.newtabpage.activity-stream.aboutHome.enabled", false]
|
||||
]});
|
||||
// Opening, then closing, a private window shouldn't create session data.
|
||||
(await BrowserTestUtils.openNewBrowserWindow({private: true})).close();
|
||||
|
||||
|
|
|
@ -971,6 +971,8 @@ var SessionStoreInternal = {
|
|||
SessionStoreInternal.restoreNextTab();
|
||||
|
||||
this._sendTabRestoredNotification(tab, data.isRemotenessUpdate);
|
||||
|
||||
Services.obs.notifyObservers(null, "sessionstore-one-or-no-tab-restored");
|
||||
break;
|
||||
case "SessionStore:crashedTabRevived":
|
||||
// The browser was revived by navigating to a different page
|
||||
|
@ -1149,6 +1151,7 @@ var SessionStoreInternal = {
|
|||
|
||||
// Nothing to restore now, notify observers things are complete.
|
||||
Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED);
|
||||
Services.obs.notifyObservers(null, "sessionstore-one-or-no-tab-restored");
|
||||
this._deferredAllWindowsRestored.resolve();
|
||||
} else {
|
||||
TelemetryTimestamps.add("sessionRestoreRestoring");
|
||||
|
@ -1168,6 +1171,7 @@ var SessionStoreInternal = {
|
|||
} else {
|
||||
// Nothing to restore, notify observers things are complete.
|
||||
Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED);
|
||||
Services.obs.notifyObservers(null, "sessionstore-one-or-no-tab-restored");
|
||||
this._deferredAllWindowsRestored.resolve();
|
||||
}
|
||||
// this window was opened by _openWindowWithState
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
[
|
||||
{
|
||||
"version": "Visual Studio 2015 Update 3 14.0.25425.01 / SDK 10.0.14393.0",
|
||||
"size": 326656969,
|
||||
"digest": "babc414ffc0457d27f5a1ed24a8e4873afbe2f1c1a4075469a27c005e1babc3b2a788f643f825efedff95b79686664c67ec4340ed535487168a3482e68559bc7",
|
||||
"algorithm": "sha512",
|
||||
"filename": "vs2015u3.zip",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "Ninja 1.7.1",
|
||||
"size": 184821,
|
||||
"digest": "e4f9a1ae624a2630e75264ba37d396d9c7407d6e6aea3763056210ba6e1387908bd31cf4037a6a3661a418e86c4d2761e0c333e6a3bd0d66549d2b0d72d3f43b",
|
||||
"algorithm": "sha512",
|
||||
"filename": "ninja171.zip",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "MinGit-2.13.3-64-bit",
|
||||
"size": 21482885,
|
||||
"digest": "929bb3c07be8487ee519422a312bdbfeec8f4db4b62c49d02f9aad9fd2a66c0ee5fad63d2b06c8744c336dc9d50446fa4457897333ad17ffd783ecabd1e2ddbb",
|
||||
"algorithm": "sha512",
|
||||
"filename": "git.zip",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
|
@ -372,10 +372,12 @@ var FormAutofillContent = {
|
|||
*
|
||||
* @param {Object} profile Submitted form's address/creditcard guid and record.
|
||||
* @param {Object} domWin Current content window.
|
||||
* @param {int} timeStartedFillingMS Time of form filling started.
|
||||
*/
|
||||
_onFormSubmit(profile, domWin) {
|
||||
_onFormSubmit(profile, domWin, timeStartedFillingMS) {
|
||||
let mm = this._messageManagerFromWindow(domWin);
|
||||
mm.sendAsyncMessage("FormAutofill:OnFormSubmit", profile);
|
||||
mm.sendAsyncMessage("FormAutofill:OnFormSubmit",
|
||||
{profile, timeStartedFillingMS});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -407,7 +409,7 @@ var FormAutofillContent = {
|
|||
return true;
|
||||
}
|
||||
|
||||
this._onFormSubmit(records, domWin);
|
||||
this._onFormSubmit(records, domWin, handler.timeStartedFillingMS);
|
||||
return true;
|
||||
},
|
||||
|
||||
|
|
|
@ -114,6 +114,11 @@ FormAutofillHandler.prototype = {
|
|||
return this._formFieldCount != this.form.elements.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Time in milliseconds since epoch when a user started filling in the form.
|
||||
*/
|
||||
timeStartedFillingMS: null,
|
||||
|
||||
/**
|
||||
* Set fieldDetails from the form about fields that can be autofilled.
|
||||
*
|
||||
|
@ -127,6 +132,7 @@ FormAutofillHandler.prototype = {
|
|||
this._formFieldCount = this.form.elements.length;
|
||||
let fieldDetails = FormAutofillHeuristics.getFormInfo(this.form, allowDuplicates);
|
||||
this.fieldDetails = fieldDetails ? fieldDetails : [];
|
||||
this.form.rootElement.addEventListener("input", this);
|
||||
log.debug("Collected details on", this.fieldDetails.length, "fields");
|
||||
|
||||
this.address.fieldDetails = this.fieldDetails.filter(
|
||||
|
@ -582,4 +588,43 @@ FormAutofillHandler.prototype = {
|
|||
Services.cpmm.sendAsyncMessage("FormAutofill:GetDecryptedString", {cipherText, reauth});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the fieldDetail by HTML element (assume all details were collected in collectFormFields).
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
*
|
||||
* @returns {Object|null}
|
||||
* Return fieldDetail if fieldDetail's element ref could match the target.
|
||||
* (or return null if the element could not match any fieldDetail).
|
||||
*/
|
||||
getFieldDetailsForElement(element) {
|
||||
for (let detail of this.fieldDetails) {
|
||||
if (detail.elementWeakRef.get() == element) {
|
||||
return detail;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "input":
|
||||
if (!event.isTrusted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FormAutofillUtils.isFieldEligibleForAutofill(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.getFieldDetailsForElement(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.form.rootElement.removeEventListener("input", this);
|
||||
this.timeStartedFillingMS = Date.now();
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -355,7 +355,7 @@ FormAutofillParent.prototype = {
|
|||
this._updateStatus();
|
||||
},
|
||||
|
||||
_onAddressSubmit(address, target) {
|
||||
_onAddressSubmit(address, target, timeStartedFillingMS) {
|
||||
if (address.guid) {
|
||||
// Avoid updating the fields that users don't modify.
|
||||
let originalAddress = this.profileStorage.addresses.get(address.guid);
|
||||
|
@ -366,6 +366,8 @@ FormAutofillParent.prototype = {
|
|||
}
|
||||
|
||||
if (!this.profileStorage.addresses.mergeIfPossible(address.guid, address.record)) {
|
||||
this._recordFormFillingTime("address", "autofill-update", timeStartedFillingMS);
|
||||
|
||||
FormAutofillDoorhanger.show(target, "update").then((state) => {
|
||||
let changedGUIDs = this.profileStorage.addresses.mergeToStorage(address.record);
|
||||
switch (state) {
|
||||
|
@ -389,6 +391,7 @@ FormAutofillParent.prototype = {
|
|||
Services.telemetry.scalarAdd("formautofill.addresses.fill_type_autofill_update", 1);
|
||||
return;
|
||||
}
|
||||
this._recordFormFillingTime("address", "autofill", timeStartedFillingMS);
|
||||
this.profileStorage.addresses.notifyUsed(address.guid);
|
||||
// Address is merged successfully
|
||||
Services.telemetry.scalarAdd("formautofill.addresses.fill_type_autofill", 1);
|
||||
|
@ -398,6 +401,7 @@ FormAutofillParent.prototype = {
|
|||
changedGUIDs.push(this.profileStorage.addresses.add(address.record));
|
||||
}
|
||||
changedGUIDs.forEach(guid => this.profileStorage.addresses.notifyUsed(guid));
|
||||
this._recordFormFillingTime("address", "manual", timeStartedFillingMS);
|
||||
|
||||
// Show first time use doorhanger
|
||||
if (Services.prefs.getBoolPref("extensions.formautofill.firstTimeUse")) {
|
||||
|
@ -441,13 +445,28 @@ FormAutofillParent.prototype = {
|
|||
},
|
||||
|
||||
_onFormSubmit(data, target) {
|
||||
let {address, creditCard} = data;
|
||||
let {profile: {address, creditCard}, timeStartedFillingMS} = data;
|
||||
|
||||
if (address) {
|
||||
this._onAddressSubmit(address, target);
|
||||
this._onAddressSubmit(address, target, timeStartedFillingMS);
|
||||
}
|
||||
if (creditCard) {
|
||||
this._onCreditCardSubmit(creditCard, target);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Set the probes for the filling time with specific filling type and form type.
|
||||
*
|
||||
* @private
|
||||
* @param {string} formType
|
||||
* 3 type of form (address/creditcard/address-creditcard).
|
||||
* @param {string} fillingType
|
||||
* 3 filling type (manual/autofill/autofill-update).
|
||||
* @param {int} startedFillingMS
|
||||
* Time that form started to filling in ms.
|
||||
*/
|
||||
_recordFormFillingTime(formType, fillingType, startedFillingMS) {
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("FORM_FILLING_REQUIRED_TIME_MS");
|
||||
histogram.add(`${formType}-${fillingType}`, Date.now() - startedFillingMS);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -118,9 +118,15 @@ var PocketPageAction = {
|
|||
animatableBox.id = "pocket-animatable-box";
|
||||
let animatableImage = doc.createElement("image");
|
||||
animatableImage.id = "pocket-animatable-image";
|
||||
animatableImage.setAttribute("role", "button");
|
||||
let tooltip =
|
||||
gPocketBundle.GetStringFromName("pocket-button.tooltiptext");
|
||||
animatableImage.setAttribute("tooltiptext", tooltip);
|
||||
let pocketButton = doc.createElement("image");
|
||||
pocketButton.id = "pocket-button";
|
||||
pocketButton.classList.add("urlbar-icon");
|
||||
pocketButton.setAttribute("role", "button");
|
||||
pocketButton.setAttribute("tooltiptext", tooltip);
|
||||
|
||||
wrapper.appendChild(pocketButton);
|
||||
wrapper.appendChild(animatableBox);
|
||||
|
|
|
@ -43,8 +43,9 @@ const prefs = Services.prefs.getBranch("extensions.shield-recipe-client.");
|
|||
const TIMER_NAME = "recipe-client-addon-run";
|
||||
const RUN_INTERVAL_PREF = "run_interval_seconds";
|
||||
const FIRST_RUN_PREF = "first_run";
|
||||
const UI_AVAILABLE_NOTIFICATION = "sessionstore-windows-restored";
|
||||
const SHIELD_INIT_NOTIFICATION = "shield-init-complete";
|
||||
const UI_AVAILABLE_TOPIC = "sessionstore-windows-restored";
|
||||
const SHIELD_INIT_TOPIC = "shield-init-complete";
|
||||
const PREF_CHANGED_TOPIC = "nsPref:changed";
|
||||
|
||||
this.RecipeRunner = {
|
||||
init() {
|
||||
|
@ -60,19 +61,8 @@ this.RecipeRunner = {
|
|||
if (prefs.getBoolPref(FIRST_RUN_PREF)) {
|
||||
// Run once immediately after the UI is available. Do this before adding the
|
||||
// timer so we can't end up racing it.
|
||||
const observer = {
|
||||
observe: async (subject, topic, data) => {
|
||||
Services.obs.removeObserver(observer, UI_AVAILABLE_NOTIFICATION);
|
||||
|
||||
await this.run();
|
||||
this.registerTimer();
|
||||
prefs.setBoolPref(FIRST_RUN_PREF, false);
|
||||
|
||||
Services.obs.notifyObservers(null, SHIELD_INIT_NOTIFICATION);
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(observer, UI_AVAILABLE_NOTIFICATION);
|
||||
CleanupManager.addCleanupHandler(() => Services.obs.removeObserver(observer, UI_AVAILABLE_NOTIFICATION));
|
||||
Services.obs.addObserver(this, UI_AVAILABLE_TOPIC);
|
||||
CleanupManager.addCleanupHandler(() => Services.obs.removeObserver(this, UI_AVAILABLE_TOPIC));
|
||||
} else {
|
||||
this.registerTimer();
|
||||
}
|
||||
|
@ -108,17 +98,38 @@ this.RecipeRunner = {
|
|||
return true;
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case PREF_CHANGED_TOPIC:
|
||||
this.observePrefChange(data);
|
||||
break;
|
||||
case UI_AVAILABLE_TOPIC:
|
||||
this.observeUIAvailable().catch(err => Cu.reportError(err));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Watch for preference changes from Services.pref.addObserver.
|
||||
*/
|
||||
observe(changedPrefBranch, action, changedPref) {
|
||||
if (action === "nsPref:changed" && changedPref === RUN_INTERVAL_PREF) {
|
||||
observePrefChange(prefName) {
|
||||
if (prefName === RUN_INTERVAL_PREF) {
|
||||
this.updateRunInterval();
|
||||
} else {
|
||||
log.debug(`Observer fired with unexpected pref change: ${action} ${changedPref}`);
|
||||
log.debug(`Observer fired with unexpected pref change: ${prefName}`);
|
||||
}
|
||||
},
|
||||
|
||||
async observeUIAvailable() {
|
||||
Services.obs.removeObserver(this, UI_AVAILABLE_TOPIC);
|
||||
|
||||
await this.run();
|
||||
this.registerTimer();
|
||||
prefs.setBoolPref(FIRST_RUN_PREF, false);
|
||||
|
||||
Services.obs.notifyObservers(null, SHIELD_INIT_TOPIC);
|
||||
},
|
||||
|
||||
updateRunInterval() {
|
||||
// Run once every `runInterval` wall-clock seconds. This is managed by setting a "last ran"
|
||||
// timestamp, and running if it is more than `runInterval` seconds ago. Even with very short
|
||||
|
|
|
@ -376,7 +376,7 @@ decorate_task(
|
|||
ok(!runStub.called, "RecipeRunner.run is not called immediately");
|
||||
ok(!registerTimerStub.called, "RecipeRunner.registerTimer is not called immediately");
|
||||
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored");
|
||||
RecipeRunner.observe(null, "sessionstore-windows-restored");
|
||||
await TestUtils.topicObserved("shield-init-complete");
|
||||
ok(runStub.called, "RecipeRunner.run is called after the UI is available");
|
||||
ok(registerTimerStub.called, "RecipeRunner.registerTimer is called after the UI is available");
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
ifndef ENABLE_TESTS
|
||||
# We can't package tests if they aren't enabled.
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS = 0
|
||||
endif
|
||||
|
||||
ifneq (,$(filter automation/%,$(MAKECMDGOALS)))
|
||||
ifeq (4.0,$(firstword $(sort 4.0 $(MAKE_VERSION))))
|
||||
MAKEFLAGS += --output-sync=target
|
||||
|
|
|
@ -31,6 +31,10 @@ def jemalloc(value, target, build_project, c_compiler):
|
|||
if target.kernel == 'Linux':
|
||||
return True
|
||||
|
||||
if value and target.kernel not in ('WINNT', 'Linux', 'Darwin', 'kFreeBSD',
|
||||
'FreeBSD', 'NetBSD'):
|
||||
die('--enable-jemalloc is not supported on %s', target.kernel)
|
||||
|
||||
|
||||
set_config('MOZ_MEMORY', jemalloc)
|
||||
set_define('MOZ_MEMORY', jemalloc)
|
||||
|
@ -47,29 +51,6 @@ def jemalloc_for_old_configure(jemalloc):
|
|||
add_old_configure_arg(jemalloc_for_old_configure)
|
||||
|
||||
|
||||
@depends(jemalloc, target)
|
||||
def jemalloc_os_define(jemalloc, target):
|
||||
if jemalloc:
|
||||
if target.kernel == 'WINNT':
|
||||
return 'MOZ_MEMORY_WINDOWS'
|
||||
if target.kernel == 'Linux':
|
||||
return 'MOZ_MEMORY_LINUX'
|
||||
if target.kernel == 'Darwin':
|
||||
return 'MOZ_MEMORY_DARWIN'
|
||||
if target.kernel in ('kFreeBSD', 'FreeBSD', 'NetBSD'):
|
||||
return 'MOZ_MEMORY_BSD'
|
||||
die('--enable-jemalloc is not supported on %s', target.kernel)
|
||||
|
||||
set_define(jemalloc_os_define, '1')
|
||||
|
||||
@depends(jemalloc, target)
|
||||
def jemalloc_os_define_android(jemalloc, target):
|
||||
if jemalloc and target.os == 'Android':
|
||||
return 'MOZ_MEMORY_ANDROID'
|
||||
|
||||
set_define(jemalloc_os_define_android, '1')
|
||||
|
||||
|
||||
option('--enable-replace-malloc',
|
||||
help='Enable ability to dynamically replace the malloc implementation')
|
||||
|
||||
|
|
|
@ -7,5 +7,6 @@ support-files =
|
|||
!/caps/tests/mochitest/file_disableScript.html
|
||||
|
||||
[test_bug995943.xul]
|
||||
skip-if = stylo && debug && os == 'linux' # bug 1384701
|
||||
[test_addonMayLoad.html]
|
||||
[test_disableScript.xul]
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_promise-get-allocation-stack.html";
|
||||
const { PromisesFront } = require("devtools/shared/fronts/promises");
|
||||
var events = require("devtools/shared/event-emitter");
|
||||
var EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
|
@ -48,7 +48,7 @@ function* testGetAllocationStack(client, form, tab) {
|
|||
|
||||
// Get the grip for promise p
|
||||
let onNewPromise = new Promise(resolve => {
|
||||
events.on(front, "new-promises", promises => {
|
||||
EventEmitter.on(front, "new-promises", promises => {
|
||||
for (let p of promises) {
|
||||
if (p.preview.ownProperties.name &&
|
||||
p.preview.ownProperties.name.value === "p") {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
const SOURCE_URL = "browser_dbg_promises-chrome-allocation-stack.js";
|
||||
const PromisesFront = require("devtools/shared/fronts/promises");
|
||||
var events = require("devtools/shared/event-emitter");
|
||||
var EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
const STACK_DATA = [
|
||||
{ functionDisplayName: "test/</<" },
|
||||
|
@ -57,7 +57,7 @@ function* testGetAllocationStack(client, form, makePromises) {
|
|||
|
||||
// Get the grip for promise p
|
||||
let onNewPromise = new Promise(resolve => {
|
||||
events.on(front, "new-promises", promises => {
|
||||
EventEmitter.on(front, "new-promises", promises => {
|
||||
for (let p of promises) {
|
||||
if (p.preview.ownProperties.name &&
|
||||
p.preview.ownProperties.name.value === "p") {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_promise-get-fulfillment-stack.html";
|
||||
const { PromisesFront } = require("devtools/shared/fronts/promises");
|
||||
var events = require("devtools/shared/event-emitter");
|
||||
var EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ function* testGetFulfillmentStack(client, form, tab) {
|
|||
|
||||
// Get the grip for promise p
|
||||
let onNewPromise = new Promise(resolve => {
|
||||
events.on(front, "new-promises", promises => {
|
||||
EventEmitter.on(front, "new-promises", promises => {
|
||||
for (let p of promises) {
|
||||
if (p.preview.ownProperties.name &&
|
||||
p.preview.ownProperties.name.value === "p") {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_promise-get-rejection-stack.html";
|
||||
const { PromisesFront } = require("devtools/shared/fronts/promises");
|
||||
var events = require("devtools/shared/event-emitter");
|
||||
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.
|
||||
|
@ -73,7 +73,7 @@ function* testGetRejectionStack(client, form, tab) {
|
|||
|
||||
// Get the grip for promise p
|
||||
let onNewPromise = new Promise(resolve => {
|
||||
events.on(front, "new-promises", promises => {
|
||||
EventEmitter.on(front, "new-promises", promises => {
|
||||
for (let p of promises) {
|
||||
if (p.preview.ownProperties.name &&
|
||||
p.preview.ownProperties.name.value === "p") {
|
||||
|
|
|
@ -36,11 +36,14 @@ function SourceMapURLService(target, threadClient, sourceMapService) {
|
|||
Services.prefs.addObserver(SOURCE_MAP_PREF, this._onPrefChanged);
|
||||
|
||||
// Start fetching the sources now.
|
||||
this._loadingPromise = new Promise(resolve => {
|
||||
threadClient.getSources(({sources}) => {
|
||||
// Just ignore errors.
|
||||
resolve(sources);
|
||||
});
|
||||
this._loadingPromise = threadClient.getSources().then(({sources}) => {
|
||||
// Ignore errors. Register the sources we got; we can't rely on
|
||||
// an event to arrive if the source actor already existed.
|
||||
for (let source of sources) {
|
||||
this._onSourceUpdated(null, {source});
|
||||
}
|
||||
}, e => {
|
||||
// Also ignore any protocol-based errors.
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ skip-if = debug # Bug 1282269
|
|||
[browser_source_map-01.js]
|
||||
[browser_source_map-absolute.js]
|
||||
[browser_source_map-cross-domain.js]
|
||||
[browser_source_map-init.js]
|
||||
[browser_source_map-inline.js]
|
||||
[browser_source_map-no-race.js]
|
||||
[browser_source_map-reload.js]
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that the source map service initializes properly when source
|
||||
// actors have already been created. Regression test for bug 1391768.
|
||||
|
||||
"use strict";
|
||||
|
||||
const JS_URL = URL_ROOT + "code_bundle_no_race.js";
|
||||
|
||||
const PAGE_URL = `data:text/html,
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Empty test page to test race case</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="${JS_URL}"></script>
|
||||
</body>
|
||||
|
||||
</html>`;
|
||||
|
||||
const ORIGINAL_URL = "webpack:///code_no_race.js";
|
||||
|
||||
const GENERATED_LINE = 84;
|
||||
const ORIGINAL_LINE = 11;
|
||||
|
||||
add_task(function* () {
|
||||
// Opening the debugger causes the source actors to be created.
|
||||
const toolbox = yield openNewTabAndToolbox(PAGE_URL, "jsdebugger");
|
||||
// In bug 1391768, when the sourceMapURLService was created, it was
|
||||
// ignoring any source actors that already existed, leading to
|
||||
// source-mapping failures for those.
|
||||
const service = toolbox.sourceMapURLService;
|
||||
|
||||
info(`checking original location for ${JS_URL}:${GENERATED_LINE}`);
|
||||
let newLoc = yield service.originalPositionFor(JS_URL, GENERATED_LINE);
|
||||
is(newLoc.sourceUrl, ORIGINAL_URL, "check mapped URL");
|
||||
is(newLoc.line, ORIGINAL_LINE, "check mapped line number");
|
||||
});
|
|
@ -7,7 +7,7 @@
|
|||
// on NodeActor. Custom form property is set when 'form' event is sent
|
||||
// by NodeActor actor (see 'onNodeActorForm' method).
|
||||
|
||||
const Events = require("devtools/shared/event-emitter");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {ActorClassWithSpec, Actor, FrontClassWithSpec, Front, generateActorSpec} =
|
||||
require("devtools/shared/protocol");
|
||||
|
||||
|
@ -34,11 +34,11 @@ var EventsFormActor = ActorClassWithSpec(eventsSpec, {
|
|||
},
|
||||
|
||||
attach: function () {
|
||||
Events.on(NodeActor, "form", this.onNodeActorForm);
|
||||
EventEmitter.on(NodeActor, "form", this.onNodeActorForm);
|
||||
},
|
||||
|
||||
detach: function () {
|
||||
Events.off(NodeActor, "form", this.onNodeActorForm);
|
||||
EventEmitter.off(NodeActor, "form", this.onNodeActorForm);
|
||||
},
|
||||
|
||||
onNodeActorForm: function (event) {
|
||||
|
|
|
@ -47,7 +47,6 @@ support-files =
|
|||
!/devtools/client/shared/test/test-actor-registry.js
|
||||
|
||||
[browser_rules_add-property-and-reselect.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
[browser_rules_add-property-cancel_01.js]
|
||||
[browser_rules_add-property-cancel_02.js]
|
||||
[browser_rules_add-property-cancel_03.js]
|
||||
|
@ -112,7 +111,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
|||
[browser_rules_cubicbezier-commit-on-ENTER.js]
|
||||
[browser_rules_cubicbezier-revert-on-ESC.js]
|
||||
[browser_rules_custom.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
skip-if = stylo # Bug 1391198
|
||||
[browser_rules_cycle-angle.js]
|
||||
[browser_rules_cycle-color.js]
|
||||
[browser_rules_edit-display-grid-property.js]
|
||||
|
@ -132,7 +131,7 @@ skip-if = (os == "linux") # Bug 1356214
|
|||
[browser_rules_edit-property_04.js]
|
||||
[browser_rules_edit-property_05.js]
|
||||
[browser_rules_edit-property_06.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
skip-if = stylo # Bug 1391198
|
||||
[browser_rules_edit-property_07.js]
|
||||
[browser_rules_edit-property_08.js]
|
||||
[browser_rules_edit-property_09.js]
|
||||
|
@ -183,17 +182,17 @@ skip-if = (os == "win" && debug) # bug 963492: win.
|
|||
[browser_rules_invalid-source-map.js]
|
||||
[browser_rules_keybindings.js]
|
||||
[browser_rules_keyframes-rule_01.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
skip-if = stylo # Bug 1394994
|
||||
[browser_rules_keyframes-rule_02.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
skip-if = stylo # Bug 1394994
|
||||
[browser_rules_keyframeLineNumbers.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
skip-if = stylo # Bug 1394994
|
||||
[browser_rules_lineNumbers.js]
|
||||
[browser_rules_livepreview.js]
|
||||
[browser_rules_mark_overridden_01.js]
|
||||
[browser_rules_mark_overridden_02.js]
|
||||
[browser_rules_mark_overridden_03.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
skip-if = stylo # Bug 1391198
|
||||
[browser_rules_mark_overridden_04.js]
|
||||
[browser_rules_mark_overridden_05.js]
|
||||
[browser_rules_mark_overridden_06.js]
|
||||
|
@ -223,7 +222,7 @@ skip-if = stylo # Bug 1387445
|
|||
[browser_rules_search-filter-overridden-property.js]
|
||||
[browser_rules_search-filter_01.js]
|
||||
[browser_rules_search-filter_02.js]
|
||||
skip-if = stylo # Bug 1387445
|
||||
skip-if = stylo # Bug 1394994
|
||||
[browser_rules_search-filter_03.js]
|
||||
[browser_rules_search-filter_04.js]
|
||||
[browser_rules_search-filter_05.js]
|
||||
|
|
|
@ -215,6 +215,12 @@ webconsole.menu.copyURL.accesskey=a
|
|||
webconsole.menu.openURL.label=Open URL in New Tab
|
||||
webconsole.menu.openURL.accesskey=T
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.menu.openInNetworkPanel.label)
|
||||
# Label used for a context-menu item displayed for network message logs. Clicking on it
|
||||
# opens the network message in the Network panel
|
||||
webconsole.menu.openInNetworkPanel.label=Open in Network Panel
|
||||
webconsole.menu.openInNetworkPanel.accesskey=N
|
||||
|
||||
# LOCALIZATION NOTE (webconsole.menu.openInVarView.label)
|
||||
# Label used for a context-menu item displayed for object/variable logs. Clicking on it
|
||||
# opens the webconsole variable view for the logged variable.
|
||||
|
|
|
@ -203,11 +203,11 @@ const HeadersPanel = createClass({
|
|||
className: "headers-summary learn-more-link",
|
||||
}),
|
||||
button({
|
||||
className: "devtools-button",
|
||||
className: "devtools-button edit-and-resend-button",
|
||||
onClick: cloneSelectedRequest,
|
||||
}, EDIT_AND_RESEND),
|
||||
button({
|
||||
className: "devtools-button",
|
||||
className: "devtools-button raw-headers-button",
|
||||
onClick: this.toggleRawHeaders,
|
||||
}, RAW_HEADERS),
|
||||
)
|
||||
|
|
|
@ -41,9 +41,9 @@ function NetworkDetailsPanel({
|
|||
request,
|
||||
selectTab,
|
||||
sourceMapService,
|
||||
cloneSelectedRequest,
|
||||
}) :
|
||||
CustomRequestPanel({
|
||||
cloneSelectedRequest,
|
||||
request,
|
||||
})
|
||||
)
|
||||
|
|
|
@ -9,9 +9,8 @@ const {
|
|||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const Actions = require("../actions/index");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { getSelectedRequest } = require("../selectors/index");
|
||||
const { PANELS } = require("../constants");
|
||||
|
||||
// Components
|
||||
const Tabbar = createFactory(require("devtools/client/shared/components/tabs/tabbar"));
|
||||
|
@ -38,7 +37,7 @@ const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
|
|||
*/
|
||||
function TabboxPanel({
|
||||
activeTabId,
|
||||
cloneSelectedRequest,
|
||||
cloneSelectedRequest = ()=>{},
|
||||
request,
|
||||
selectTab,
|
||||
sourceMapService,
|
||||
|
@ -56,45 +55,45 @@ function TabboxPanel({
|
|||
showAllTabsMenu: true,
|
||||
},
|
||||
TabPanel({
|
||||
id: "headers",
|
||||
id: PANELS.HEADERS,
|
||||
title: HEADERS_TITLE,
|
||||
},
|
||||
HeadersPanel({ request, cloneSelectedRequest }),
|
||||
),
|
||||
TabPanel({
|
||||
id: "cookies",
|
||||
id: PANELS.COOKIES,
|
||||
title: COOKIES_TITLE,
|
||||
},
|
||||
CookiesPanel({ request }),
|
||||
),
|
||||
TabPanel({
|
||||
id: "params",
|
||||
id: PANELS.PARAMS,
|
||||
title: PARAMS_TITLE,
|
||||
},
|
||||
ParamsPanel({ request }),
|
||||
),
|
||||
TabPanel({
|
||||
id: "response",
|
||||
id: PANELS.RESPONSE,
|
||||
title: RESPONSE_TITLE,
|
||||
},
|
||||
ResponsePanel({ request }),
|
||||
),
|
||||
TabPanel({
|
||||
id: "timings",
|
||||
id: PANELS.TIMINGS,
|
||||
title: TIMINGS_TITLE,
|
||||
},
|
||||
TimingsPanel({ request }),
|
||||
),
|
||||
request.cause && request.cause.stacktrace && request.cause.stacktrace.length > 0 &&
|
||||
TabPanel({
|
||||
id: "stack-trace",
|
||||
id: PANELS.STACK_TRACE,
|
||||
title: STACK_TRACE_TITLE,
|
||||
},
|
||||
StackTracePanel({ request, sourceMapService }),
|
||||
),
|
||||
request.securityState && request.securityState !== "insecure" &&
|
||||
TabPanel({
|
||||
id: "security",
|
||||
id: PANELS.SECURITY,
|
||||
title: SECURITY_TITLE,
|
||||
},
|
||||
SecurityPanel({ request }),
|
||||
|
@ -107,20 +106,11 @@ TabboxPanel.displayName = "TabboxPanel";
|
|||
|
||||
TabboxPanel.propTypes = {
|
||||
activeTabId: PropTypes.string,
|
||||
cloneSelectedRequest: PropTypes.func.isRequired,
|
||||
cloneSelectedRequest: PropTypes.func,
|
||||
request: PropTypes.object,
|
||||
selectTab: PropTypes.func.isRequired,
|
||||
// Service to enable the source map feature.
|
||||
sourceMapService: PropTypes.object,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
activeTabId: state.ui.detailsPanelSelectedTab,
|
||||
request: getSelectedRequest(state),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
|
||||
selectTab: (tabId) => dispatch(Actions.selectDetailsPanelTab(tabId)),
|
||||
}),
|
||||
)(TabboxPanel);
|
||||
module.exports = connect()(TabboxPanel);
|
||||
|
|
|
@ -5,54 +5,29 @@
|
|||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const { CurlUtils } = require("devtools/client/shared/curl");
|
||||
const { TimelineFront } = require("devtools/shared/fronts/timeline");
|
||||
const { ACTIVITY_TYPE, EVENTS } = require("../constants");
|
||||
const { getDisplayedRequestById } = require("../selectors/index");
|
||||
const { fetchHeaders, formDataURI } = require("../utils/request-utils");
|
||||
const FirefoxDataProvider = require("./firefox-data-provider");
|
||||
|
||||
class FirefoxConnector {
|
||||
constructor() {
|
||||
// Internal properties
|
||||
this.payloadQueue = [];
|
||||
|
||||
// Public methods
|
||||
this.connect = this.connect.bind(this);
|
||||
this.disconnect = this.disconnect.bind(this);
|
||||
this.willNavigate = this.willNavigate.bind(this);
|
||||
this.displayCachedEvents = this.displayCachedEvents.bind(this);
|
||||
this.onDocLoadingMarker = this.onDocLoadingMarker.bind(this);
|
||||
this.addRequest = this.addRequest.bind(this);
|
||||
this.updateRequest = this.updateRequest.bind(this);
|
||||
this.fetchImage = this.fetchImage.bind(this);
|
||||
this.fetchRequestHeaders = this.fetchRequestHeaders.bind(this);
|
||||
this.fetchResponseHeaders = this.fetchResponseHeaders.bind(this);
|
||||
this.fetchPostData = this.fetchPostData.bind(this);
|
||||
this.fetchResponseCookies = this.fetchResponseCookies.bind(this);
|
||||
this.fetchRequestCookies = this.fetchRequestCookies.bind(this);
|
||||
this.getPayloadFromQueue = this.getPayloadFromQueue.bind(this);
|
||||
this.isQueuePayloadReady = this.isQueuePayloadReady.bind(this);
|
||||
this.pushPayloadToQueue = this.pushPayloadToQueue.bind(this);
|
||||
this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
|
||||
this.setPreferences = this.setPreferences.bind(this);
|
||||
this.triggerActivity = this.triggerActivity.bind(this);
|
||||
this.inspectRequest = this.inspectRequest.bind(this);
|
||||
this.getLongString = this.getLongString.bind(this);
|
||||
this.getNetworkRequest = this.getNetworkRequest.bind(this);
|
||||
this.getTabTarget = this.getTabTarget.bind(this);
|
||||
this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
|
||||
|
||||
// Event handlers
|
||||
this.onNetworkEvent = this.onNetworkEvent.bind(this);
|
||||
this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
|
||||
this.onRequestHeaders = this.onRequestHeaders.bind(this);
|
||||
this.onRequestCookies = this.onRequestCookies.bind(this);
|
||||
this.onRequestPostData = this.onRequestPostData.bind(this);
|
||||
this.onSecurityInfo = this.onSecurityInfo.bind(this);
|
||||
this.onResponseHeaders = this.onResponseHeaders.bind(this);
|
||||
this.onResponseCookies = this.onResponseCookies.bind(this);
|
||||
this.onResponseContent = this.onResponseContent.bind(this);
|
||||
this.onEventTimings = this.onEventTimings.bind(this);
|
||||
// Internals
|
||||
this.getLongString = this.getLongString.bind(this);
|
||||
this.getNetworkRequest = this.getNetworkRequest.bind(this);
|
||||
}
|
||||
|
||||
async connect(connection, actions, getState) {
|
||||
|
@ -63,10 +38,17 @@ class FirefoxConnector {
|
|||
|
||||
this.webConsoleClient = this.tabTarget.activeConsole;
|
||||
|
||||
this.dataProvider = new FirefoxDataProvider({
|
||||
webConsoleClient: this.webConsoleClient,
|
||||
actions: this.actions,
|
||||
});
|
||||
|
||||
this.tabTarget.on("will-navigate", this.willNavigate);
|
||||
this.tabTarget.on("close", this.disconnect);
|
||||
this.webConsoleClient.on("networkEvent", this.onNetworkEvent);
|
||||
this.webConsoleClient.on("networkEventUpdate", this.onNetworkEventUpdate);
|
||||
this.webConsoleClient.on("networkEvent",
|
||||
this.dataProvider.onNetworkEvent);
|
||||
this.webConsoleClient.on("networkEventUpdate",
|
||||
this.dataProvider.onNetworkEventUpdate);
|
||||
|
||||
// Don't start up waiting for timeline markers if the server isn't
|
||||
// recent enough to emit the markers we're interested in.
|
||||
|
@ -96,6 +78,7 @@ class FirefoxConnector {
|
|||
this.webConsoleClient.off("networkEventUpdate");
|
||||
this.webConsoleClient = null;
|
||||
this.timelineFront = null;
|
||||
this.dataProvider = null;
|
||||
}
|
||||
|
||||
willNavigate() {
|
||||
|
@ -114,10 +97,10 @@ class FirefoxConnector {
|
|||
displayCachedEvents() {
|
||||
for (let networkInfo of this.webConsoleClient.getNetworkEvents()) {
|
||||
// First add the request to the timeline.
|
||||
this.onNetworkEvent("networkEvent", networkInfo);
|
||||
this.dataProvider.onNetworkEvent("networkEvent", networkInfo);
|
||||
// Then replay any updates already received.
|
||||
for (let updateType of networkInfo.updates) {
|
||||
this.onNetworkEventUpdate("networkEventUpdate", {
|
||||
this.dataProvider.onNetworkEventUpdate("networkEventUpdate", {
|
||||
packet: { updateType },
|
||||
networkInfo,
|
||||
});
|
||||
|
@ -135,222 +118,6 @@ class FirefoxConnector {
|
|||
this.actions.addTimingMarker(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new network request to application state.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @param {object} data data payload will be added to application state
|
||||
*/
|
||||
addRequest(id, data) {
|
||||
let {
|
||||
method,
|
||||
url,
|
||||
isXHR,
|
||||
cause,
|
||||
startedDateTime,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
} = data;
|
||||
|
||||
this.actions.addRequest(
|
||||
id,
|
||||
{
|
||||
// Convert the received date/time string to a unix timestamp.
|
||||
startedMillis: Date.parse(startedDateTime),
|
||||
method,
|
||||
url,
|
||||
isXHR,
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
},
|
||||
true,
|
||||
)
|
||||
.then(() => window.emit(EVENTS.REQUEST_ADDED, id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a network request if it already exists in application state.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @param {object} data data payload will be updated to application state
|
||||
*/
|
||||
async updateRequest(id, data) {
|
||||
let {
|
||||
mimeType,
|
||||
responseContent,
|
||||
responseCookies,
|
||||
responseHeaders,
|
||||
requestCookies,
|
||||
requestHeaders,
|
||||
requestPostData,
|
||||
} = data;
|
||||
|
||||
// fetch request detail contents in parallel
|
||||
let [
|
||||
imageObj,
|
||||
requestHeadersObj,
|
||||
responseHeadersObj,
|
||||
postDataObj,
|
||||
requestCookiesObj,
|
||||
responseCookiesObj,
|
||||
] = await Promise.all([
|
||||
this.fetchImage(mimeType, responseContent),
|
||||
this.fetchRequestHeaders(requestHeaders),
|
||||
this.fetchResponseHeaders(responseHeaders),
|
||||
this.fetchPostData(requestPostData),
|
||||
this.fetchRequestCookies(requestCookies),
|
||||
this.fetchResponseCookies(responseCookies),
|
||||
]);
|
||||
|
||||
let payload = Object.assign({}, data,
|
||||
imageObj, requestHeadersObj, responseHeadersObj,
|
||||
postDataObj, requestCookiesObj, responseCookiesObj);
|
||||
|
||||
this.pushPayloadToQueue(id, payload);
|
||||
|
||||
if (this.isQueuePayloadReady(id)) {
|
||||
await this.actions.updateRequest(id, this.getPayloadFromQueue(id).payload, true);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchImage(mimeType, responseContent) {
|
||||
let payload = {};
|
||||
if (mimeType && responseContent && responseContent.content) {
|
||||
let { encoding, text } = responseContent.content;
|
||||
let response = await this.getLongString(text);
|
||||
|
||||
if (mimeType.includes("image/")) {
|
||||
payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
|
||||
}
|
||||
|
||||
responseContent.content.text = response;
|
||||
payload.responseContent = responseContent;
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchRequestHeaders(requestHeaders) {
|
||||
let payload = {};
|
||||
if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
|
||||
let headers = await fetchHeaders(requestHeaders, this.getLongString);
|
||||
if (headers) {
|
||||
payload.requestHeaders = headers;
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchResponseHeaders(responseHeaders) {
|
||||
let payload = {};
|
||||
if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
|
||||
let headers = await fetchHeaders(responseHeaders, this.getLongString);
|
||||
if (headers) {
|
||||
payload.responseHeaders = headers;
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchPostData(requestPostData) {
|
||||
let payload = {};
|
||||
if (requestPostData && requestPostData.postData) {
|
||||
let { text } = requestPostData.postData;
|
||||
let postData = await this.getLongString(text);
|
||||
const headers = CurlUtils.getHeadersFromMultipartText(postData);
|
||||
const headersSize = headers.reduce((acc, { name, value }) => {
|
||||
return acc + name.length + value.length + 2;
|
||||
}, 0);
|
||||
requestPostData.postData.text = postData;
|
||||
payload.requestPostData = Object.assign({}, requestPostData);
|
||||
payload.requestHeadersFromUploadStream = { headers, headersSize };
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchResponseCookies(responseCookies) {
|
||||
let payload = {};
|
||||
if (responseCookies) {
|
||||
let resCookies = [];
|
||||
// response store cookies in responseCookies or responseCookies.cookies
|
||||
let cookies = responseCookies.cookies ?
|
||||
responseCookies.cookies : responseCookies;
|
||||
// make sure cookies is iterable
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
resCookies.push(Object.assign({}, cookie, {
|
||||
value: await this.getLongString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (resCookies.length) {
|
||||
payload.responseCookies = resCookies;
|
||||
}
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchRequestCookies(requestCookies) {
|
||||
let payload = {};
|
||||
if (requestCookies) {
|
||||
let reqCookies = [];
|
||||
// request store cookies in requestCookies or requestCookies.cookies
|
||||
let cookies = requestCookies.cookies ?
|
||||
requestCookies.cookies : requestCookies;
|
||||
// make sure cookies is iterable
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
reqCookies.push(Object.assign({}, cookie, {
|
||||
value: await this.getLongString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (reqCookies.length) {
|
||||
payload.requestCookies = reqCookies;
|
||||
}
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access a payload item from payload queue.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @return {boolean} return a queued payload item from queue.
|
||||
*/
|
||||
getPayloadFromQueue(id) {
|
||||
return this.payloadQueue.find((item) => item.id === id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet order of "networkUpdateEvent" is predictable, as a result we can wait for
|
||||
* the last one "eventTimings" packet arrives to check payload is ready.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @return {boolean} return whether a specific networkEvent has been updated completely.
|
||||
*/
|
||||
isQueuePayloadReady(id) {
|
||||
let queuedPayload = this.getPayloadFromQueue(id);
|
||||
return queuedPayload && queuedPayload.payload.eventTimings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a request payload into a queue if request doesn't exist. Otherwise update the
|
||||
* request itself.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @param {object} payload request data payload
|
||||
*/
|
||||
pushPayloadToQueue(id, payload) {
|
||||
let queuedPayload = this.getPayloadFromQueue(id);
|
||||
if (!queuedPayload) {
|
||||
this.payloadQueue.push({ id, payload });
|
||||
} else {
|
||||
// Merge upcoming networkEventUpdate payload into existing one
|
||||
queuedPayload.payload = Object.assign({}, queuedPayload.payload, payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a HTTP request data payload
|
||||
*
|
||||
|
@ -490,7 +257,7 @@ class FirefoxConnector {
|
|||
* @return {object} networkInfo data packet
|
||||
*/
|
||||
getNetworkRequest(id) {
|
||||
return this.webConsoleClient.getNetworkRequest(id);
|
||||
return this.dataProvider.getNetworkRequest(id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -505,7 +272,7 @@ class FirefoxConnector {
|
|||
* are available, or rejected if something goes wrong.
|
||||
*/
|
||||
getLongString(stringGrip) {
|
||||
return this.webConsoleClient.getString(stringGrip);
|
||||
return this.dataProvider.getLongString(stringGrip);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -526,213 +293,6 @@ class FirefoxConnector {
|
|||
this.toolbox.viewSourceInDebugger(sourceURL, sourceLine);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The "networkEvent" message type handler.
|
||||
*
|
||||
* @param {string} type message type
|
||||
* @param {object} networkInfo network request information
|
||||
*/
|
||||
onNetworkEvent(type, networkInfo) {
|
||||
let {
|
||||
actor,
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
isXHR,
|
||||
request: {
|
||||
method,
|
||||
url,
|
||||
},
|
||||
startedDateTime,
|
||||
} = networkInfo;
|
||||
|
||||
this.addRequest(actor, {
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
isXHR,
|
||||
method,
|
||||
startedDateTime,
|
||||
url,
|
||||
});
|
||||
|
||||
window.emit(EVENTS.NETWORK_EVENT, actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "networkEventUpdate" message type handler.
|
||||
*
|
||||
* @param {string} type message type
|
||||
* @param {object} packet the message received from the server.
|
||||
* @param {object} networkInfo the network request information.
|
||||
*/
|
||||
onNetworkEventUpdate(type, { packet, networkInfo }) {
|
||||
let { actor } = networkInfo;
|
||||
|
||||
switch (packet.updateType) {
|
||||
case "requestHeaders":
|
||||
this.webConsoleClient.getRequestHeaders(actor, this.onRequestHeaders);
|
||||
window.emit(EVENTS.UPDATING_REQUEST_HEADERS, actor);
|
||||
break;
|
||||
case "requestCookies":
|
||||
this.webConsoleClient.getRequestCookies(actor, this.onRequestCookies);
|
||||
window.emit(EVENTS.UPDATING_REQUEST_COOKIES, actor);
|
||||
break;
|
||||
case "requestPostData":
|
||||
this.webConsoleClient.getRequestPostData(actor, this.onRequestPostData);
|
||||
window.emit(EVENTS.UPDATING_REQUEST_POST_DATA, actor);
|
||||
break;
|
||||
case "securityInfo":
|
||||
this.updateRequest(actor, {
|
||||
securityState: networkInfo.securityInfo,
|
||||
}).then(() => {
|
||||
this.webConsoleClient.getSecurityInfo(actor, this.onSecurityInfo);
|
||||
window.emit(EVENTS.UPDATING_SECURITY_INFO, actor);
|
||||
});
|
||||
break;
|
||||
case "responseHeaders":
|
||||
this.webConsoleClient.getResponseHeaders(actor, this.onResponseHeaders);
|
||||
window.emit(EVENTS.UPDATING_RESPONSE_HEADERS, actor);
|
||||
break;
|
||||
case "responseCookies":
|
||||
this.webConsoleClient.getResponseCookies(actor, this.onResponseCookies);
|
||||
window.emit(EVENTS.UPDATING_RESPONSE_COOKIES, actor);
|
||||
break;
|
||||
case "responseStart":
|
||||
this.updateRequest(actor, {
|
||||
httpVersion: networkInfo.response.httpVersion,
|
||||
remoteAddress: networkInfo.response.remoteAddress,
|
||||
remotePort: networkInfo.response.remotePort,
|
||||
status: networkInfo.response.status,
|
||||
statusText: networkInfo.response.statusText,
|
||||
headersSize: networkInfo.response.headersSize
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
|
||||
});
|
||||
break;
|
||||
case "responseContent":
|
||||
this.webConsoleClient.getResponseContent(actor,
|
||||
this.onResponseContent.bind(this, {
|
||||
contentSize: networkInfo.response.bodySize,
|
||||
transferredSize: networkInfo.response.transferredSize,
|
||||
mimeType: networkInfo.response.content.mimeType
|
||||
}));
|
||||
window.emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
|
||||
break;
|
||||
case "eventTimings":
|
||||
this.updateRequest(actor, { totalTime: networkInfo.totalTime })
|
||||
.then(() => {
|
||||
this.webConsoleClient.getEventTimings(actor, this.onEventTimings);
|
||||
window.emit(EVENTS.UPDATING_EVENT_TIMINGS, actor);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "requestHeaders" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onRequestHeaders(response) {
|
||||
this.updateRequest(response.from, {
|
||||
requestHeaders: response
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "requestCookies" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onRequestCookies(response) {
|
||||
this.updateRequest(response.from, {
|
||||
requestCookies: response
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_REQUEST_COOKIES, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "requestPostData" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onRequestPostData(response) {
|
||||
this.updateRequest(response.from, {
|
||||
requestPostData: response
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "securityInfo" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onSecurityInfo(response) {
|
||||
this.updateRequest(response.from, {
|
||||
securityInfo: response.securityInfo
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "responseHeaders" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onResponseHeaders(response) {
|
||||
this.updateRequest(response.from, {
|
||||
responseHeaders: response
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "responseCookies" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onResponseCookies(response) {
|
||||
this.updateRequest(response.from, {
|
||||
responseCookies: response
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "responseContent" packet.
|
||||
*
|
||||
* @param {object} data the message received from the server event.
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onResponseContent(data, response) {
|
||||
let payload = Object.assign({ responseContent: response }, data);
|
||||
this.updateRequest(response.from, payload).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "eventTimings" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onEventTimings(response) {
|
||||
this.updateRequest(response.from, {
|
||||
eventTimings: response
|
||||
}).then(() => {
|
||||
window.emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new FirefoxConnector();
|
||||
|
|
|
@ -0,0 +1,525 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* eslint-disable block-scoped-var */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { EVENTS } = require("../constants");
|
||||
const { CurlUtils } = require("devtools/client/shared/curl");
|
||||
const { fetchHeaders, formDataURI } = require("../utils/request-utils");
|
||||
|
||||
/**
|
||||
* This object is responsible for fetching additional HTTP
|
||||
* data from the backend.
|
||||
*/
|
||||
class FirefoxDataProvider {
|
||||
constructor({webConsoleClient, actions}) {
|
||||
// Options
|
||||
this.webConsoleClient = webConsoleClient;
|
||||
this.actions = actions;
|
||||
|
||||
// Internal properties
|
||||
this.payloadQueue = [];
|
||||
|
||||
// Public methods
|
||||
this.addRequest = this.addRequest.bind(this);
|
||||
this.updateRequest = this.updateRequest.bind(this);
|
||||
|
||||
// Internals
|
||||
this.fetchImage = this.fetchImage.bind(this);
|
||||
this.fetchRequestHeaders = this.fetchRequestHeaders.bind(this);
|
||||
this.fetchResponseHeaders = this.fetchResponseHeaders.bind(this);
|
||||
this.fetchPostData = this.fetchPostData.bind(this);
|
||||
this.fetchResponseCookies = this.fetchResponseCookies.bind(this);
|
||||
this.fetchRequestCookies = this.fetchRequestCookies.bind(this);
|
||||
this.getPayloadFromQueue = this.getPayloadFromQueue.bind(this);
|
||||
this.isQueuePayloadReady = this.isQueuePayloadReady.bind(this);
|
||||
this.pushPayloadToQueue = this.pushPayloadToQueue.bind(this);
|
||||
this.getLongString = this.getLongString.bind(this);
|
||||
this.getNetworkRequest = this.getNetworkRequest.bind(this);
|
||||
|
||||
// Event handlers
|
||||
this.onNetworkEvent = this.onNetworkEvent.bind(this);
|
||||
this.onNetworkEventUpdate = this.onNetworkEventUpdate.bind(this);
|
||||
this.onRequestHeaders = this.onRequestHeaders.bind(this);
|
||||
this.onRequestCookies = this.onRequestCookies.bind(this);
|
||||
this.onRequestPostData = this.onRequestPostData.bind(this);
|
||||
this.onSecurityInfo = this.onSecurityInfo.bind(this);
|
||||
this.onResponseHeaders = this.onResponseHeaders.bind(this);
|
||||
this.onResponseCookies = this.onResponseCookies.bind(this);
|
||||
this.onResponseContent = this.onResponseContent.bind(this);
|
||||
this.onEventTimings = this.onEventTimings.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new network request to application state.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @param {object} data data payload will be added to application state
|
||||
*/
|
||||
async addRequest(id, data) {
|
||||
let {
|
||||
method,
|
||||
url,
|
||||
isXHR,
|
||||
cause,
|
||||
startedDateTime,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
} = data;
|
||||
|
||||
if (this.actions.addRequest) {
|
||||
await this.actions.addRequest(id, {
|
||||
// Convert the received date/time string to a unix timestamp.
|
||||
startedMillis: Date.parse(startedDateTime),
|
||||
method,
|
||||
url,
|
||||
isXHR,
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker},
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
emit(EVENTS.REQUEST_ADDED, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a network request if it already exists in application state.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @param {object} data data payload will be updated to application state
|
||||
*/
|
||||
async updateRequest(id, data) {
|
||||
let {
|
||||
mimeType,
|
||||
responseContent,
|
||||
responseCookies,
|
||||
responseHeaders,
|
||||
requestCookies,
|
||||
requestHeaders,
|
||||
requestPostData,
|
||||
} = data;
|
||||
|
||||
// fetch request detail contents in parallel
|
||||
let [
|
||||
imageObj,
|
||||
requestHeadersObj,
|
||||
responseHeadersObj,
|
||||
postDataObj,
|
||||
requestCookiesObj,
|
||||
responseCookiesObj,
|
||||
] = await Promise.all([
|
||||
this.fetchImage(mimeType, responseContent),
|
||||
this.fetchRequestHeaders(requestHeaders),
|
||||
this.fetchResponseHeaders(responseHeaders),
|
||||
this.fetchPostData(requestPostData),
|
||||
this.fetchRequestCookies(requestCookies),
|
||||
this.fetchResponseCookies(responseCookies),
|
||||
]);
|
||||
|
||||
let payload = Object.assign({},
|
||||
data,
|
||||
imageObj,
|
||||
requestHeadersObj,
|
||||
responseHeadersObj,
|
||||
postDataObj,
|
||||
requestCookiesObj,
|
||||
responseCookiesObj
|
||||
);
|
||||
|
||||
this.pushPayloadToQueue(id, payload);
|
||||
|
||||
if (this.actions.updateRequest && this.isQueuePayloadReady(id)) {
|
||||
await this.actions.updateRequest(id, this.getPayloadFromQueue(id).payload, true);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchImage(mimeType, responseContent) {
|
||||
let payload = {};
|
||||
if (mimeType && responseContent && responseContent.content) {
|
||||
let { encoding, text } = responseContent.content;
|
||||
let response = await this.getLongString(text);
|
||||
|
||||
if (mimeType.includes("image/")) {
|
||||
payload.responseContentDataUri = formDataURI(mimeType, encoding, response);
|
||||
}
|
||||
|
||||
responseContent.content.text = response;
|
||||
payload.responseContent = responseContent;
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchRequestHeaders(requestHeaders) {
|
||||
let payload = {};
|
||||
if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
|
||||
let headers = await fetchHeaders(requestHeaders, this.getLongString);
|
||||
if (headers) {
|
||||
payload.requestHeaders = headers;
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchResponseHeaders(responseHeaders) {
|
||||
let payload = {};
|
||||
if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
|
||||
let headers = await fetchHeaders(responseHeaders, this.getLongString);
|
||||
if (headers) {
|
||||
payload.responseHeaders = headers;
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchPostData(requestPostData) {
|
||||
let payload = {};
|
||||
if (requestPostData && requestPostData.postData) {
|
||||
let { text } = requestPostData.postData;
|
||||
let postData = await this.getLongString(text);
|
||||
const headers = CurlUtils.getHeadersFromMultipartText(postData);
|
||||
|
||||
// Calculate total header size and don't forget to include
|
||||
// two new-line characters at the end.
|
||||
const headersSize = headers.reduce((acc, { name, value }) => {
|
||||
return acc + name.length + value.length + 2;
|
||||
}, 0);
|
||||
|
||||
requestPostData.postData.text = postData;
|
||||
payload.requestPostData = Object.assign({}, requestPostData);
|
||||
payload.requestHeadersFromUploadStream = { headers, headersSize };
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchResponseCookies(responseCookies) {
|
||||
let payload = {};
|
||||
if (responseCookies) {
|
||||
let resCookies = [];
|
||||
// response store cookies in responseCookies or responseCookies.cookies
|
||||
let cookies = responseCookies.cookies ?
|
||||
responseCookies.cookies : responseCookies;
|
||||
// make sure cookies is iterable
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
resCookies.push(Object.assign({}, cookie, {
|
||||
value: await this.getLongString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (resCookies.length) {
|
||||
payload.responseCookies = resCookies;
|
||||
}
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
async fetchRequestCookies(requestCookies) {
|
||||
let payload = {};
|
||||
if (requestCookies) {
|
||||
let reqCookies = [];
|
||||
// request store cookies in requestCookies or requestCookies.cookies
|
||||
let cookies = requestCookies.cookies ?
|
||||
requestCookies.cookies : requestCookies;
|
||||
// make sure cookies is iterable
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
reqCookies.push(Object.assign({}, cookie, {
|
||||
value: await this.getLongString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (reqCookies.length) {
|
||||
payload.requestCookies = reqCookies;
|
||||
}
|
||||
}
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access a payload item from payload queue.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @return {boolean} return a queued payload item from queue.
|
||||
*/
|
||||
getPayloadFromQueue(id) {
|
||||
return this.payloadQueue.find((item) => item.id === id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if payload is ready (all data fetched from the backend)
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @return {boolean} return whether a specific networkEvent has been updated completely.
|
||||
*/
|
||||
isQueuePayloadReady(id) {
|
||||
let queuedPayload = this.getPayloadFromQueue(id);
|
||||
|
||||
// TODO we should find a better solution since it might happen
|
||||
// that eventTimings is not the last update.
|
||||
return queuedPayload && queuedPayload.payload.eventTimings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a request payload into a queue if request doesn't exist. Otherwise update the
|
||||
* request itself.
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @param {object} payload request data payload
|
||||
*/
|
||||
pushPayloadToQueue(id, payload) {
|
||||
let queuedPayload = this.getPayloadFromQueue(id);
|
||||
if (!queuedPayload) {
|
||||
this.payloadQueue.push({ id, payload });
|
||||
} else {
|
||||
// Merge upcoming networkEventUpdate payload into existing one
|
||||
queuedPayload.payload = Object.assign({}, queuedPayload.payload, payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the network information packet from actor server
|
||||
*
|
||||
* @param {string} id request id
|
||||
* @return {object} networkInfo data packet
|
||||
*/
|
||||
getNetworkRequest(id) {
|
||||
return this.webConsoleClient.getNetworkRequest(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the full text of a LongString.
|
||||
*
|
||||
* @param {object|string} stringGrip
|
||||
* The long string grip containing the corresponding actor.
|
||||
* If you pass in a plain string (by accident or because you're lazy),
|
||||
* then a promise of the same string is simply returned.
|
||||
* @return {object}
|
||||
* A promise that is resolved when the full string contents
|
||||
* are available, or rejected if something goes wrong.
|
||||
*/
|
||||
getLongString(stringGrip) {
|
||||
return this.webConsoleClient.getString(stringGrip);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "networkEvent" message type handler.
|
||||
*
|
||||
* @param {string} type message type
|
||||
* @param {object} networkInfo network request information
|
||||
*/
|
||||
onNetworkEvent(type, networkInfo) {
|
||||
let {
|
||||
actor,
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
isXHR,
|
||||
request: {
|
||||
method,
|
||||
url,
|
||||
},
|
||||
startedDateTime,
|
||||
} = networkInfo;
|
||||
|
||||
this.addRequest(actor, {
|
||||
cause,
|
||||
fromCache,
|
||||
fromServiceWorker,
|
||||
isXHR,
|
||||
method,
|
||||
startedDateTime,
|
||||
url,
|
||||
});
|
||||
|
||||
emit(EVENTS.NETWORK_EVENT, actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "networkEventUpdate" message type handler.
|
||||
*
|
||||
* @param {string} type message type
|
||||
* @param {object} packet the message received from the server.
|
||||
* @param {object} networkInfo the network request information.
|
||||
*/
|
||||
onNetworkEventUpdate(type, { packet, networkInfo }) {
|
||||
let { actor } = networkInfo;
|
||||
|
||||
switch (packet.updateType) {
|
||||
case "requestHeaders":
|
||||
this.webConsoleClient.getRequestHeaders(actor, this.onRequestHeaders);
|
||||
emit(EVENTS.UPDATING_REQUEST_HEADERS, actor);
|
||||
break;
|
||||
case "requestCookies":
|
||||
this.webConsoleClient.getRequestCookies(actor, this.onRequestCookies);
|
||||
emit(EVENTS.UPDATING_REQUEST_COOKIES, actor);
|
||||
break;
|
||||
case "requestPostData":
|
||||
this.webConsoleClient.getRequestPostData(actor, this.onRequestPostData);
|
||||
emit(EVENTS.UPDATING_REQUEST_POST_DATA, actor);
|
||||
break;
|
||||
case "securityInfo":
|
||||
this.updateRequest(actor, {
|
||||
securityState: networkInfo.securityInfo,
|
||||
}).then(() => {
|
||||
this.webConsoleClient.getSecurityInfo(actor, this.onSecurityInfo);
|
||||
emit(EVENTS.UPDATING_SECURITY_INFO, actor);
|
||||
});
|
||||
break;
|
||||
case "responseHeaders":
|
||||
this.webConsoleClient.getResponseHeaders(actor, this.onResponseHeaders);
|
||||
emit(EVENTS.UPDATING_RESPONSE_HEADERS, actor);
|
||||
break;
|
||||
case "responseCookies":
|
||||
this.webConsoleClient.getResponseCookies(actor, this.onResponseCookies);
|
||||
emit(EVENTS.UPDATING_RESPONSE_COOKIES, actor);
|
||||
break;
|
||||
case "responseStart":
|
||||
this.updateRequest(actor, {
|
||||
httpVersion: networkInfo.response.httpVersion,
|
||||
remoteAddress: networkInfo.response.remoteAddress,
|
||||
remotePort: networkInfo.response.remotePort,
|
||||
status: networkInfo.response.status,
|
||||
statusText: networkInfo.response.statusText,
|
||||
headersSize: networkInfo.response.headersSize
|
||||
}).then(() => {
|
||||
emit(EVENTS.STARTED_RECEIVING_RESPONSE, actor);
|
||||
});
|
||||
break;
|
||||
case "responseContent":
|
||||
this.webConsoleClient.getResponseContent(actor,
|
||||
this.onResponseContent.bind(this, {
|
||||
contentSize: networkInfo.response.bodySize,
|
||||
transferredSize: networkInfo.response.transferredSize,
|
||||
mimeType: networkInfo.response.content.mimeType
|
||||
}));
|
||||
emit(EVENTS.UPDATING_RESPONSE_CONTENT, actor);
|
||||
break;
|
||||
case "eventTimings":
|
||||
this.updateRequest(actor, { totalTime: networkInfo.totalTime })
|
||||
.then(() => {
|
||||
this.webConsoleClient.getEventTimings(actor, this.onEventTimings);
|
||||
emit(EVENTS.UPDATING_EVENT_TIMINGS, actor);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "requestHeaders" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onRequestHeaders(response) {
|
||||
this.updateRequest(response.from, {
|
||||
requestHeaders: response
|
||||
}).then(() => {
|
||||
emit(EVENTS.RECEIVED_REQUEST_HEADERS, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "requestCookies" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onRequestCookies(response) {
|
||||
this.updateRequest(response.from, {
|
||||
requestCookies: response
|
||||
}).then(() => {
|
||||
emit(EVENTS.RECEIVED_REQUEST_COOKIES, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "requestPostData" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onRequestPostData(response) {
|
||||
this.updateRequest(response.from, {
|
||||
requestPostData: response
|
||||
}).then(() => {
|
||||
emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "securityInfo" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onSecurityInfo(response) {
|
||||
this.updateRequest(response.from, {
|
||||
securityInfo: response.securityInfo
|
||||
}).then(() => {
|
||||
emit(EVENTS.RECEIVED_SECURITY_INFO, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "responseHeaders" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onResponseHeaders(response) {
|
||||
this.updateRequest(response.from, {
|
||||
responseHeaders: response
|
||||
}).then(() => {
|
||||
emit(EVENTS.RECEIVED_RESPONSE_HEADERS, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "responseCookies" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onResponseCookies(response) {
|
||||
this.updateRequest(response.from, {
|
||||
responseCookies: response
|
||||
}).then(() => {
|
||||
emit(EVENTS.RECEIVED_RESPONSE_COOKIES, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "responseContent" packet.
|
||||
*
|
||||
* @param {object} data the message received from the server event.
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onResponseContent(data, response) {
|
||||
let payload = Object.assign({ responseContent: response }, data);
|
||||
this.updateRequest(response.from, payload).then(() => {
|
||||
emit(EVENTS.RECEIVED_RESPONSE_CONTENT, response.from);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles additional information received for a "eventTimings" packet.
|
||||
*
|
||||
* @param {object} response the message received from the server.
|
||||
*/
|
||||
onEventTimings(response) {
|
||||
this.updateRequest(response.from, {
|
||||
eventTimings: response
|
||||
}).then(() => {
|
||||
emit(EVENTS.RECEIVED_EVENT_TIMINGS, response.from);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guard 'emit' to avoid exception in non-window environment.
|
||||
*/
|
||||
function emit(type, data) {
|
||||
if (typeof window != "undefined") {
|
||||
window.emit(type, data);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FirefoxDataProvider;
|
|
@ -4,5 +4,6 @@
|
|||
|
||||
DevToolsModules(
|
||||
'firefox-connector.js',
|
||||
'firefox-data-provider.js',
|
||||
'index.js',
|
||||
)
|
||||
|
|
|
@ -94,6 +94,44 @@ const EVENTS = {
|
|||
CONNECTED: "connected",
|
||||
};
|
||||
|
||||
const UPDATE_PROPS = [
|
||||
"method",
|
||||
"url",
|
||||
"remotePort",
|
||||
"remoteAddress",
|
||||
"status",
|
||||
"statusText",
|
||||
"httpVersion",
|
||||
"securityState",
|
||||
"securityInfo",
|
||||
"mimeType",
|
||||
"contentSize",
|
||||
"transferredSize",
|
||||
"totalTime",
|
||||
"eventTimings",
|
||||
"headersSize",
|
||||
"customQueryValue",
|
||||
"requestHeaders",
|
||||
"requestHeadersFromUploadStream",
|
||||
"requestCookies",
|
||||
"requestPostData",
|
||||
"responseHeaders",
|
||||
"responseCookies",
|
||||
"responseContent",
|
||||
"responseContentDataUri",
|
||||
"formDataSections",
|
||||
];
|
||||
|
||||
const PANELS = {
|
||||
COOKIES: "cookies",
|
||||
HEADERS: "headers",
|
||||
PARAMS: "params",
|
||||
RESPONSE: "response",
|
||||
SECURITY: "security",
|
||||
STACK_TRACE: "stack-trace",
|
||||
TIMINGS: "timings",
|
||||
};
|
||||
|
||||
const RESPONSE_HEADERS = [
|
||||
"Cache-Control",
|
||||
"Connection",
|
||||
|
@ -246,11 +284,13 @@ const general = {
|
|||
ACTIVITY_TYPE,
|
||||
EVENTS,
|
||||
FILTER_SEARCH_DELAY: 200,
|
||||
UPDATE_PROPS,
|
||||
HEADERS,
|
||||
RESPONSE_HEADERS,
|
||||
FILTER_FLAGS,
|
||||
SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE: 51200, // 50 KB in bytes
|
||||
REQUESTS_WATERFALL,
|
||||
PANELS,
|
||||
};
|
||||
|
||||
// flatten constants
|
||||
|
|
|
@ -15,6 +15,7 @@ const {
|
|||
SELECT_REQUEST,
|
||||
SEND_CUSTOM_REQUEST,
|
||||
UPDATE_REQUEST,
|
||||
UPDATE_PROPS,
|
||||
} = require("../constants");
|
||||
|
||||
const Request = I.Record({
|
||||
|
@ -68,34 +69,6 @@ const Requests = I.Record({
|
|||
lastEndedMillis: -Infinity,
|
||||
});
|
||||
|
||||
const UPDATE_PROPS = [
|
||||
"method",
|
||||
"url",
|
||||
"remotePort",
|
||||
"remoteAddress",
|
||||
"status",
|
||||
"statusText",
|
||||
"httpVersion",
|
||||
"securityState",
|
||||
"securityInfo",
|
||||
"mimeType",
|
||||
"contentSize",
|
||||
"transferredSize",
|
||||
"totalTime",
|
||||
"eventTimings",
|
||||
"headersSize",
|
||||
"customQueryValue",
|
||||
"requestHeaders",
|
||||
"requestHeadersFromUploadStream",
|
||||
"requestCookies",
|
||||
"requestPostData",
|
||||
"responseHeaders",
|
||||
"responseCookies",
|
||||
"responseContent",
|
||||
"responseContentDataUri",
|
||||
"formDataSections",
|
||||
];
|
||||
|
||||
/**
|
||||
* Remove the currently selected custom request.
|
||||
*/
|
||||
|
|
|
@ -19,6 +19,7 @@ const {
|
|||
SELECT_REQUEST,
|
||||
TOGGLE_COLUMN,
|
||||
WATERFALL_RESIZE,
|
||||
PANELS,
|
||||
} = require("../constants");
|
||||
|
||||
const cols = {
|
||||
|
@ -51,7 +52,7 @@ const Columns = I.Record(
|
|||
|
||||
const UI = I.Record({
|
||||
columns: new Columns(),
|
||||
detailsPanelSelectedTab: "headers",
|
||||
detailsPanelSelectedTab: PANELS.HEADERS,
|
||||
networkDetailsOpen: false,
|
||||
browserCacheDisabled: Services.prefs.getBoolPref("devtools.cache.disabled"),
|
||||
statisticsOpen: false,
|
||||
|
|
|
@ -13,9 +13,6 @@ pref("devtools.devedition.promo.url", "https://www.mozilla.org/firefox/developer
|
|||
pref("devtools.devedition.promo.enabled", false);
|
||||
#endif
|
||||
|
||||
// DevTools development workflow
|
||||
pref("devtools.loader.hotreload", false);
|
||||
|
||||
// Developer toolbar preferences
|
||||
pref("devtools.toolbar.enabled", true);
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@ tags = devtools
|
|||
subsuite = devtools
|
||||
# !e10s: RDM only works for remote tabs
|
||||
# Win: Bug 1319248
|
||||
# Stylo: Bug 1384701
|
||||
skip-if = !e10s || os == "win" || (stylo && os == "linux" && debug)
|
||||
skip-if = !e10s || os == "win"
|
||||
support-files =
|
||||
devices.json
|
||||
doc_page_state.html
|
||||
|
|
|
@ -8,7 +8,6 @@ const loaders = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {
|
|||
const { devtools } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { joinURI } = devtools.require("devtools/shared/path");
|
||||
const { assert } = devtools.require("devtools/shared/DevToolsUtils");
|
||||
const Services = devtools.require("Services");
|
||||
const { AppConstants } = devtools.require("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
const BROWSER_BASED_DIRS = [
|
||||
|
@ -37,10 +36,6 @@ const COMMON_LIBRARY_DIRS = [
|
|||
const browserBasedDirsRegExp =
|
||||
/^resource\:\/\/devtools\/client\/\S*\/components\//;
|
||||
|
||||
function clearCache() {
|
||||
Services.obs.notifyObservers(null, "startupcache-invalidate");
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a loader to be used in a browser environment. This evaluates
|
||||
* modules in their own environment, but sets window (the normal
|
||||
|
@ -101,7 +96,6 @@ function BrowserLoaderBuilder({ baseURI, window, useOnlyShared, commonLibRequire
|
|||
|
||||
const loaderOptions = devtools.require("@loader/options");
|
||||
const dynamicPaths = {};
|
||||
const componentProxies = new Map();
|
||||
|
||||
if (AppConstants.DEBUG || AppConstants.DEBUG_JS_MODULES) {
|
||||
dynamicPaths["devtools/client/shared/vendor/react"] =
|
||||
|
@ -169,39 +163,6 @@ function BrowserLoaderBuilder({ baseURI, window, useOnlyShared, commonLibRequire
|
|||
}
|
||||
};
|
||||
|
||||
if (Services.prefs.getBoolPref("devtools.loader.hotreload")) {
|
||||
opts.loadModuleHook = (module, require) => {
|
||||
const { uri, exports } = module;
|
||||
|
||||
if (exports.prototype &&
|
||||
exports.prototype.isReactComponent) {
|
||||
const { createProxy, getForceUpdate } =
|
||||
require("devtools/client/shared/vendor/react-proxy");
|
||||
const React = require("devtools/client/shared/vendor/react");
|
||||
|
||||
if (!componentProxies.get(uri)) {
|
||||
const proxy = createProxy(exports);
|
||||
componentProxies.set(uri, proxy);
|
||||
module.exports = proxy.get();
|
||||
} else {
|
||||
const proxy = componentProxies.get(uri);
|
||||
const instances = proxy.update(exports);
|
||||
instances.forEach(getForceUpdate(React));
|
||||
module.exports = proxy.get();
|
||||
}
|
||||
}
|
||||
return exports;
|
||||
};
|
||||
const watcher = devtools.require("devtools/client/shared/devtools-file-watcher");
|
||||
let onFileChanged = (_, relativePath, path) => {
|
||||
this.hotReloadFile(componentProxies, "resource://devtools/" + relativePath);
|
||||
};
|
||||
watcher.on("file-changed", onFileChanged);
|
||||
window.addEventListener("unload", () => {
|
||||
watcher.off("file-changed", onFileChanged);
|
||||
});
|
||||
}
|
||||
|
||||
const mainModule = loaders.Module(baseURI, joinURI(baseURI, "main.js"));
|
||||
this.loader = loaders.Loader(opts);
|
||||
this.require = loaders.Require(this.loader, mainModule);
|
||||
|
@ -228,20 +189,6 @@ BrowserLoaderBuilder.prototype = {
|
|||
? this.require(module)[property]
|
||||
: this.require(module || property);
|
||||
});
|
||||
},
|
||||
|
||||
hotReloadFile: function (componentProxies, fileURI) {
|
||||
if (fileURI.match(/\.js$/)) {
|
||||
// Test for React proxy components
|
||||
const proxy = componentProxies.get(fileURI);
|
||||
if (proxy) {
|
||||
// Remove the old module and re-require the new one; the require
|
||||
// hook in the loader will take care of the rest
|
||||
delete this.loader.modules[fileURI];
|
||||
clearCache();
|
||||
this.require(fileURI);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { Services } = require("resource://gre/modules/Services.jsm");
|
||||
const { getTheme } = require("devtools/client/shared/theme");
|
||||
|
||||
function iterStyleNodes(window, func) {
|
||||
for (let node of window.document.childNodes) {
|
||||
// Look for ProcessingInstruction nodes.
|
||||
if (node.nodeType === 7) {
|
||||
func(node);
|
||||
}
|
||||
}
|
||||
|
||||
const links = window.document.getElementsByTagNameNS(
|
||||
"http://www.w3.org/1999/xhtml", "link"
|
||||
);
|
||||
for (let node of links) {
|
||||
func(node);
|
||||
}
|
||||
}
|
||||
|
||||
function replaceCSS(window, fileURI) {
|
||||
const document = window.document;
|
||||
const randomKey = Math.random();
|
||||
Services.obs.notifyObservers(null, "startupcache-invalidate");
|
||||
|
||||
// Scan every CSS tag and reload ones that match the file we are
|
||||
// looking for.
|
||||
iterStyleNodes(window, node => {
|
||||
if (node.nodeType === 7) {
|
||||
// xml-stylesheet declaration
|
||||
if (node.data.includes(fileURI)) {
|
||||
const newNode = window.document.createProcessingInstruction(
|
||||
"xml-stylesheet",
|
||||
`href="${fileURI}?s=${randomKey}" type="text/css"`
|
||||
);
|
||||
document.insertBefore(newNode, node);
|
||||
document.removeChild(node);
|
||||
}
|
||||
} else if (node.href.includes(fileURI)) {
|
||||
const parentNode = node.parentNode;
|
||||
const newNode = window.document.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
"link"
|
||||
);
|
||||
newNode.rel = "stylesheet";
|
||||
newNode.type = "text/css";
|
||||
newNode.href = fileURI + "?s=" + randomKey;
|
||||
|
||||
parentNode.insertBefore(newNode, node);
|
||||
parentNode.removeChild(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _replaceResourceInSheet(sheet, filename, randomKey) {
|
||||
for (let i = 0; i < sheet.cssRules.length; i++) {
|
||||
const rule = sheet.cssRules[i];
|
||||
if (rule.type === rule.IMPORT_RULE) {
|
||||
_replaceResourceInSheet(rule.styleSheet, filename);
|
||||
} else if (rule.cssText.includes(filename)) {
|
||||
// Strip off any existing query strings. This might lose
|
||||
// updates for files if there are multiple resources
|
||||
// referenced in the same rule, but the chances of someone hot
|
||||
// reloading multiple resources in the same rule is very low.
|
||||
const text = rule.cssText.replace(/\?s=0.\d+/g, "");
|
||||
const newRule = (
|
||||
text.replace(filename, filename + "?s=" + randomKey)
|
||||
);
|
||||
|
||||
sheet.deleteRule(i);
|
||||
sheet.insertRule(newRule, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function replaceCSSResource(window, fileURI) {
|
||||
const document = window.document;
|
||||
const randomKey = Math.random();
|
||||
|
||||
// Only match the filename. False positives are much better than
|
||||
// missing updates, as all that would happen is we reload more
|
||||
// resources than we need. We do this because many resources only
|
||||
// use relative paths.
|
||||
const parts = fileURI.split("/");
|
||||
const file = parts[parts.length - 1];
|
||||
|
||||
// Scan every single rule in the entire page for any reference to
|
||||
// this resource, and re-insert the rule to force it to update.
|
||||
for (let sheet of document.styleSheets) {
|
||||
_replaceResourceInSheet(sheet, file, randomKey);
|
||||
}
|
||||
|
||||
for (let node of document.querySelectorAll("img,image")) {
|
||||
if (node.src.startsWith(fileURI)) {
|
||||
node.src = fileURI + "?s=" + randomKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function watchCSS(window) {
|
||||
if (Services.prefs.getBoolPref("devtools.loader.hotreload")) {
|
||||
const watcher = require("devtools/client/shared/devtools-file-watcher");
|
||||
|
||||
function onFileChanged(_, relativePath) {
|
||||
if (relativePath.match(/\.css$/)) {
|
||||
if (relativePath.startsWith("client/themes")) {
|
||||
let path = relativePath.replace(/^client\/themes\//, "");
|
||||
|
||||
// Special-case a few files that get imported from other CSS
|
||||
// files. We just manually hot reload the parent CSS file.
|
||||
if (path === "variables.css" || path === "toolbars.css" ||
|
||||
path === "common.css" || path === "splitters.css") {
|
||||
replaceCSS(window, "chrome://devtools/skin/" + getTheme() + "-theme.css");
|
||||
} else {
|
||||
replaceCSS(window, "chrome://devtools/skin/" + path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
replaceCSS(
|
||||
window,
|
||||
"chrome://devtools/content/" + relativePath.replace(/^client\//, "")
|
||||
);
|
||||
replaceCSS(window, "resource://devtools/" + relativePath);
|
||||
} else if (relativePath.match(/\.(svg|png)$/)) {
|
||||
relativePath = relativePath.replace(/^client\/themes\//, "");
|
||||
replaceCSSResource(window, "chrome://devtools/skin/" + relativePath);
|
||||
}
|
||||
}
|
||||
watcher.on("file-changed", onFileChanged);
|
||||
|
||||
window.addEventListener("unload", () => {
|
||||
watcher.off("file-changed", onFileChanged);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { watchCSS };
|
|
@ -1,78 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { Ci } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const EventEmitter = require("devtools/shared/old-event-emitter");
|
||||
|
||||
loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
|
||||
const HOTRELOAD_PREF = "devtools.loader.hotreload";
|
||||
|
||||
function resolveResourcePath(uri) {
|
||||
const handler = Services.io.getProtocolHandler("resource")
|
||||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
const resolved = handler.resolveURI(Services.io.newURI(uri));
|
||||
return resolved.replace(/file:\/\//, "");
|
||||
}
|
||||
|
||||
function findSourceDir(path) {
|
||||
if (path === "" || path === "/") {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
return OS.File.exists(
|
||||
OS.Path.join(path, "devtools/client/shared/file-watcher.js")
|
||||
).then(exists => {
|
||||
if (exists) {
|
||||
return path;
|
||||
}
|
||||
return findSourceDir(OS.Path.dirname(path));
|
||||
});
|
||||
}
|
||||
|
||||
let worker = null;
|
||||
const onPrefChange = function () {
|
||||
// We need to figure out a src dir to watch. These are the actual
|
||||
// files the user is working with, not the files in the obj dir. We
|
||||
// do this by walking up the filesystem and looking for the devtools
|
||||
// directories, and falling back to the raw path. This means none of
|
||||
// this will work for users who store their obj dirs outside of the
|
||||
// src dir.
|
||||
//
|
||||
// We take care not to mess with the `devtoolsPath` if that's what
|
||||
// we end up using, because it might be intentionally mapped to a
|
||||
// specific place on the filesystem for loading devtools externally.
|
||||
//
|
||||
// `devtoolsPath` is currently the devtools directory inside of the
|
||||
// obj dir, and we search for `devtools/client`, so go up 2 levels
|
||||
// to skip that devtools dir and start searching for the src dir.
|
||||
if (Services.prefs.getBoolPref(HOTRELOAD_PREF) && !worker) {
|
||||
const devtoolsPath = resolveResourcePath("resource://devtools")
|
||||
.replace(/\/$/, "");
|
||||
const searchPoint = OS.Path.dirname(OS.Path.dirname(devtoolsPath));
|
||||
findSourceDir(searchPoint)
|
||||
.then(srcPath => {
|
||||
const rootPath = srcPath ? OS.Path.join(srcPath, "devtools")
|
||||
: devtoolsPath;
|
||||
const watchPath = OS.Path.join(rootPath, "client");
|
||||
const { watchFiles } = require("devtools/client/shared/file-watcher");
|
||||
worker = watchFiles(watchPath, path => {
|
||||
let relativePath = path.replace(rootPath + "/", "");
|
||||
module.exports.emit("file-changed", relativePath, path);
|
||||
});
|
||||
});
|
||||
} else if (worker) {
|
||||
worker.terminate();
|
||||
worker = null;
|
||||
}
|
||||
};
|
||||
|
||||
Services.prefs.addObserver(HOTRELOAD_PREF, {
|
||||
observe: onPrefChange
|
||||
});
|
||||
onPrefChange();
|
||||
|
||||
EventEmitter.decorate(module.exports);
|
|
@ -1,81 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
/* eslint-env worker */
|
||||
/* global OS */
|
||||
importScripts("resource://gre/modules/osfile.jsm");
|
||||
|
||||
const modifiedTimes = new Map();
|
||||
|
||||
function gatherFiles(path, fileRegex) {
|
||||
let files = [];
|
||||
const iterator = new OS.File.DirectoryIterator(path);
|
||||
|
||||
try {
|
||||
for (let child of iterator) {
|
||||
// Don't descend into test directories. Saves us some time and
|
||||
// there's no reason to.
|
||||
if (child.isDir && !child.path.endsWith("/test")) {
|
||||
files = files.concat(gatherFiles(child.path, fileRegex));
|
||||
} else if (child.path.match(fileRegex)) {
|
||||
let info;
|
||||
try {
|
||||
info = OS.File.stat(child.path);
|
||||
} catch (e) {
|
||||
// Just ignore it.
|
||||
continue;
|
||||
}
|
||||
|
||||
files.push(child.path);
|
||||
modifiedTimes.set(child.path, info.lastModificationDate.getTime());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
function scanFiles(files, onChangedFile) {
|
||||
files.forEach(file => {
|
||||
let info;
|
||||
try {
|
||||
info = OS.File.stat(file);
|
||||
} catch (e) {
|
||||
// Just ignore it. It was probably deleted.
|
||||
return;
|
||||
}
|
||||
|
||||
const lastTime = modifiedTimes.get(file);
|
||||
|
||||
if (info.lastModificationDate.getTime() > lastTime) {
|
||||
modifiedTimes.set(file, info.lastModificationDate.getTime());
|
||||
onChangedFile(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onmessage = function (event) {
|
||||
const { path, fileRegex } = event.data;
|
||||
|
||||
const info = OS.File.stat(path);
|
||||
if (!info.isDir) {
|
||||
throw new Error("Watcher expects a directory as root path");
|
||||
}
|
||||
|
||||
// We get a list of all the files upfront, which means we don't
|
||||
// support adding new files. But you need to rebuild Firefox when
|
||||
// adding a new file anyway.
|
||||
const files = gatherFiles(path, fileRegex || /.*/);
|
||||
|
||||
// Every second, scan for file changes by stat-ing each of them and
|
||||
// comparing modification time.
|
||||
setInterval(() => {
|
||||
scanFiles(files, changedFile => {
|
||||
postMessage({ path: changedFile });
|
||||
});
|
||||
}, 1000);
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { ChromeWorker } = require("chrome");
|
||||
|
||||
function watchFiles(path, onFileChanged) {
|
||||
const watchWorker = new ChromeWorker(
|
||||
"resource://devtools/client/shared/file-watcher-worker.js"
|
||||
);
|
||||
|
||||
watchWorker.onmessage = event => {
|
||||
// We need to turn a local path back into a resource URI (or
|
||||
// chrome). This means that this system will only work when built
|
||||
// files are symlinked, so that these URIs actually read from
|
||||
// local sources. There might be a better way to do this.
|
||||
const { path: newPath } = event.data;
|
||||
onFileChanged(newPath);
|
||||
};
|
||||
|
||||
watchWorker.postMessage({
|
||||
path,
|
||||
fileRegex: /\.(js|css|svg|png)$/
|
||||
});
|
||||
return watchWorker;
|
||||
}
|
||||
exports.watchFiles = watchFiles;
|
|
@ -20,18 +20,14 @@ DevToolsModules(
|
|||
'autocomplete-popup.js',
|
||||
'browser-loader.js',
|
||||
'css-angle.js',
|
||||
'css-reload.js',
|
||||
'curl.js',
|
||||
'demangle.js',
|
||||
'developer-toolbar.js',
|
||||
'devices.js',
|
||||
'devtools-file-watcher.js',
|
||||
'DOMHelpers.jsm',
|
||||
'doorhanger.js',
|
||||
'enum.js',
|
||||
'file-saver.js',
|
||||
'file-watcher-worker.js',
|
||||
'file-watcher.js',
|
||||
'getjson.js',
|
||||
'inplace-editor.js',
|
||||
'Jsbeautify.jsm',
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const Services = require("Services");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const { watchCSS } = require("devtools/client/shared/css-reload");
|
||||
const { appendStyleSheet } = require("devtools/client/shared/stylesheet-utils");
|
||||
|
||||
let documentElement = document.documentElement;
|
||||
|
@ -154,6 +153,4 @@
|
|||
Services.prefs.removeObserver("devtools.theme", handlePrefChange);
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
watchCSS(window);
|
||||
})();
|
||||
|
|
|
@ -25,7 +25,6 @@ if CONFIG['DEBUG_JS_MODULES'] or CONFIG['MOZ_DEBUG']:
|
|||
modules += [
|
||||
'react-dom-server.js',
|
||||
'react-dom.js',
|
||||
'react-proxy.js',
|
||||
'react-redux.js',
|
||||
'react-virtualized.js',
|
||||
'react.js',
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -49,6 +49,8 @@
|
|||
<hbox id="storage-toolbar" class="devtools-toolbar">
|
||||
<button id="add-button"
|
||||
class="devtools-button add-button"></button>
|
||||
<button id="refresh-button"
|
||||
class="devtools-button refresh-button"></button>
|
||||
<spacer flex="1"/>
|
||||
<textbox id="storage-searchbox"
|
||||
class="devtools-filterinput"
|
||||
|
|
|
@ -169,6 +169,7 @@ function StorageUI(front, target, panelWin, toolbox) {
|
|||
this._tablePopup = this._panelDoc.getElementById("storage-table-popup");
|
||||
this._tablePopup.addEventListener("popupshowing", this.onTablePopupShowing);
|
||||
|
||||
this.onRefreshTable = this.onRefreshTable.bind(this);
|
||||
this.onAddItem = this.onAddItem.bind(this);
|
||||
this.onRemoveItem = this.onRemoveItem.bind(this);
|
||||
this.onRemoveAllFrom = this.onRemoveAllFrom.bind(this);
|
||||
|
@ -176,6 +177,9 @@ function StorageUI(front, target, panelWin, toolbox) {
|
|||
this.onRemoveAllSessionCookies = this.onRemoveAllSessionCookies.bind(this);
|
||||
this.onRemoveTreeItem = this.onRemoveTreeItem.bind(this);
|
||||
|
||||
this._refreshButton = this._panelDoc.getElementById("refresh-button");
|
||||
this._refreshButton.addEventListener("command", this.onRefreshTable);
|
||||
|
||||
this._addButton = this._panelDoc.getElementById("add-button");
|
||||
this._addButton.addEventListener("command", this.onAddItem);
|
||||
|
||||
|
@ -242,6 +246,7 @@ StorageUI.prototype = {
|
|||
this.sidebarToggleBtn = null;
|
||||
|
||||
this._treePopup.removeEventListener("popupshowing", this.onTreePopupShowing);
|
||||
this._refreshButton.removeEventListener("command", this.onRefreshTable);
|
||||
this._addButton.removeEventListener("command", this.onAddItem);
|
||||
this._tablePopupAddItem.removeEventListener("command", this.onAddItem);
|
||||
this._treePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
|
||||
|
@ -1162,6 +1167,13 @@ StorageUI.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles refreshing the selected storage
|
||||
*/
|
||||
onRefreshTable: function (event) {
|
||||
this.onHostSelect(event, this.tree.selectedItem);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles adding an item from the storage
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" width="14" height="14">
|
||||
<path d="M12,7H6l2.4-2.4C7.6,4,6.6,3.8,5.5,4.1C4.3,4.5,3.3,5.5,3,6.8 C2.6,9,4.3,11,6.5,11c1,0,2-0.5,2.6-1.2l1.7,1c-1.3,1.6-3.3,2.5-5.6,2c-2-0.5-3.6-2.1-4-4.1C0.4,5.1,3.1,2,6.5,2 c1.3,0,2.4,0.4,3.3,1.2L12,1V7z"/>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.917 7C13.44 4.162 10.973 2 8 2 4.686 2 2 4.686 2 8s2.686 6 6 6c2.22 0 4.16-1.207 5.197-3H12c-.912 1.214-2.364 2-4 2-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h1.017z"/>
|
||||
<path d="M14 1L8 7h6V1zm-1 1L9 6h4V2z" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 517 B После Ширина: | Высота: | Размер: 565 B |
|
@ -37,6 +37,11 @@
|
|||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
#storage-toolbar .refresh-button::before {
|
||||
background-image: url("chrome://devtools/skin/images/reload.svg");
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
#storage-toolbar .devtools-button {
|
||||
min-width: 0;
|
||||
}
|
||||
|
|
|
@ -854,14 +854,43 @@ a.learn-more-link.webconsole-learn-more-link {
|
|||
background-position: -36px -36px;
|
||||
}
|
||||
|
||||
/* Network Messages */
|
||||
|
||||
.message.network .method {
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.network.message .network-info {
|
||||
display: none;
|
||||
margin-top: 8px;
|
||||
border: solid 1px var(--theme-splitter-color);
|
||||
}
|
||||
|
||||
.network.message.open .network-info {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.network.message .network-info .panels {
|
||||
max-height: 250px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
/* Hide 'Edit And Resend' button since the feature isn't
|
||||
supported in the Console panel. */
|
||||
.network.message #headers-panel .edit-and-resend-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.network.message #response-panel .treeTable {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.network .message-flex-body > .message-body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Output Wrapper */
|
||||
|
||||
.webconsole-output-wrapper .message .indent {
|
||||
display: inline-block;
|
||||
border-inline-end: solid 1px var(--theme-splitter-color);
|
||||
|
|
|
@ -15,6 +15,7 @@ const { batchActions } = require("devtools/client/shared/redux/middleware/deboun
|
|||
const {
|
||||
MESSAGE_ADD,
|
||||
NETWORK_MESSAGE_UPDATE,
|
||||
NETWORK_UPDATE_REQUEST,
|
||||
MESSAGES_CLEAR,
|
||||
MESSAGE_OPEN,
|
||||
MESSAGE_CLOSE,
|
||||
|
@ -94,7 +95,7 @@ function messageTableDataReceive(id, data) {
|
|||
};
|
||||
}
|
||||
|
||||
function networkMessageUpdate(packet, idGenerator = null) {
|
||||
function networkMessageUpdate(packet, idGenerator = null, response) {
|
||||
if (idGenerator == null) {
|
||||
idGenerator = defaultIdGenerator;
|
||||
}
|
||||
|
@ -104,6 +105,15 @@ function networkMessageUpdate(packet, idGenerator = null) {
|
|||
return {
|
||||
type: NETWORK_MESSAGE_UPDATE,
|
||||
message,
|
||||
response,
|
||||
};
|
||||
}
|
||||
|
||||
function networkUpdateRequest(id, data) {
|
||||
return {
|
||||
type: NETWORK_UPDATE_REQUEST,
|
||||
id,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -179,6 +189,7 @@ module.exports = {
|
|||
messageClose,
|
||||
messageTableDataGet,
|
||||
networkMessageUpdate,
|
||||
networkUpdateRequest,
|
||||
messageObjectPropertiesLoad,
|
||||
messageObjectEntriesLoad,
|
||||
// for test purpose only.
|
||||
|
|
|
@ -13,6 +13,7 @@ const {
|
|||
FILTER_BAR_TOGGLE,
|
||||
PREFS,
|
||||
TIMESTAMPS_TOGGLE,
|
||||
SELECT_NETWORK_MESSAGE_TAB,
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
|
||||
function filterBarToggle(show) {
|
||||
|
@ -32,7 +33,15 @@ function timestampsToggle(visible) {
|
|||
};
|
||||
}
|
||||
|
||||
function selectNetworkMessageTab(id) {
|
||||
return {
|
||||
type: SELECT_NETWORK_MESSAGE_TAB,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
filterBarToggle,
|
||||
timestampsToggle,
|
||||
selectNetworkMessageTab,
|
||||
};
|
||||
|
|
|
@ -46,6 +46,7 @@ const ConsoleOutput = createClass({
|
|||
messagesRepeat: PropTypes.object.isRequired,
|
||||
networkMessagesUpdate: PropTypes.object.isRequired,
|
||||
visibleMessages: PropTypes.array.isRequired,
|
||||
networkMessageActiveTabId: PropTypes.string.isRequired,
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -67,7 +68,7 @@ const ConsoleOutput = createClass({
|
|||
const visibleMessagesDelta =
|
||||
nextProps.visibleMessages.length - this.props.visibleMessages.length;
|
||||
const messagesDelta =
|
||||
nextProps.messages.length - this.props.messages.length;
|
||||
nextProps.messages.size - this.props.messages.size;
|
||||
|
||||
// We need to scroll to the bottom if:
|
||||
// - the number of messages displayed changed
|
||||
|
@ -102,6 +103,7 @@ const ConsoleOutput = createClass({
|
|||
messagesObjectEntries,
|
||||
messagesRepeat,
|
||||
networkMessagesUpdate,
|
||||
networkMessageActiveTabId,
|
||||
serviceContainer,
|
||||
timestampsVisible,
|
||||
} = this.props;
|
||||
|
@ -116,6 +118,7 @@ const ConsoleOutput = createClass({
|
|||
timestampsVisible,
|
||||
repeat: messagesRepeat[messageId],
|
||||
networkMessageUpdate: networkMessagesUpdate[messageId],
|
||||
networkMessageActiveTabId,
|
||||
getMessage: () => messages.get(messageId),
|
||||
loadedObjectProperties: messagesObjectProperties.get(messageId),
|
||||
loadedObjectEntries: messagesObjectEntries.get(messageId),
|
||||
|
@ -156,6 +159,7 @@ function mapStateToProps(state, props) {
|
|||
messagesRepeat: getAllRepeatById(state),
|
||||
networkMessagesUpdate: getAllNetworkMessagesUpdateById(state),
|
||||
timestampsVisible: state.ui.timestampsVisible,
|
||||
networkMessageActiveTabId: state.ui.networkMessageActiveTabId,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@ const {
|
|||
PropTypes
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const Message = createFactory(require("devtools/client/webconsole/new-console-output/components/message"));
|
||||
const actions = require("devtools/client/webconsole/new-console-output/actions/index");
|
||||
const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
|
||||
const TabboxPanel = createFactory(require("devtools/client/netmonitor/src/components/tabbox-panel"));
|
||||
|
||||
NetworkEventMessage.displayName = "NetworkEventMessage";
|
||||
|
||||
|
@ -26,14 +28,30 @@ NetworkEventMessage.propTypes = {
|
|||
networkMessageUpdate: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
* This component is responsible for rendering network messages
|
||||
* in the Console panel.
|
||||
*
|
||||
* Network logs are expandable and the user can inspect it inline
|
||||
* within the Console panel (no need to switch to the Network panel).
|
||||
*
|
||||
* HTTP details are rendered using `TabboxPanel` component used to
|
||||
* render contents of the side bar in the Network panel.
|
||||
*
|
||||
* All HTTP details data are fetched from the backend on-demand
|
||||
* when the user is expanding network log for the first time.
|
||||
*/
|
||||
function NetworkEventMessage({
|
||||
message = {},
|
||||
serviceContainer,
|
||||
timestampsVisible,
|
||||
networkMessageUpdate = {},
|
||||
networkMessageActiveTabId,
|
||||
dispatch,
|
||||
open,
|
||||
}) {
|
||||
const {
|
||||
actor,
|
||||
id,
|
||||
indent,
|
||||
source,
|
||||
type,
|
||||
|
@ -61,27 +79,50 @@ function NetworkEventMessage({
|
|||
statusInfo = `[${httpVersion} ${status} ${statusText} ${totalTime}ms]`;
|
||||
}
|
||||
|
||||
const openNetworkMonitor = serviceContainer.openNetworkPanel
|
||||
? () => serviceContainer.openNetworkPanel(actor)
|
||||
: null;
|
||||
const toggle = () => {
|
||||
if (open) {
|
||||
dispatch(actions.messageClose(id));
|
||||
} else {
|
||||
dispatch(actions.messageOpen(id));
|
||||
}
|
||||
};
|
||||
|
||||
// Message body components.
|
||||
const method = dom.span({className: "method" }, request.method);
|
||||
const xhr = isXHR
|
||||
? dom.span({ className: "xhr" }, l10n.getStr("webConsoleXhrIndicator"))
|
||||
: null;
|
||||
const url = dom.a({ className: "url", title: request.url, onClick: openNetworkMonitor },
|
||||
const url = dom.a({ className: "url", title: request.url, onClick: toggle },
|
||||
request.url.replace(/\?.+/, ""));
|
||||
const statusBody = statusInfo
|
||||
? dom.a({ className: "status", onClick: openNetworkMonitor }, statusInfo)
|
||||
? dom.a({ className: "status", onClick: toggle }, statusInfo)
|
||||
: null;
|
||||
|
||||
const messageBody = [method, xhr, url, statusBody];
|
||||
|
||||
// Only render the attachment if the network-event is
|
||||
// actually opened (performance optimization).
|
||||
const attachment = open && dom.div({className: "network-info devtools-monospace"},
|
||||
TabboxPanel({
|
||||
activeTabId: networkMessageActiveTabId,
|
||||
request: networkMessageUpdate,
|
||||
sourceMapService: serviceContainer.sourceMapService,
|
||||
selectTab: (tabId) => {
|
||||
dispatch(actions.selectNetworkMessageTab(tabId));
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
return Message({
|
||||
dispatch,
|
||||
messageId: id,
|
||||
source,
|
||||
type,
|
||||
level,
|
||||
indent,
|
||||
collapsible: true,
|
||||
open,
|
||||
attachment,
|
||||
topLevelClasses,
|
||||
timeStamp,
|
||||
messageBody,
|
||||
|
|
|
@ -89,10 +89,11 @@ const Message = createClass({
|
|||
},
|
||||
|
||||
onContextMenu(e) {
|
||||
let { serviceContainer, source, request } = this.props;
|
||||
let { serviceContainer, source, request, messageId } = this.props;
|
||||
let messageInfo = {
|
||||
source,
|
||||
request,
|
||||
messageId,
|
||||
};
|
||||
serviceContainer.openContextMenu(e, messageInfo);
|
||||
e.stopPropagation();
|
||||
|
|
|
@ -12,6 +12,7 @@ const actionTypes = {
|
|||
MESSAGE_OPEN: "MESSAGE_OPEN",
|
||||
MESSAGE_CLOSE: "MESSAGE_CLOSE",
|
||||
NETWORK_MESSAGE_UPDATE: "NETWORK_MESSAGE_UPDATE",
|
||||
NETWORK_UPDATE_REQUEST: "NETWORK_UPDATE_REQUEST",
|
||||
MESSAGE_TABLE_RECEIVE: "MESSAGE_TABLE_RECEIVE",
|
||||
MESSAGE_OBJECT_PROPERTIES_RECEIVE: "MESSAGE_OBJECT_PROPERTIES_RECEIVE",
|
||||
MESSAGE_OBJECT_ENTRIES_RECEIVE: "MESSAGE_OBJECT_ENTRIES_RECEIVE",
|
||||
|
@ -22,6 +23,7 @@ const actionTypes = {
|
|||
FILTERS_CLEAR: "FILTERS_CLEAR",
|
||||
DEFAULT_FILTERS_RESET: "DEFAULT_FILTERS_RESET",
|
||||
FILTER_BAR_TOGGLE: "FILTER_BAR_TOGGLE",
|
||||
SELECT_NETWORK_MESSAGE_TAB: "SELECT_NETWORK_MESSAGE_TAB",
|
||||
};
|
||||
|
||||
const prefs = {
|
||||
|
|
|
@ -52,6 +52,11 @@ NewConsoleOutputWrapper.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Do not focus if an input field was clicked
|
||||
if (target.closest("input")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not focus if something other than the output region was clicked
|
||||
if (!target.closest(".webconsole-output")) {
|
||||
return;
|
||||
|
@ -75,7 +80,16 @@ NewConsoleOutputWrapper.prototype = {
|
|||
}]));
|
||||
},
|
||||
hudProxyClient: this.jsterm.hud.proxy.client,
|
||||
openContextMenu: (e, message) => {
|
||||
openLink: url => this.jsterm.hud.owner.openLink(url),
|
||||
createElement: nodename => {
|
||||
return this.document.createElementNS("http://www.w3.org/1999/xhtml", nodename);
|
||||
},
|
||||
};
|
||||
|
||||
// Set `openContextMenu` this way so, `serviceContainer` variable
|
||||
// is available in the current scope and we can pass it into
|
||||
// `createContextMenu` method.
|
||||
serviceContainer.openContextMenu = (e, message) => {
|
||||
let { screenX, screenY, target } = e;
|
||||
|
||||
let messageEl = target.closest(".message");
|
||||
|
@ -86,18 +100,13 @@ NewConsoleOutputWrapper.prototype = {
|
|||
let actor = actorEl ? actorEl.dataset.linkActorId : null;
|
||||
|
||||
let menu = createContextMenu(this.jsterm, this.parentNode,
|
||||
{ actor, clipboardText, message });
|
||||
{ actor, clipboardText, message, serviceContainer });
|
||||
|
||||
// Emit the "menu-open" event for testing.
|
||||
menu.once("open", () => this.emit("menu-open"));
|
||||
menu.popup(screenX, screenY, this.toolbox);
|
||||
|
||||
return menu;
|
||||
},
|
||||
openLink: url => this.jsterm.hud.owner.openLink(url),
|
||||
createElement: nodename => {
|
||||
return this.document.createElementNS("http://www.w3.org/1999/xhtml", nodename);
|
||||
},
|
||||
};
|
||||
|
||||
if (this.toolbox) {
|
||||
|
@ -219,6 +228,19 @@ NewConsoleOutputWrapper.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
dispatchRequestUpdate: function (id, data) {
|
||||
batchedMessageAdd(actions.networkUpdateRequest(id, data));
|
||||
|
||||
// Fire an event indicating that all data fetched from
|
||||
// the backend has been received. This is based on
|
||||
// 'FirefoxDataProvider.isQueuePayloadReady', see more
|
||||
// comments in that method.
|
||||
// (netmonitor/src/connector/firefox-data-provider).
|
||||
// This event might be utilized in tests to find the right
|
||||
// time when to finish.
|
||||
this.jsterm.hud.emit("network-request-payload-ready", {id, data});
|
||||
},
|
||||
|
||||
// Should be used for test purpose only.
|
||||
getStore: function () {
|
||||
return store;
|
||||
|
|
|
@ -22,6 +22,10 @@ const {
|
|||
const { getGripPreviewItems } = require("devtools/client/shared/components/reps/reps");
|
||||
const { getSourceNames } = require("devtools/client/shared/source-utils");
|
||||
|
||||
const {
|
||||
UPDATE_PROPS
|
||||
} = require("devtools/client/netmonitor/src/constants");
|
||||
|
||||
const MessageState = Immutable.Record({
|
||||
// List of all the messages added to the console.
|
||||
messagesById: Immutable.OrderedMap(),
|
||||
|
@ -166,8 +170,10 @@ function messages(state = new MessageState(), action, filtersState, prefsState)
|
|||
return state.withMutations(function (record) {
|
||||
record.set("messagesUiById", messagesUiById.push(action.id));
|
||||
|
||||
let currMessage = messagesById.get(action.id);
|
||||
|
||||
// If the message is a group
|
||||
if (isGroupType(messagesById.get(action.id).type)) {
|
||||
if (isGroupType(currMessage.type)) {
|
||||
// We want to make its children visible
|
||||
const messagesToShow = [...messagesById].reduce((res, [id, message]) => {
|
||||
if (
|
||||
|
@ -195,6 +201,21 @@ function messages(state = new MessageState(), action, filtersState, prefsState)
|
|||
...visibleMessages.slice(insertIndex),
|
||||
]);
|
||||
}
|
||||
|
||||
// If the current message is a network event, mark it as opened-once,
|
||||
// so HTTP details are not fetched again the next time the user
|
||||
// opens the log.
|
||||
if (currMessage.source == "network") {
|
||||
record.set("messagesById",
|
||||
messagesById.set(
|
||||
action.id, Object.assign({},
|
||||
currMessage, {
|
||||
openedOnce: true
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
case constants.MESSAGE_CLOSE:
|
||||
|
@ -250,6 +271,44 @@ function messages(state = new MessageState(), action, filtersState, prefsState)
|
|||
})
|
||||
);
|
||||
|
||||
case constants.NETWORK_UPDATE_REQUEST: {
|
||||
let request = networkMessagesUpdateById[action.id];
|
||||
if (!request) {
|
||||
return state;
|
||||
}
|
||||
|
||||
let values = {};
|
||||
for (let [key, value] of Object.entries(action.data)) {
|
||||
if (UPDATE_PROPS.includes(key)) {
|
||||
values[key] = value;
|
||||
|
||||
switch (key) {
|
||||
case "securityInfo":
|
||||
values.securityState = value.state;
|
||||
break;
|
||||
case "totalTime":
|
||||
values.totalTime = request.totalTime;
|
||||
break;
|
||||
case "requestPostData":
|
||||
values.requestHeadersFromUploadStream = {
|
||||
headers: [],
|
||||
headersSize: 0,
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let newState = state.set(
|
||||
"networkMessagesUpdateById",
|
||||
Object.assign({}, networkMessagesUpdateById, {
|
||||
[action.id]: Object.assign({}, request, values)
|
||||
})
|
||||
);
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
case constants.REMOVED_ACTORS_CLEAR:
|
||||
return state.set("removedActors", []);
|
||||
|
||||
|
|
|
@ -7,14 +7,20 @@
|
|||
|
||||
const {
|
||||
FILTER_BAR_TOGGLE,
|
||||
TIMESTAMPS_TOGGLE
|
||||
TIMESTAMPS_TOGGLE,
|
||||
SELECT_NETWORK_MESSAGE_TAB,
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
const Immutable = require("devtools/client/shared/vendor/immutable");
|
||||
|
||||
const {
|
||||
PANELS,
|
||||
} = require("devtools/client/netmonitor/src/constants");
|
||||
|
||||
const UiState = Immutable.Record({
|
||||
filterBarVisible: false,
|
||||
filteredMessageVisible: false,
|
||||
timestampsVisible: true,
|
||||
networkMessageActiveTabId: PANELS.HEADERS,
|
||||
});
|
||||
|
||||
function ui(state = new UiState(), action) {
|
||||
|
@ -23,6 +29,8 @@ function ui(state = new UiState(), action) {
|
|||
return state.set("filterBarVisible", !state.filterBarVisible);
|
||||
case TIMESTAMPS_TOGGLE:
|
||||
return state.set("timestampsVisible", action.visible);
|
||||
case SELECT_NETWORK_MESSAGE_TAB:
|
||||
return state.set("networkMessageActiveTabId", action.id);
|
||||
}
|
||||
|
||||
return state;
|
||||
|
|
|
@ -17,13 +17,24 @@ const {
|
|||
} = require("devtools/client/shared/redux/middleware/debounce");
|
||||
const {
|
||||
MESSAGE_ADD,
|
||||
MESSAGE_OPEN,
|
||||
MESSAGES_CLEAR,
|
||||
REMOVED_ACTORS_CLEAR,
|
||||
NETWORK_MESSAGE_UPDATE,
|
||||
PREFS,
|
||||
} = require("devtools/client/webconsole/new-console-output/constants");
|
||||
const { reducers } = require("./reducers/index");
|
||||
const Services = require("Services");
|
||||
const {
|
||||
getMessage,
|
||||
getAllMessagesUiById,
|
||||
} = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const DataProvider = require("devtools/client/netmonitor/src/connector/firefox-data-provider");
|
||||
|
||||
/**
|
||||
* Create and configure store for the Console panel. This is the place
|
||||
* where various enhancers and middleware can be registered.
|
||||
*/
|
||||
function configureStore(hud, options = {}) {
|
||||
const logLimit = options.logLimit
|
||||
|| Math.max(Services.prefs.getIntPref("devtools.hud.loglimit"), 1);
|
||||
|
@ -42,13 +53,19 @@ function configureStore(hud, options = {}) {
|
|||
}),
|
||||
ui: new UiState({
|
||||
filterBarVisible: Services.prefs.getBoolPref(PREFS.UI.FILTER_BAR),
|
||||
networkMessageActiveTabId: "headers",
|
||||
})
|
||||
};
|
||||
|
||||
return createStore(
|
||||
createRootReducer(),
|
||||
initialState,
|
||||
compose(applyMiddleware(thunk), enableActorReleaser(hud), enableBatching())
|
||||
compose(
|
||||
applyMiddleware(thunk),
|
||||
enableActorReleaser(hud),
|
||||
enableBatching(),
|
||||
enableNetProvider(hud)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -125,6 +142,69 @@ function enableActorReleaser(hud) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This enhancer is responsible for fetching HTTP details data
|
||||
* collected by the backend. The fetch happens on-demand
|
||||
* when the user expands network log in order to inspect it.
|
||||
*
|
||||
* This way we don't slow down the Console logging by fetching.
|
||||
* unnecessary data over RDP.
|
||||
*/
|
||||
function enableNetProvider(hud) {
|
||||
let dataProvider;
|
||||
return next => (reducer, initialState, enhancer) => {
|
||||
function netProviderEnhancer(state, action) {
|
||||
let proxy = hud ? hud.proxy : null;
|
||||
if (!proxy) {
|
||||
return reducer(state, action);
|
||||
}
|
||||
|
||||
let actions = {
|
||||
updateRequest: (id, data, batch) => {
|
||||
proxy.dispatchRequestUpdate(id, data);
|
||||
}
|
||||
};
|
||||
|
||||
// Data provider implements async logic for fetching
|
||||
// data from the backend. It's created the first
|
||||
// time it's needed.
|
||||
if (!dataProvider) {
|
||||
dataProvider = new DataProvider({
|
||||
actions,
|
||||
webConsoleClient: proxy.webConsoleClient
|
||||
});
|
||||
}
|
||||
|
||||
let type = action.type;
|
||||
|
||||
// If network message has been opened, fetch all
|
||||
// HTTP details from the backend.
|
||||
if (type == MESSAGE_OPEN) {
|
||||
let message = getMessage(state, action.id);
|
||||
if (!message.openedOnce && message.source == "network") {
|
||||
message.updates.forEach(updateType => {
|
||||
dataProvider.onNetworkEventUpdate(null, {
|
||||
packet: { updateType: updateType },
|
||||
networkInfo: message,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Process all incoming HTTP details packets.
|
||||
if (type == NETWORK_MESSAGE_UPDATE) {
|
||||
let open = getAllMessagesUiById(state).includes(action.id);
|
||||
if (open) {
|
||||
dataProvider.onNetworkEventUpdate(null, action.response);
|
||||
}
|
||||
}
|
||||
|
||||
return reducer(state, action);
|
||||
}
|
||||
|
||||
return next(netProviderEnhancer, initialState, enhancer);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Helper function for releasing backend actors.
|
||||
*/
|
||||
|
|
|
@ -109,4 +109,16 @@ describe("NetworkEventMessage component:", () => {
|
|||
expect(wrapper.find(".message-body .status").text()).toMatch(EXPECTED_STATUS);
|
||||
});
|
||||
});
|
||||
|
||||
describe("is expandable", () => {
|
||||
it("renders as expected", () => {
|
||||
const message = stubPreparedMessages.get("XHR POST request");
|
||||
const wrapper = render(NetworkEventMessage({
|
||||
message,
|
||||
serviceContainer,
|
||||
}));
|
||||
|
||||
expect(wrapper.find(".message .theme-twisty")).toExist();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,7 +27,48 @@ stubPreparedMessages.set("GET request", new NetworkEventMessage({
|
|||
"type": "log",
|
||||
"groupId": null,
|
||||
"timeStamp": 1487022056850,
|
||||
"indent": 0
|
||||
"indent": 0,
|
||||
"updates": [],
|
||||
"openedOnce": false,
|
||||
"securityState": null,
|
||||
"securityInfo": null,
|
||||
"requestHeadersFromUploadStream": null,
|
||||
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"urlDetails": {
|
||||
"baseNameWithQuery": "inexistent.html",
|
||||
"host": "example.com",
|
||||
"scheme": "http",
|
||||
"unicodeUrl": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"isLocal": null
|
||||
},
|
||||
"method": "GET",
|
||||
"cause": {
|
||||
"type": "img",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-network-event.html",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-network-event.html",
|
||||
"lineNumber": 3,
|
||||
"columnNumber": 1,
|
||||
"functionName": "triggerPacket",
|
||||
"asyncCause": null
|
||||
},
|
||||
{
|
||||
"filename": "resource://testing-common/content-task.js line 52 > eval",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 9,
|
||||
"functionName": null,
|
||||
"asyncCause": null
|
||||
},
|
||||
{
|
||||
"filename": "resource://testing-common/content-task.js",
|
||||
"lineNumber": 53,
|
||||
"columnNumber": 20,
|
||||
"functionName": null,
|
||||
"asyncCause": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("GET request update", new NetworkEventMessage({
|
||||
|
@ -56,7 +97,20 @@ stubPreparedMessages.set("GET request update", new NetworkEventMessage({
|
|||
"type": "log",
|
||||
"groupId": null,
|
||||
"totalTime": 16,
|
||||
"indent": 0
|
||||
"indent": 0,
|
||||
"openedOnce": false,
|
||||
"securityState": null,
|
||||
"securityInfo": null,
|
||||
"requestHeadersFromUploadStream": null,
|
||||
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"urlDetails": {
|
||||
"baseNameWithQuery": "inexistent.html",
|
||||
"host": "example.com",
|
||||
"scheme": "http",
|
||||
"unicodeUrl": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"isLocal": null
|
||||
},
|
||||
"method": "GET"
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("XHR GET request", new NetworkEventMessage({
|
||||
|
@ -73,7 +127,48 @@ stubPreparedMessages.set("XHR GET request", new NetworkEventMessage({
|
|||
"type": "log",
|
||||
"groupId": null,
|
||||
"timeStamp": 1487022057746,
|
||||
"indent": 0
|
||||
"indent": 0,
|
||||
"updates": [],
|
||||
"openedOnce": false,
|
||||
"securityState": null,
|
||||
"securityInfo": null,
|
||||
"requestHeadersFromUploadStream": null,
|
||||
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"urlDetails": {
|
||||
"baseNameWithQuery": "inexistent.html",
|
||||
"host": "example.com",
|
||||
"scheme": "http",
|
||||
"unicodeUrl": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"isLocal": null
|
||||
},
|
||||
"method": "GET",
|
||||
"cause": {
|
||||
"type": "xhr",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-network-event.html",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-network-event.html",
|
||||
"lineNumber": 4,
|
||||
"columnNumber": 1,
|
||||
"functionName": "triggerPacket",
|
||||
"asyncCause": null
|
||||
},
|
||||
{
|
||||
"filename": "resource://testing-common/content-task.js line 52 > eval",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 9,
|
||||
"functionName": null,
|
||||
"asyncCause": null
|
||||
},
|
||||
{
|
||||
"filename": "resource://testing-common/content-task.js",
|
||||
"lineNumber": 53,
|
||||
"columnNumber": 20,
|
||||
"functionName": null,
|
||||
"asyncCause": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("XHR GET request update", new NetworkEventMessage({
|
||||
|
@ -102,7 +197,20 @@ stubPreparedMessages.set("XHR GET request update", new NetworkEventMessage({
|
|||
"type": "log",
|
||||
"groupId": null,
|
||||
"totalTime": 16,
|
||||
"indent": 0
|
||||
"indent": 0,
|
||||
"openedOnce": false,
|
||||
"securityState": null,
|
||||
"securityInfo": null,
|
||||
"requestHeadersFromUploadStream": null,
|
||||
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"urlDetails": {
|
||||
"baseNameWithQuery": "inexistent.html",
|
||||
"host": "example.com",
|
||||
"scheme": "http",
|
||||
"unicodeUrl": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"isLocal": null
|
||||
},
|
||||
"method": "GET"
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("XHR POST request", new NetworkEventMessage({
|
||||
|
@ -119,7 +227,48 @@ stubPreparedMessages.set("XHR POST request", new NetworkEventMessage({
|
|||
"type": "log",
|
||||
"groupId": null,
|
||||
"timeStamp": 1487022058414,
|
||||
"indent": 0
|
||||
"indent": 0,
|
||||
"updates": [],
|
||||
"openedOnce": false,
|
||||
"securityState": null,
|
||||
"securityInfo": null,
|
||||
"requestHeadersFromUploadStream": null,
|
||||
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"urlDetails": {
|
||||
"baseNameWithQuery": "inexistent.html",
|
||||
"host": "example.com",
|
||||
"scheme": "http",
|
||||
"unicodeUrl": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"isLocal": null
|
||||
},
|
||||
"method": "POST",
|
||||
"cause": {
|
||||
"type": "xhr",
|
||||
"loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-network-event.html",
|
||||
"stacktrace": [
|
||||
{
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-network-event.html",
|
||||
"lineNumber": 4,
|
||||
"columnNumber": 1,
|
||||
"functionName": "triggerPacket",
|
||||
"asyncCause": null
|
||||
},
|
||||
{
|
||||
"filename": "resource://testing-common/content-task.js line 52 > eval",
|
||||
"lineNumber": 8,
|
||||
"columnNumber": 9,
|
||||
"functionName": null,
|
||||
"asyncCause": null
|
||||
},
|
||||
{
|
||||
"filename": "resource://testing-common/content-task.js",
|
||||
"lineNumber": 53,
|
||||
"columnNumber": 20,
|
||||
"functionName": null,
|
||||
"asyncCause": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}));
|
||||
|
||||
stubPreparedMessages.set("XHR POST request update", new NetworkEventMessage({
|
||||
|
@ -148,7 +297,20 @@ stubPreparedMessages.set("XHR POST request update", new NetworkEventMessage({
|
|||
"type": "log",
|
||||
"groupId": null,
|
||||
"totalTime": 10,
|
||||
"indent": 0
|
||||
"indent": 0,
|
||||
"openedOnce": false,
|
||||
"securityState": null,
|
||||
"securityInfo": null,
|
||||
"requestHeadersFromUploadStream": null,
|
||||
"url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"urlDetails": {
|
||||
"baseNameWithQuery": "inexistent.html",
|
||||
"host": "example.com",
|
||||
"scheme": "http",
|
||||
"unicodeUrl": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/inexistent.html",
|
||||
"isLocal": null
|
||||
},
|
||||
"method": "POST"
|
||||
}));
|
||||
|
||||
stubPackets.set("GET request", {
|
||||
|
|
|
@ -48,7 +48,8 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
|||
[browser_webconsole_location_scratchpad_link.js]
|
||||
[browser_webconsole_location_styleeditor_link.js]
|
||||
[browser_webconsole_logErrorInPage.js]
|
||||
[browser_webconsole_network_messages_click.js]
|
||||
[browser_webconsole_network_messages_openinnet.js]
|
||||
[browser_webconsole_network_messages_expand.js]
|
||||
[browser_webconsole_nodes_highlight.js]
|
||||
[browser_webconsole_nodes_select.js]
|
||||
[browser_webconsole_object_inspector_entries.js]
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,Test that clicking on a network message " +
|
||||
"in the console toggles the HTTP inspection.";
|
||||
|
||||
const TEST_FILE = "test-network-request.html";
|
||||
const TEST_PATH = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/mochitest/";
|
||||
|
||||
const NET_PREF = "devtools.webconsole.filter.net";
|
||||
const XHR_PREF = "devtools.webconsole.filter.netxhr";
|
||||
|
||||
Services.prefs.setBoolPref(NET_PREF, true);
|
||||
Services.prefs.setBoolPref(XHR_PREF, true);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(NET_PREF);
|
||||
Services.prefs.clearUserPref(XHR_PREF);
|
||||
});
|
||||
|
||||
add_task(async function task() {
|
||||
const hud = await openNewTabAndConsole(TEST_URI);
|
||||
|
||||
const currentTab = gBrowser.selectedTab;
|
||||
let target = TargetFactory.forTab(currentTab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
|
||||
const documentUrl = TEST_PATH + TEST_FILE;
|
||||
await loadDocument(documentUrl);
|
||||
info("Document loaded.");
|
||||
|
||||
await testNetworkMessage(hud, documentUrl);
|
||||
await waitForNetworkUpdates(toolbox);
|
||||
});
|
||||
|
||||
async function testNetworkMessage(hud, url) {
|
||||
let messageNode = await waitFor(() => findMessage(hud, url));
|
||||
let urlNode = messageNode.querySelector(".url");
|
||||
info("Network message found.");
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, urlNode);
|
||||
|
||||
let headersTab = messageNode.querySelector("#headers-tab");
|
||||
let cookiesTab = messageNode.querySelector("#cookies-tab");
|
||||
let paramsTab = messageNode.querySelector("#params-tab");
|
||||
let responseTab = messageNode.querySelector("#response-tab");
|
||||
let timingsTab = messageNode.querySelector("#timings-tab");
|
||||
|
||||
ok(headersTab, "Headers tab is available");
|
||||
ok(cookiesTab, "Cookies tab is available");
|
||||
ok(paramsTab, "Params tab is available");
|
||||
ok(responseTab, "Response tab is available");
|
||||
ok(timingsTab, "Timings tab is available");
|
||||
}
|
||||
|
||||
async function waitForNetworkUpdates(toolbox) {
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let hud = panel.hud;
|
||||
let ui = hud.ui;
|
||||
|
||||
return new Promise(resolve => {
|
||||
ui.jsterm.hud.on("network-request-payload-ready", () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,Test that clicking on a network message " +
|
||||
"in the console opens the netmonitor panel.";
|
||||
const TEST_URI = "data:text/html;charset=utf8,Test that 'Open in Network Panel' " +
|
||||
"context menu item opens the selected request in netmonitor panel.";
|
||||
|
||||
const TEST_FILE = "test-network-request.html";
|
||||
const JSON_TEST_URL = "test-network-request.html";
|
||||
|
@ -12,6 +12,7 @@ const TEST_PATH = "http://example.com/browser/devtools/client/webconsole/new-con
|
|||
|
||||
const NET_PREF = "devtools.webconsole.filter.net";
|
||||
const XHR_PREF = "devtools.webconsole.filter.netxhr";
|
||||
|
||||
Services.prefs.setBoolPref(NET_PREF, true);
|
||||
Services.prefs.setBoolPref(XHR_PREF, true);
|
||||
registerCleanupFunction(() => {
|
||||
|
@ -47,17 +48,16 @@ add_task(async function task() {
|
|||
|
||||
async function testNetmonitorLink(toolbox, hud, url) {
|
||||
let messageNode = await waitFor(() => findMessage(hud, url));
|
||||
let urlNode = messageNode.querySelector(".url");
|
||||
info("Network message found.");
|
||||
|
||||
let onNetmonitorSelected = new Promise((resolve) => {
|
||||
toolbox.once("netmonitor-selected", (event, panel) => {
|
||||
resolve(panel);
|
||||
});
|
||||
let onNetmonitorSelected = toolbox.once("netmonitor-selected", (event, panel) => {
|
||||
return panel;
|
||||
});
|
||||
|
||||
info("Simulate click on the network message url.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, urlNode);
|
||||
let menuPopup = await openContextMenu(hud, messageNode);
|
||||
let openInNetMenuItem = menuPopup.querySelector("#console-menu-open-in-network-panel");
|
||||
ok(openInNetMenuItem, "open in network panel item is enabled");
|
||||
openInNetMenuItem.click();
|
||||
|
||||
const {panelWin} = await onNetmonitorSelected;
|
||||
ok(true, "The netmonitor panel is selected when clicking on the network message");
|
|
@ -53,7 +53,7 @@ var openNewTabAndConsole = Task.async(function* (url) {
|
|||
});
|
||||
|
||||
/**
|
||||
* Wait for messages in the web console output, resolving once they are receieved.
|
||||
* Wait for messages in the web console output, resolving once they are received.
|
||||
*
|
||||
* @param object options
|
||||
* - hud: the webconsole
|
||||
|
@ -100,7 +100,7 @@ function waitForMessages({ hud, messages }) {
|
|||
* idempotent function, since we have to run it a second time after it returns
|
||||
* true in order to return the value.
|
||||
* @param string message [optional]
|
||||
* A message to output if the condition failes.
|
||||
* A message to output if the condition fails.
|
||||
* @param number interval [optional]
|
||||
* How often the predicate is invoked, in milliseconds.
|
||||
* @return object
|
||||
|
@ -144,6 +144,7 @@ function findMessages(hud, text, selector = ".message") {
|
|||
);
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a context menu event on the provided element, and wait for the console context
|
||||
* menu to open. Returns a promise that resolves the menu popup element.
|
||||
|
@ -154,10 +155,10 @@ function findMessages(hud, text, selector = ".message") {
|
|||
* The dom element on which the context menu event should be synthesized.
|
||||
* @return promise
|
||||
*/
|
||||
function* openContextMenu(hud, element) {
|
||||
async function openContextMenu(hud, element) {
|
||||
let onConsoleMenuOpened = hud.ui.newConsoleOutput.once("menu-open");
|
||||
synthesizeContextMenuEvent(element);
|
||||
yield onConsoleMenuOpened;
|
||||
await onConsoleMenuOpened;
|
||||
return hud.ui.newConsoleOutput.toolbox.doc.getElementById("webconsole-menu");
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ requireHacker.global_hook("default", path => {
|
|||
return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/Services")`;
|
||||
case "devtools/shared/client/main":
|
||||
return `module.exports = require("devtools/client/webconsole/new-console-output/test/fixtures/ObjectClient")`;
|
||||
case "devtools/client/netmonitor/src/components/tabbox-panel":
|
||||
return "{}";
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
getAllNetworkMessagesUpdateById,
|
||||
} = require("devtools/client/webconsole/new-console-output/selectors/messages");
|
||||
const {
|
||||
setupActions,
|
||||
setupStore,
|
||||
clonePacket
|
||||
} = require("devtools/client/webconsole/new-console-output/test/helpers");
|
||||
const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
|
||||
|
||||
const expect = require("expect");
|
||||
|
||||
describe("Network message reducer:", () => {
|
||||
let actions;
|
||||
let getState;
|
||||
let dispatch;
|
||||
|
||||
before(() => {
|
||||
actions = setupActions();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const store = setupStore([]);
|
||||
|
||||
getState = store.getState;
|
||||
dispatch = store.dispatch;
|
||||
|
||||
let packet = clonePacket(stubPackets.get("GET request"));
|
||||
let updatePacket = clonePacket(stubPackets.get("GET request update"));
|
||||
|
||||
packet.actor = "message1";
|
||||
updatePacket.networkInfo.actor = "message1";
|
||||
dispatch(actions.messageAdd(packet));
|
||||
dispatch(actions.networkMessageUpdate(updatePacket.networkInfo));
|
||||
});
|
||||
|
||||
describe("networkMessagesUpdateById", () => {
|
||||
it("adds fetched HTTP request headers", () => {
|
||||
let headers = {
|
||||
headers: []
|
||||
};
|
||||
|
||||
dispatch(actions.networkUpdateRequest("message1", {
|
||||
requestHeaders: headers
|
||||
}));
|
||||
|
||||
let networkUpdates = getAllNetworkMessagesUpdateById(getState());
|
||||
expect(networkUpdates.message1.requestHeaders).toBe(headers);
|
||||
});
|
||||
|
||||
it("adds fetched HTTP security info", () => {
|
||||
let securityInfo = {
|
||||
state: "insecure"
|
||||
};
|
||||
|
||||
dispatch(actions.networkUpdateRequest("message1", {
|
||||
securityInfo: securityInfo
|
||||
}));
|
||||
|
||||
let networkUpdates = getAllNetworkMessagesUpdateById(getState());
|
||||
expect(networkUpdates.message1.securityInfo).toBe(securityInfo);
|
||||
expect(networkUpdates.message1.securityState).toBe("insecure");
|
||||
});
|
||||
|
||||
it("adds fetched HTTP post data", () => {
|
||||
let requestPostData = {
|
||||
postData: {
|
||||
text: ""
|
||||
}
|
||||
};
|
||||
|
||||
dispatch(actions.networkUpdateRequest("message1", {
|
||||
requestPostData: requestPostData
|
||||
}));
|
||||
|
||||
let networkUpdates = getAllNetworkMessagesUpdateById(getState());
|
||||
expect(networkUpdates.message1.requestPostData).toBe(requestPostData);
|
||||
expect(networkUpdates.message1.requestHeadersFromUploadStream).toExist();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -60,5 +60,10 @@ exports.NetworkEventMessage = function (props) {
|
|||
timeStamp: null,
|
||||
totalTime: null,
|
||||
indent: 0,
|
||||
updates: null,
|
||||
openedOnce: false,
|
||||
securityState: null,
|
||||
securityInfo: null,
|
||||
requestHeadersFromUploadStream: null,
|
||||
}, props);
|
||||
};
|
||||
|
|
|
@ -31,7 +31,12 @@ const { l10n } = require("devtools/client/webconsole/new-console-output/utils/me
|
|||
* - {String} source
|
||||
* - {String} request
|
||||
*/
|
||||
function createContextMenu(jsterm, parentNode, { actor, clipboardText, message }) {
|
||||
function createContextMenu(jsterm, parentNode, {
|
||||
actor,
|
||||
clipboardText,
|
||||
message,
|
||||
serviceContainer
|
||||
}) {
|
||||
let win = parentNode.ownerDocument.defaultView;
|
||||
let selection = win.getSelection();
|
||||
|
||||
|
@ -55,6 +60,19 @@ function createContextMenu(jsterm, parentNode, { actor, clipboardText, message }
|
|||
},
|
||||
}));
|
||||
|
||||
// Open Network message in the Network panel.
|
||||
menu.append(new MenuItem({
|
||||
id: "console-menu-open-in-network-panel",
|
||||
label: l10n.getStr("webconsole.menu.openInNetworkPanel.label"),
|
||||
accesskey: l10n.getStr("webconsole.menu.openInNetworkPanel.accesskey"),
|
||||
visible: source === MESSAGE_SOURCE.NETWORK,
|
||||
click: () => {
|
||||
if (request && serviceContainer.openNetworkPanel) {
|
||||
serviceContainer.openNetworkPanel(message.messageId);
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
// Open URL in a new tab for a network request.
|
||||
menu.append(new MenuItem({
|
||||
id: "console-menu-open-url",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"use strict";
|
||||
|
||||
const l10n = require("devtools/client/webconsole/webconsole-l10n");
|
||||
const { getUrlDetails } = require("devtools/client/netmonitor/src/utils/request-utils");
|
||||
|
||||
const {
|
||||
MESSAGE_SOURCE,
|
||||
|
@ -232,6 +233,11 @@ function transformNetworkEventPacket(packet) {
|
|||
response: networkEvent.response,
|
||||
timeStamp: networkEvent.timeStamp,
|
||||
totalTime: networkEvent.totalTime,
|
||||
url: networkEvent.request.url,
|
||||
urlDetails: getUrlDetails(networkEvent.request.url),
|
||||
method: networkEvent.request.method,
|
||||
updates: networkEvent.updates,
|
||||
cause: networkEvent.cause,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ WebConsolePanel.prototype = {
|
|||
let msg = "WebConsolePanel open failed. " +
|
||||
reason.error + ": " + reason.message;
|
||||
dump(msg + "\n");
|
||||
console.error(msg);
|
||||
console.error(msg, reason);
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -243,6 +243,10 @@ WebConsoleConnectionProxy.prototype = {
|
|||
this.webConsoleFrame.newConsoleOutput.dispatchMessageUpdate(networkInfo, response);
|
||||
},
|
||||
|
||||
dispatchRequestUpdate: function (id, data) {
|
||||
this.webConsoleFrame.newConsoleOutput.dispatchRequestUpdate(id, data);
|
||||
},
|
||||
|
||||
/**
|
||||
* The "cachedMessages" response handler.
|
||||
*
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
<link rel="stylesheet" href="chrome://devtools/skin/webconsole.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/components-frame.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/reps/reps.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/tabs.css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/tabbar.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/content/netmonitor/src/assets/styles/netmonitor.css"/>
|
||||
|
||||
<script src="chrome://devtools/content/shared/theme-switching.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="resource://devtools/client/webconsole/new-console-output/main.js"></script>
|
||||
|
|
|
@ -82,6 +82,7 @@ webpackConfig.resolve = {
|
|||
"devtools/shared/old-event-emitter": "devtools-modules/src/utils/event-emitter",
|
||||
"devtools/shared/client/main": path.join(__dirname, "new-console-output/test/fixtures/ObjectClient"),
|
||||
"devtools/shared/platform/clipboard": path.join(__dirname, "../../shared/platform/content/clipboard"),
|
||||
"devtools/shared/platform/stack": path.join(__dirname, "../../shared/platform/content/stack"),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -30,10 +30,8 @@
|
|||
* [Panel SVGs](frontend/svgs.md)
|
||||
* [React](frontend/react.md)
|
||||
* [Guidelines](frontend/react-guidelines.md)
|
||||
* [Tips](frontend/react-tips.md)
|
||||
* [Redux](frontend/redux.md)
|
||||
* [Guidelines](frontend/redux-guidelines.md)
|
||||
* [Tips](frontend/redux-tips.md)
|
||||
* [Telemetry](frontend/telemetry.md)
|
||||
* [Backend](backend/backend.md)
|
||||
* [Remote Debugging Protocol](backend/protocol.md)
|
||||
|
|
|
@ -19,8 +19,8 @@ Ensure that the actor's destroy is really destroying everything that it should.
|
|||
```js
|
||||
destroy: function() {
|
||||
Actor.prototype.destroy.call(this);
|
||||
events.off(this.tabActor, "will-navigate", this.onWillNavigate);
|
||||
events.off(this.tabActor, "navigate", this.onNavigate);
|
||||
this.tabActor.off("will-navigate", this.onWillNavigate);
|
||||
this.tabActor.off("navigate", this.onNavigate);
|
||||
|
||||
this.stopAnimationPlayerUpdates();
|
||||
this.tabActor = this.observer = this.actors = null;
|
||||
|
|
|
@ -487,11 +487,11 @@ Here's how you'd set it up in a spec:
|
|||
|
||||
Here's how the implementation would look:
|
||||
|
||||
const event = require("devtools/shared/event-emitter");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
// In your protocol.ActorClassWithSpec definition:
|
||||
giveGoodNews: function (news) {
|
||||
event.emit(this, "good-news", news);
|
||||
EventEmitter.emit(this, "good-news", news);
|
||||
}
|
||||
|
||||
Now you can listen to events on a front:
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# React Tips
|
||||
|
||||
Learn various tips and tricks for working with our React code.
|
||||
|
||||
## Hot Reloading
|
||||
|
||||
If you followed [this
|
||||
rule](react-guidelines.md#export-the-component-directly-and-create-factory-on-import)
|
||||
about exporting components, and are using the BrowserLoader, you can
|
||||
hot reload any React component. Just turn on the pref
|
||||
`devtools.loader.hotreload`, re-open the devtools, and you should be
|
||||
able to save any React component and instantly see changes.
|
||||
|
||||
This does not reset the state of your app, so you can quickly se
|
||||
changes in the same context.
|
||||
|
||||
## Profiling
|
||||
|
||||
We need information here about how to use React.addons.Perf to profile the app.
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
Need to document:
|
||||
|
||||
* How to attach various redux loggers
|
||||
* How to hot reload redux code
|
|
@ -30,7 +30,6 @@ const promise = require("promise");
|
|||
const protocol = require("devtools/shared/protocol");
|
||||
const {Actor} = protocol;
|
||||
const {animationPlayerSpec, animationsSpec} = require("devtools/shared/specs/animation");
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
|
||||
// Types of animations.
|
||||
const ANIMATION_TYPES = {
|
||||
|
@ -385,7 +384,7 @@ var AnimationPlayerActor = protocol.ActorClassWithSpec(animationPlayerSpec, {
|
|||
}
|
||||
|
||||
if (hasChanged) {
|
||||
events.emit(this, "changed", this.getCurrentState());
|
||||
this.emit("changed", this.getCurrentState());
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -595,14 +594,14 @@ exports.AnimationsActor = protocol.ActorClassWithSpec(animationsSpec, {
|
|||
this.onAnimationMutation = this.onAnimationMutation.bind(this);
|
||||
|
||||
this.allAnimationsPaused = false;
|
||||
events.on(this.tabActor, "will-navigate", this.onWillNavigate);
|
||||
events.on(this.tabActor, "navigate", this.onNavigate);
|
||||
this.tabActor.on("will-navigate", this.onWillNavigate);
|
||||
this.tabActor.on("navigate", this.onNavigate);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
Actor.prototype.destroy.call(this);
|
||||
events.off(this.tabActor, "will-navigate", this.onWillNavigate);
|
||||
events.off(this.tabActor, "navigate", this.onNavigate);
|
||||
this.tabActor.off("will-navigate", this.onWillNavigate);
|
||||
this.tabActor.off("navigate", this.onNavigate);
|
||||
|
||||
this.stopAnimationPlayerUpdates();
|
||||
this.tabActor = this.observer = this.actors = this.walker = null;
|
||||
|
@ -729,7 +728,7 @@ exports.AnimationsActor = protocol.ActorClassWithSpec(animationsSpec, {
|
|||
// Let's wait for all added animations to be ready before telling the
|
||||
// front-end.
|
||||
Promise.all(readyPromises).then(() => {
|
||||
events.emit(this, "mutations", eventData);
|
||||
this.emit("mutations", eventData);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,12 +6,9 @@
|
|||
/* global XPCNativeWrapper */
|
||||
|
||||
const {Ci, Cu} = require("chrome");
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const {serializeStack, parseStack} = require("toolkit/loader");
|
||||
|
||||
const {on, off, emit} = events;
|
||||
|
||||
const { functionCallSpec, callWatcherSpec } = require("devtools/shared/specs/call-watcher");
|
||||
const { CallWatcherFront } = require("devtools/shared/fronts/call-watcher");
|
||||
|
||||
|
@ -237,13 +234,13 @@ exports.CallWatcherActor = protocol.ActorClassWithSpec(callWatcherSpec, {
|
|||
this._onGlobalCreated = this._onGlobalCreated.bind(this);
|
||||
this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
|
||||
this._onContentFunctionCall = this._onContentFunctionCall.bind(this);
|
||||
on(this.tabActor, "window-ready", this._onGlobalCreated);
|
||||
on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
|
||||
this.tabActor.on("window-ready", this._onGlobalCreated);
|
||||
this.tabActor.on("window-destroyed", this._onGlobalDestroyed);
|
||||
},
|
||||
destroy: function (conn) {
|
||||
protocol.Actor.prototype.destroy.call(this, conn);
|
||||
off(this.tabActor, "window-ready", this._onGlobalCreated);
|
||||
off(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
|
||||
this.tabActor.off("window-ready", this._onGlobalCreated);
|
||||
this.tabActor.off("window-destroyed", this._onGlobalDestroyed);
|
||||
this.finalize();
|
||||
},
|
||||
|
||||
|
@ -543,7 +540,7 @@ exports.CallWatcherActor = protocol.ActorClassWithSpec(callWatcherSpec, {
|
|||
if (this.onCall) {
|
||||
this.onCall(functionCall);
|
||||
} else {
|
||||
emit(this, "call", functionCall);
|
||||
this.emit("call", functionCall);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,7 +9,6 @@ const { Cc, Ci } = require("chrome");
|
|||
const Services = require("Services");
|
||||
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const { cssUsageSpec } = require("devtools/shared/specs/csscoverage");
|
||||
|
||||
|
@ -135,7 +134,7 @@ var CSSUsageActor = protocol.ActorClassWithSpec(cssUsageSpec, {
|
|||
this._tabActor.window.location.reload();
|
||||
}
|
||||
|
||||
events.emit(this, "state-change", { isRunning: true });
|
||||
this.emit("state-change", { isRunning: true });
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -150,7 +149,7 @@ var CSSUsageActor = protocol.ActorClassWithSpec(cssUsageSpec, {
|
|||
this._progress = undefined;
|
||||
|
||||
this._running = false;
|
||||
events.emit(this, "state-change", { isRunning: false });
|
||||
this.emit("state-change", { isRunning: false });
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,6 @@ const {Ci} = require("chrome");
|
|||
const Services = require("Services");
|
||||
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {Actor, ActorClassWithSpec} = require("devtools/shared/protocol");
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const {eventLoopLagSpec} = require("devtools/shared/specs/eventlooplag");
|
||||
|
||||
exports.EventLoopLagActor = ActorClassWithSpec(eventLoopLagSpec, {
|
||||
|
@ -52,7 +51,7 @@ exports.EventLoopLagActor = ActorClassWithSpec(eventLoopLagSpec, {
|
|||
observe: function (subject, topic, data) {
|
||||
if (topic == "event-loop-lag") {
|
||||
// Forward event loop lag event
|
||||
events.emit(this, "event-loop-lag", data);
|
||||
this.emit("event-loop-lag", data);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol");
|
||||
const { gcliSpec } = require("devtools/shared/specs/gcli");
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const { createSystem } = require("gcli/system");
|
||||
|
||||
/**
|
||||
|
@ -222,7 +221,7 @@ const GcliActor = ActorClassWithSpec(gcliSpec, {
|
|||
* Pass events from requisition.system.commands.onCommandsChange upwards
|
||||
*/
|
||||
_commandsChanged: function () {
|
||||
events.emit(this, "commands-changed");
|
||||
this.emit("commands-changed");
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ const { Ci, Cu } = require("chrome");
|
|||
|
||||
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const EventEmitter = require("devtools/shared/old-event-emitter");
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const Services = require("Services");
|
||||
const { isWindowIncluded } = require("devtools/shared/layout/utils");
|
||||
|
@ -106,7 +105,7 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
|
||||
// Listen to navigation events to switch from the BoxModelHighlighter to the
|
||||
// SimpleOutlineHighlighter, and back, if the top level window changes.
|
||||
events.on(this._tabActor, "navigate", this._onNavigate);
|
||||
this._tabActor.on("navigate", this._onNavigate);
|
||||
},
|
||||
|
||||
get conn() {
|
||||
|
@ -165,7 +164,7 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
|
||||
this.hideBoxModel();
|
||||
this._destroyHighlighter();
|
||||
events.off(this._tabActor, "navigate", this._onNavigate);
|
||||
this._tabActor.off("navigate", this._onNavigate);
|
||||
|
||||
this._highlighterEnv.destroy();
|
||||
this._highlighterEnv = null;
|
||||
|
@ -255,7 +254,7 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
// If shift is pressed, this is only a preview click, send the event to
|
||||
// the client, but don't stop picking.
|
||||
if (event.shiftKey) {
|
||||
events.emit(this._walker, "picker-node-previewed",
|
||||
this._walker.emit("picker-node-previewed",
|
||||
this._findAndAttachElement(event));
|
||||
return;
|
||||
}
|
||||
|
@ -270,7 +269,7 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
if (!this._currentNode) {
|
||||
this._currentNode = this._findAndAttachElement(event);
|
||||
}
|
||||
events.emit(this._walker, "picker-node-picked", this._currentNode);
|
||||
this._walker.emit("picker-node-picked", this._currentNode);
|
||||
};
|
||||
|
||||
this._onHovered = event => {
|
||||
|
@ -283,7 +282,7 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
this._currentNode = this._findAndAttachElement(event);
|
||||
if (this._hoveredNode !== this._currentNode.node) {
|
||||
this._highlighter.show(this._currentNode.node.rawNode);
|
||||
events.emit(this._walker, "picker-node-hovered", this._currentNode);
|
||||
this._walker.emit("picker-node-hovered", this._currentNode);
|
||||
this._hoveredNode = this._currentNode.node;
|
||||
}
|
||||
};
|
||||
|
@ -345,13 +344,13 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
// Cancel pick mode.
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE:
|
||||
this.cancelPick();
|
||||
events.emit(this._walker, "picker-node-canceled");
|
||||
this._walker.emit("picker-node-canceled");
|
||||
return;
|
||||
case Ci.nsIDOMKeyEvent.DOM_VK_C:
|
||||
if ((IS_OSX && event.metaKey && event.altKey) ||
|
||||
(!IS_OSX && event.ctrlKey && event.shiftKey)) {
|
||||
this.cancelPick();
|
||||
events.emit(this._walker, "picker-node-canceled");
|
||||
this._walker.emit("picker-node-canceled");
|
||||
}
|
||||
return;
|
||||
default: return;
|
||||
|
@ -360,7 +359,7 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
// Store currently attached element
|
||||
this._currentNode = this._walker.attachElement(currentNode);
|
||||
this._highlighter.show(this._currentNode.node.rawNode);
|
||||
events.emit(this._walker, "picker-node-hovered", this._currentNode);
|
||||
this._walker.emit("picker-node-hovered", this._currentNode);
|
||||
};
|
||||
|
||||
this._startPickerListeners();
|
||||
|
@ -414,11 +413,11 @@ exports.HighlighterActor = protocol.ActorClassWithSpec(highlighterSpec, {
|
|||
},
|
||||
|
||||
_highlighterReady: function () {
|
||||
events.emit(this._inspector.walker, "highlighter-ready");
|
||||
this._inspector.walker.emit("highlighter-ready");
|
||||
},
|
||||
|
||||
_highlighterHidden: function () {
|
||||
events.emit(this._inspector.walker, "highlighter-hide");
|
||||
this._inspector.walker.emit("highlighter-hide");
|
||||
},
|
||||
|
||||
cancelPick: function () {
|
||||
|
@ -518,7 +517,7 @@ exports.CustomHighlighterActor = protocol.ActorClassWithSpec(customHighlighterSp
|
|||
* Upon receiving an event from the highlighter, forward it to the client.
|
||||
*/
|
||||
_onHighlighterEvent: function (type, data) {
|
||||
events.emit(this, "highlighter-event", data);
|
||||
this.emit("highlighter-event", data);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -567,9 +566,9 @@ exports.HighlighterEnvironment = HighlighterEnvironment;
|
|||
HighlighterEnvironment.prototype = {
|
||||
initFromTabActor: function (tabActor) {
|
||||
this._tabActor = tabActor;
|
||||
events.on(this._tabActor, "window-ready", this.relayTabActorWindowReady);
|
||||
events.on(this._tabActor, "navigate", this.relayTabActorNavigate);
|
||||
events.on(this._tabActor, "will-navigate", this.relayTabActorWillNavigate);
|
||||
this._tabActor.on("window-ready", this.relayTabActorWindowReady);
|
||||
this._tabActor.on("navigate", this.relayTabActorNavigate);
|
||||
this._tabActor.on("will-navigate", this.relayTabActorWillNavigate);
|
||||
},
|
||||
|
||||
initFromWindow: function (win) {
|
||||
|
@ -686,9 +685,9 @@ HighlighterEnvironment.prototype = {
|
|||
|
||||
destroy: function () {
|
||||
if (this._tabActor) {
|
||||
events.off(this._tabActor, "window-ready", this.relayTabActorWindowReady);
|
||||
events.off(this._tabActor, "navigate", this.relayTabActorNavigate);
|
||||
events.off(this._tabActor, "will-navigate", this.relayTabActorWillNavigate);
|
||||
this._tabActor.off("window-ready", this.relayTabActorWindowReady);
|
||||
this._tabActor.off("navigate", this.relayTabActorNavigate);
|
||||
this._tabActor.off("will-navigate", this.relayTabActorWillNavigate);
|
||||
}
|
||||
|
||||
// In case the environment was initialized from a window, we need to remove
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { getCurrentZoom, getWindowDimensions,
|
||||
setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
|
||||
const {
|
||||
|
@ -212,7 +212,7 @@ MeasuringToolHighlighter.prototype = {
|
|||
|
||||
this.markup.destroy();
|
||||
|
||||
events.emit(this, "destroy");
|
||||
EventEmitter.emit(this, "destroy");
|
||||
},
|
||||
|
||||
show() {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { getCurrentZoom,
|
||||
setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
|
||||
const {
|
||||
|
@ -277,7 +277,7 @@ RulersHighlighter.prototype = {
|
|||
|
||||
this.markup.destroy();
|
||||
|
||||
events.emit(this, "destroy");
|
||||
EventEmitter.emit(this, "destroy");
|
||||
},
|
||||
|
||||
show: function () {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
const { getCurrentZoom, getWindowDimensions, getViewportDimensions,
|
||||
getRootBindingParent, loadSheet } = require("devtools/shared/layout/utils");
|
||||
const { on, emit } = require("devtools/shared/event-emitter");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
const lazyContainer = {};
|
||||
|
||||
|
@ -61,7 +61,7 @@ ClassList.prototype = {
|
|||
if (!this.contains(token)) {
|
||||
this[_tokens].push(token);
|
||||
}
|
||||
emit(this, "update");
|
||||
EventEmitter.emit(this, "update");
|
||||
},
|
||||
remove(token) {
|
||||
let index = this[_tokens].indexOf(token);
|
||||
|
@ -69,7 +69,7 @@ ClassList.prototype = {
|
|||
if (index > -1) {
|
||||
this[_tokens].splice(index, 1);
|
||||
}
|
||||
emit(this, "update");
|
||||
EventEmitter.emit(this, "update");
|
||||
},
|
||||
toggle(token) {
|
||||
if (this.contains(token)) {
|
||||
|
@ -482,7 +482,7 @@ CanvasFrameAnonymousContentHelper.prototype = {
|
|||
|
||||
let classList = new ClassList(this.getAttributeForElement(id, "class"));
|
||||
|
||||
on(classList, "update", () => {
|
||||
EventEmitter.on(classList, "update", () => {
|
||||
this.setAttributeForElement(id, "class", classList.toString());
|
||||
});
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ const {LongStringActor} = require("devtools/server/actors/string");
|
|||
const promise = require("promise");
|
||||
const defer = require("devtools/shared/defer");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const events = require("devtools/shared/event-emitter");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {WalkerSearch} = require("devtools/server/actors/utils/walker-search");
|
||||
const {PageStyleActor, getFontPreviewData} = require("devtools/server/actors/styles");
|
||||
const {
|
||||
|
@ -298,7 +298,7 @@ var NodeActor = exports.NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
|
|||
|
||||
// Fire an event so, other modules can create its own properties
|
||||
// that should be passed to the client (within the form.props field).
|
||||
events.emit(NodeActor, "form", {
|
||||
EventEmitter.emit(NodeActor, "form", {
|
||||
target: this,
|
||||
data: form
|
||||
});
|
||||
|
@ -890,8 +890,8 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
this.onFrameLoad = this.onFrameLoad.bind(this);
|
||||
this.onFrameUnload = this.onFrameUnload.bind(this);
|
||||
|
||||
events.on(tabActor, "will-navigate", this.onFrameUnload);
|
||||
events.on(tabActor, "window-ready", this.onFrameLoad);
|
||||
tabActor.on("will-navigate", this.onFrameUnload);
|
||||
tabActor.on("window-ready", this.onFrameLoad);
|
||||
|
||||
// Ensure that the root document node actor is ready and
|
||||
// managed.
|
||||
|
@ -981,8 +981,8 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
this._retainedOrphans = null;
|
||||
this._refMap = null;
|
||||
|
||||
events.off(this.tabActor, "will-navigate", this.onFrameUnload);
|
||||
events.off(this.tabActor, "window-ready", this.onFrameLoad);
|
||||
this.tabActor.off("will-navigate", this.onFrameUnload);
|
||||
this.tabActor.off("window-ready", this.onFrameLoad);
|
||||
|
||||
this.onFrameLoad = null;
|
||||
this.onFrameUnload = null;
|
||||
|
@ -1002,7 +1002,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
this.layoutActor = null;
|
||||
this.tabActor = null;
|
||||
|
||||
events.emit(this, "destroyed");
|
||||
this.emit("destroyed");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
@ -1077,7 +1077,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
}
|
||||
|
||||
if (changes.length) {
|
||||
events.emit(this, "display-change", changes);
|
||||
this.emit("display-change", changes);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1085,7 +1085,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
* When the browser window gets resized, relay the event to the front.
|
||||
*/
|
||||
_onResize: function () {
|
||||
events.emit(this, "resize");
|
||||
this.emit("resize");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2333,7 +2333,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
this._pendingMutations.push(mutation);
|
||||
|
||||
if (needEvent) {
|
||||
events.emit(this, "new-mutations");
|
||||
this.emit("new-mutations");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2347,7 +2347,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
|
|||
// Notify any observers that want *all* mutations (even on nodes that aren't
|
||||
// referenced). This is not sent over the protocol so can only be used by
|
||||
// scripts running in the server process.
|
||||
events.emit(this, "any-mutation");
|
||||
this.emit("any-mutation");
|
||||
|
||||
for (let change of mutations) {
|
||||
let targetActor = this.getNode(change.target);
|
||||
|
@ -2760,7 +2760,7 @@ exports.InspectorActor = protocol.ActorClassWithSpec(inspectorSpec, {
|
|||
window.removeEventListener("DOMContentLoaded", domReady, true);
|
||||
this.walker = WalkerActor(this.conn, tabActor, options);
|
||||
this.manage(this.walker);
|
||||
events.once(this.walker, "destroyed", () => {
|
||||
this.walker.once("destroyed", () => {
|
||||
this._walkerPromise = null;
|
||||
this._pageStylePromise = null;
|
||||
});
|
||||
|
@ -2913,7 +2913,7 @@ exports.InspectorActor = protocol.ActorClassWithSpec(inspectorSpec, {
|
|||
this._eyeDropper.show(this.window.document.documentElement, options);
|
||||
this._eyeDropper.once("selected", this._onColorPicked);
|
||||
this._eyeDropper.once("canceled", this._onColorPickCanceled);
|
||||
events.once(this.tabActor, "will-navigate", this.destroyEyeDropper);
|
||||
this.tabActor.once("will-navigate", this.destroyEyeDropper);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2926,7 +2926,7 @@ exports.InspectorActor = protocol.ActorClassWithSpec(inspectorSpec, {
|
|||
this._eyeDropper.hide();
|
||||
this._eyeDropper.off("selected", this._onColorPicked);
|
||||
this._eyeDropper.off("canceled", this._onColorPickCanceled);
|
||||
events.off(this.tabActor, "will-navigate", this.destroyEyeDropper);
|
||||
this.tabActor.off("will-navigate", this.destroyEyeDropper);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2954,11 +2954,11 @@ exports.InspectorActor = protocol.ActorClassWithSpec(inspectorSpec, {
|
|||
},
|
||||
|
||||
_onColorPicked: function (e, color) {
|
||||
events.emit(this, "color-picked", color);
|
||||
this.emit("color-picked", color);
|
||||
},
|
||||
|
||||
_onColorPickCanceled: function () {
|
||||
events.emit(this, "color-pick-canceled");
|
||||
this.emit("color-pick-canceled");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ const protocol = require("devtools/shared/protocol");
|
|||
const { Memory } = require("devtools/server/performance/memory");
|
||||
const { actorBridgeWithSpec } = require("devtools/server/actors/common");
|
||||
const { memorySpec } = require("devtools/shared/specs/memory");
|
||||
loader.lazyRequireGetter(this, "events", "devtools/shared/event-emitter");
|
||||
loader.lazyRequireGetter(this, "StackFrameCache",
|
||||
"devtools/server/actors/utils/stack", true);
|
||||
|
||||
|
@ -71,13 +70,13 @@ exports.MemoryActor = protocol.ActorClassWithSpec(memorySpec, {
|
|||
|
||||
_onGarbageCollection: function (data) {
|
||||
if (this.conn.transport) {
|
||||
events.emit(this, "garbage-collection", data);
|
||||
this.emit("garbage-collection", data);
|
||||
}
|
||||
},
|
||||
|
||||
_onAllocations: function (data) {
|
||||
if (this.conn.transport) {
|
||||
events.emit(this, "allocations", data);
|
||||
this.emit("allocations", data);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче