mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Merge autoland to central, a=merge
MozReview-Commit-ID: 9FDTT0Vkl0L
This commit is contained in:
commit
ec985117e6
@ -186,11 +186,6 @@ $(addprefix install-,$(subst /,_,$(filter dist/%,$(install_manifests)))): instal
|
||||
.PHONY: install-tests
|
||||
install-tests: install-test-files
|
||||
|
||||
# We no longer run "make install-tests" directly before running tests, but we still
|
||||
# want to depend on things like config.status, hence this target.
|
||||
.PHONY: run-tests-deps
|
||||
run-tests-deps: $(install_manifest_depends)
|
||||
|
||||
# Force --no-remove, because $objdir/_tests is handled by multiple manifests.
|
||||
.PHONY: install-test-files
|
||||
install-test-files:
|
||||
|
@ -327,7 +327,8 @@ isColumnSelectedCB(AtkTable *aTable, gint aColIdx)
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||
if (accWrap) {
|
||||
return static_cast<gboolean>(accWrap->AsTable()->IsColSelected(aColIdx));
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||
}
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||
return static_cast<gboolean>(proxy->TableColumnSelected(aColIdx));
|
||||
}
|
||||
|
||||
@ -340,7 +341,8 @@ isRowSelectedCB(AtkTable *aTable, gint aRowIdx)
|
||||
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aTable));
|
||||
if (accWrap) {
|
||||
return static_cast<gboolean>(accWrap->AsTable()->IsRowSelected(aRowIdx));
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||
}
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||
return static_cast<gboolean>(proxy->TableRowSelected(aRowIdx));
|
||||
}
|
||||
|
||||
@ -354,7 +356,8 @@ isCellSelectedCB(AtkTable *aTable, gint aRowIdx, gint aColIdx)
|
||||
if (accWrap) {
|
||||
return static_cast<gboolean>(accWrap->AsTable()->
|
||||
IsCellSelected(aRowIdx, aColIdx));
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||
}
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aTable))) {
|
||||
return static_cast<gboolean>(proxy->TableCellSelected(aRowIdx, aColIdx));
|
||||
}
|
||||
|
||||
|
@ -500,7 +500,8 @@ getTextSelectionCB(AtkText *aText, gint aSelectionNum,
|
||||
*aEndOffset = endOffset;
|
||||
|
||||
return getTextCB(aText, *aStartOffset, *aEndOffset);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
}
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
nsString data;
|
||||
proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset);
|
||||
*aStartOffset = startOffset;
|
||||
@ -526,7 +527,8 @@ addTextSelectionCB(AtkText *aText,
|
||||
}
|
||||
|
||||
return text->AddToSelection(aStartOffset, aEndOffset);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
}
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
return proxy->AddToSelection(aStartOffset, aEndOffset);
|
||||
}
|
||||
|
||||
@ -545,7 +547,8 @@ removeTextSelectionCB(AtkText *aText,
|
||||
}
|
||||
|
||||
return text->RemoveFromSelection(aSelectionNum);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
}
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
return proxy->RemoveFromSelection(aSelectionNum);
|
||||
}
|
||||
|
||||
@ -564,7 +567,8 @@ setTextSelectionCB(AtkText *aText, gint aSelectionNum,
|
||||
}
|
||||
|
||||
return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
|
||||
} else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
}
|
||||
if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
|
||||
return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
|
||||
}
|
||||
|
||||
|
@ -1586,6 +1586,7 @@ pref("services.sync.validation.enabled", true);
|
||||
// Preferences for the form autofill system extension
|
||||
pref("browser.formautofill.experimental", false);
|
||||
pref("browser.formautofill.enabled", false);
|
||||
pref("browser.formautofill.loglevel", "Warn");
|
||||
|
||||
// Enable safebrowsing v4 tables (suffixed by "-proto") update.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
|
@ -99,6 +99,7 @@
|
||||
const event = new CustomEvent("AboutNetErrorResetPreferences", {bubbles:true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
addAutofocus("prefResetButton", "beforeend");
|
||||
}
|
||||
|
||||
function setupAdvancedButton() {
|
||||
@ -198,6 +199,7 @@
|
||||
initPageCertError();
|
||||
return;
|
||||
}
|
||||
addAutofocus("errorTryAgain");
|
||||
|
||||
document.body.className = "neterror";
|
||||
|
||||
@ -317,6 +319,7 @@
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
addAutofocus("openPortalLoginPageButton");
|
||||
setupAdvancedButton();
|
||||
|
||||
addDomainErrorLinks();
|
||||
@ -335,6 +338,7 @@
|
||||
host.textContent = document.location.hostname;
|
||||
}
|
||||
|
||||
addAutofocus("returnButton");
|
||||
setupAdvancedButton();
|
||||
|
||||
document.getElementById("learnMoreContainer").style.display = "block";
|
||||
@ -364,6 +368,22 @@
|
||||
addDomainErrorLinks();
|
||||
}
|
||||
|
||||
/* Only do autofocus if we're the toplevel frame; otherwise we
|
||||
don't want to call attention to ourselves! The key part is
|
||||
that autofocus happens on insertion into the tree, so we
|
||||
can remove the button, add @autofocus, and reinsert the
|
||||
button.
|
||||
*/
|
||||
function addAutofocus(buttonId, position = "afterbegin") {
|
||||
if (window.top == window) {
|
||||
var button = document.getElementById(buttonId);
|
||||
var parent = button.parentNode;
|
||||
button.remove();
|
||||
button.setAttribute("autofocus", "true");
|
||||
parent.insertAdjacentElement(position, button);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to preserve the links contained in the error description, like
|
||||
the error code.
|
||||
|
||||
@ -595,10 +615,10 @@
|
||||
</div>
|
||||
|
||||
<div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
|
||||
<button id="returnButton" class="primary" autocomplete="off" autofocus="true">&returnToPreviousPage.label;</button>
|
||||
<button id="openPortalLoginPageButton" class="primary" autocomplete="off" autofocus="true">&openPortalLoginPage.label2;</button>
|
||||
<button id="returnButton" class="primary" autocomplete="off">&returnToPreviousPage.label;</button>
|
||||
<button id="openPortalLoginPageButton" class="primary" autocomplete="off">&openPortalLoginPage.label2;</button>
|
||||
<div class="button-spacer"></div>
|
||||
<button id="advancedButton" autocomplete="off" autofocus="true">&advanced.label;</button>
|
||||
<button id="advancedButton" autocomplete="off">&advanced.label;</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -606,21 +626,6 @@
|
||||
<button id="errorTryAgain" class="primary" autocomplete="off" onclick="retryThis(this);">&retry.label;</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Only do autofocus if we're the toplevel frame; otherwise we
|
||||
// don't want to call attention to ourselves! The key part is
|
||||
// that autofocus happens on insertion into the tree, so we
|
||||
// can remove the button, add @autofocus, and reinsert the
|
||||
// button.
|
||||
if (window.top == window) {
|
||||
var button = document.getElementById("errorTryAgain");
|
||||
var parent = button.parentNode;
|
||||
button.remove();
|
||||
button.setAttribute("autofocus", "true");
|
||||
parent.appendChild(button);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- UI for option to report certificate errors to Mozilla. Removed on
|
||||
init for other error types .-->
|
||||
<div id="certificateErrorReporting">
|
||||
|
@ -2367,7 +2367,7 @@ function BrowserViewSourceOfDocument(aArgsOrDocument) {
|
||||
relatedToCurrent: true,
|
||||
inBackground: false,
|
||||
preferredRemoteType,
|
||||
relatedBrowser: args.browser
|
||||
sameProcessAsFrameLoader: args.browser ? args.browser.frameLoader : null
|
||||
});
|
||||
args.viewSourceBrowser = tabBrowser.getBrowserForTab(tab);
|
||||
top.gViewSourceUtils.viewSourceInBrowser(args);
|
||||
@ -3347,19 +3347,21 @@ var PrintPreviewListener = {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let preferredRemoteType = browser.remoteType;
|
||||
this._tabBeforePrintPreview = gBrowser.selectedTab;
|
||||
this._printPreviewTab = gBrowser.loadOneTab("about:blank",
|
||||
{ inBackground: false,
|
||||
preferredRemoteType,
|
||||
relatedBrowser: browser });
|
||||
this._printPreviewTab = gBrowser.loadOneTab("about:blank", {
|
||||
inBackground: false,
|
||||
preferredRemoteType,
|
||||
sameProcessAsFrameLoader: browser.frameLoader
|
||||
});
|
||||
gBrowser.selectedTab = this._printPreviewTab;
|
||||
}
|
||||
return gBrowser.getBrowserForTab(this._printPreviewTab);
|
||||
},
|
||||
createSimplifiedBrowser() {
|
||||
let browser = this._tabBeforePrintPreview.linkedBrowser;
|
||||
this._simplifyPageTab = gBrowser.loadOneTab("about:blank",
|
||||
{ inBackground: true,
|
||||
relatedBrowser: browser });
|
||||
this._simplifyPageTab = gBrowser.loadOneTab("about:blank", {
|
||||
inBackground: true,
|
||||
sameProcessAsFrameLoader: browser.frameLoader
|
||||
});
|
||||
return this.getSimplifiedSourceBrowser();
|
||||
},
|
||||
getSourceBrowser() {
|
||||
|
@ -1511,32 +1511,32 @@
|
||||
var aPreferredRemoteType;
|
||||
var aNoReferrer;
|
||||
var aUserContextId;
|
||||
var aRelatedBrowser;
|
||||
var aSameProcessAsFrameLoader;
|
||||
var aOriginPrincipal;
|
||||
var aOpener;
|
||||
if (arguments.length == 2 &&
|
||||
typeof arguments[1] == "object" &&
|
||||
!(arguments[1] instanceof Ci.nsIURI)) {
|
||||
let params = arguments[1];
|
||||
aTriggeringPrincipal = params.triggeringPrincipal
|
||||
aReferrerURI = params.referrerURI;
|
||||
aReferrerPolicy = params.referrerPolicy;
|
||||
aCharset = params.charset;
|
||||
aPostData = params.postData;
|
||||
aLoadInBackground = params.inBackground;
|
||||
aAllowThirdPartyFixup = params.allowThirdPartyFixup;
|
||||
aFromExternal = params.fromExternal;
|
||||
aRelatedToCurrent = params.relatedToCurrent;
|
||||
aAllowMixedContent = params.allowMixedContent;
|
||||
aSkipAnimation = params.skipAnimation;
|
||||
aForceNotRemote = params.forceNotRemote;
|
||||
aPreferredRemoteType = params.preferredRemoteType;
|
||||
aNoReferrer = params.noReferrer;
|
||||
aUserContextId = params.userContextId;
|
||||
aRelatedBrowser = params.relatedBrowser;
|
||||
aOriginPrincipal = params.originPrincipal;
|
||||
aOpener = params.opener;
|
||||
aIsPrerendered = params.isPrerendered;
|
||||
aTriggeringPrincipal = params.triggeringPrincipal
|
||||
aReferrerURI = params.referrerURI;
|
||||
aReferrerPolicy = params.referrerPolicy;
|
||||
aCharset = params.charset;
|
||||
aPostData = params.postData;
|
||||
aLoadInBackground = params.inBackground;
|
||||
aAllowThirdPartyFixup = params.allowThirdPartyFixup;
|
||||
aFromExternal = params.fromExternal;
|
||||
aRelatedToCurrent = params.relatedToCurrent;
|
||||
aAllowMixedContent = params.allowMixedContent;
|
||||
aSkipAnimation = params.skipAnimation;
|
||||
aForceNotRemote = params.forceNotRemote;
|
||||
aPreferredRemoteType = params.preferredRemoteType;
|
||||
aNoReferrer = params.noReferrer;
|
||||
aUserContextId = params.userContextId;
|
||||
aSameProcessAsFrameLoader = params.sameProcessAsFrameLoader;
|
||||
aOriginPrincipal = params.originPrincipal;
|
||||
aOpener = params.opener;
|
||||
aIsPrerendered = params.isPrerendered;
|
||||
}
|
||||
|
||||
var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
|
||||
@ -1560,7 +1560,7 @@
|
||||
noReferrer: aNoReferrer,
|
||||
userContextId: aUserContextId,
|
||||
originPrincipal: aOriginPrincipal,
|
||||
relatedBrowser: aRelatedBrowser,
|
||||
sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
|
||||
opener: aOpener,
|
||||
isPrerendered: aIsPrerendered });
|
||||
if (!bgLoad)
|
||||
@ -1736,9 +1736,9 @@
|
||||
aBrowser.destroy();
|
||||
|
||||
// Make sure to restore the original droppedLinkHandler and
|
||||
// relatedBrowser.
|
||||
// sameProcessAsFrameLoader.
|
||||
let droppedLinkHandler = aBrowser.droppedLinkHandler;
|
||||
let relatedBrowser = aBrowser.relatedBrowser;
|
||||
let sameProcessAsFrameLoader = aBrowser.sameProcessAsFrameLoader;
|
||||
|
||||
// Change the "remote" attribute.
|
||||
let parent = aBrowser.parentNode;
|
||||
@ -1756,7 +1756,7 @@
|
||||
// type copying related browser would stop the switch and the
|
||||
// previously related browser will no longer be relevant.
|
||||
if (!aShouldBeRemote || currentRemoteType == aOptions.remoteType) {
|
||||
aBrowser.relatedBrowser = relatedBrowser;
|
||||
aBrowser.sameProcessAsFrameLoader = sameProcessAsFrameLoader;
|
||||
}
|
||||
|
||||
if (aOptions.opener) {
|
||||
@ -1996,8 +1996,8 @@
|
||||
|
||||
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
|
||||
|
||||
if (aParams.relatedBrowser) {
|
||||
b.relatedBrowser = aParams.relatedBrowser;
|
||||
if (aParams.sameProcessAsFrameLoader) {
|
||||
b.sameProcessAsFrameLoader = aParams.sameProcessAsFrameLoader;
|
||||
}
|
||||
|
||||
// Create the browserStack container
|
||||
@ -2078,7 +2078,7 @@
|
||||
remoteType,
|
||||
uriIsAboutBlank,
|
||||
userContextId: aParams.userContextId,
|
||||
relatedBrowser: aParams.relatedBrowser,
|
||||
sameProcessAsFrameLoader: aParams.sameProcessAsFrameLoader,
|
||||
opener: aParams.opener,
|
||||
isPrerendered: aParams.isPrerendered});
|
||||
}
|
||||
@ -2157,7 +2157,7 @@
|
||||
var aNoReferrer;
|
||||
var aUserContextId;
|
||||
var aEventDetail;
|
||||
var aRelatedBrowser;
|
||||
var aSameProcessAsFrameLoader;
|
||||
var aOriginPrincipal;
|
||||
var aDisallowInheritPrincipal;
|
||||
var aOpener;
|
||||
@ -2181,7 +2181,7 @@
|
||||
aNoReferrer = params.noReferrer;
|
||||
aUserContextId = params.userContextId;
|
||||
aEventDetail = params.eventDetail;
|
||||
aRelatedBrowser = params.relatedBrowser;
|
||||
aSameProcessAsFrameLoader = params.sameProcessAsFrameLoader;
|
||||
aOriginPrincipal = params.originPrincipal;
|
||||
aDisallowInheritPrincipal = params.disallowInheritPrincipal;
|
||||
aOpener = params.opener;
|
||||
@ -2273,7 +2273,7 @@
|
||||
forceNotRemote: aForceNotRemote,
|
||||
preferredRemoteType: aPreferredRemoteType,
|
||||
userContextId: aUserContextId,
|
||||
relatedBrowser: aRelatedBrowser,
|
||||
sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
|
||||
opener: aOpener,
|
||||
isPrerendered: aIsPrerendered,
|
||||
};
|
||||
|
@ -46,7 +46,9 @@ add_task(function* checkCaptivePortalCertErrorUI() {
|
||||
"Captive portal error page UI is visible.");
|
||||
|
||||
info("Clicking the Open Login Page button.");
|
||||
doc.getElementById("openPortalLoginPageButton").click();
|
||||
let loginButton = doc.getElementById("openPortalLoginPageButton");
|
||||
is(loginButton.getAttribute("autofocus"), "true", "openPortalLoginPageButton has autofocus");
|
||||
loginButton.click();
|
||||
});
|
||||
|
||||
let portalTab = yield portalTabPromise;
|
||||
|
@ -39,6 +39,7 @@ add_task(function* checkReturnToAboutHome() {
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let returnButton = doc.getElementById("returnButton");
|
||||
is(returnButton.getAttribute("autofocus"), "true", "returnButton has autofocus");
|
||||
returnButton.click();
|
||||
});
|
||||
yield pageshowPromise;
|
||||
|
@ -31,7 +31,10 @@ add_task(function* checkReturnToPreviousPage() {
|
||||
|
||||
let pageshowPromise = promiseWaitForEvent(browser, "pageshow");
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
content.document.getElementById("prefResetButton").click();
|
||||
let doc = content.document;
|
||||
let prefResetButton = doc.getElementById("prefResetButton");
|
||||
Assert.equal(prefResetButton.getAttribute("autofocus"), "true", "prefResetButton has autofocus");
|
||||
prefResetButton.click();
|
||||
});
|
||||
yield pageshowPromise;
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Obtain the blob, and read the string contained in it.
|
||||
// Post back the string.
|
||||
|
||||
/* eslint-env worker */
|
||||
|
||||
var postStringInBlob = function(blobObject) {
|
||||
var fileReader = new FileReaderSync();
|
||||
var result = fileReader.readAsText(blobObject);
|
||||
|
@ -877,9 +877,15 @@ var gCookiesWindow = {
|
||||
_updateRemoveAllButton: function gCookiesWindow__updateRemoveAllButton() {
|
||||
let removeAllCookies = document.getElementById("removeAllCookies");
|
||||
removeAllCookies.disabled = this._view._rowCount == 0;
|
||||
let label = this._view._filtered ?
|
||||
this._bundle.getString("removeAllShownCookies.label") : this._bundle.getString("removeAllCookies.label");
|
||||
removeAllCookies.setAttribute("label", label);
|
||||
|
||||
let labelStringID = "removeAllCookies.label";
|
||||
let accessKeyStringID = "removeAllCookies.accesskey";
|
||||
if (this._view._filtered) {
|
||||
labelStringID = "removeAllShownCookies.label";
|
||||
accessKeyStringID = "removeAllShownCookies.accesskey";
|
||||
}
|
||||
removeAllCookies.setAttribute("label", this._bundle.getString(labelStringID));
|
||||
removeAllCookies.setAttribute("accesskey", this._bundle.getString(accessKeyStringID));
|
||||
},
|
||||
|
||||
filter() {
|
||||
|
@ -45,9 +45,6 @@ let gSiteDataSettings = {
|
||||
Services.obs.notifyObservers(null, "sitedata-settings-init", null);
|
||||
});
|
||||
|
||||
let removeAllBtn = document.getElementById("removeAll");
|
||||
removeAllBtn.setAttribute("accesskey", this._prefStrBundle.getString("removeAll.accesskey"));
|
||||
|
||||
setEventListener("hostCol", "click", this.onClickTreeCol);
|
||||
setEventListener("usageCol", "click", this.onClickTreeCol);
|
||||
setEventListener("statusCol", "click", this.onClickTreeCol);
|
||||
@ -64,9 +61,15 @@ let gSiteDataSettings = {
|
||||
let removeAllBtn = document.getElementById("removeAll");
|
||||
removeSelectedBtn.disabled = items.length == 0;
|
||||
removeAllBtn.disabled = removeSelectedBtn.disabled;
|
||||
let removeAllBtnLabel = this._searchBox.value ?
|
||||
this._prefStrBundle.getString("removeAllShown.label") : this._prefStrBundle.getString("removeAll.label");
|
||||
removeAllBtn.setAttribute("label", removeAllBtnLabel);
|
||||
|
||||
let removeAllBtnLabelStringID = "removeAllSiteData.label";
|
||||
let removeAllBtnAccesskeyStringID = "removeAllSiteData.accesskey";
|
||||
if (this._searchBox.value) {
|
||||
removeAllBtnLabelStringID = "removeAllSiteDataShown.label";
|
||||
removeAllBtnAccesskeyStringID = "removeAllSiteDataShown.accesskey";
|
||||
}
|
||||
removeAllBtn.setAttribute("label", this._prefStrBundle.getString(removeAllBtnLabelStringID));
|
||||
removeAllBtn.setAttribute("accesskey", this._prefStrBundle.getString(removeAllBtnAccesskeyStringID));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr, manager: Cm} = Compo
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileAutoCompleteResult",
|
||||
"resource://formautofill/ProfileAutoCompleteResult.jsm");
|
||||
@ -67,7 +68,7 @@ AutocompleteFactory.prototype = {
|
||||
* @implements {nsIAutoCompleteSearch}
|
||||
*/
|
||||
function AutofillProfileAutoCompleteSearch() {
|
||||
|
||||
FormAutofillUtils.defineLazyLogGetter(this, "AutofillProfileAutoCompleteSearch");
|
||||
}
|
||||
AutofillProfileAutoCompleteSearch.prototype = {
|
||||
classID: Components.ID("4f9f1e4c-7f2c-439e-9c9e-566b68bc187d"),
|
||||
@ -87,6 +88,7 @@ AutofillProfileAutoCompleteSearch.prototype = {
|
||||
* @param {Object} listener the listener to notify when the search is complete
|
||||
*/
|
||||
startSearch(searchString, searchParam, previousResult, listener) {
|
||||
this.log.debug("startSearch: for", searchString, "with input", formFillController.focusedInput);
|
||||
let focusedInput = formFillController.focusedInput;
|
||||
this.forceStop = false;
|
||||
let info = this._serializeInfo(FormAutofillContent.getInputDetails(focusedInput));
|
||||
@ -130,6 +132,7 @@ AutofillProfileAutoCompleteSearch.prototype = {
|
||||
* Promise that resolves when profiles returned from parent process.
|
||||
*/
|
||||
_getProfiles(data) {
|
||||
this.log.debug("_getProfiles with data:", data);
|
||||
return new Promise((resolve) => {
|
||||
Services.cpmm.addMessageListener("FormAutofill:Profiles", function getResult(result) {
|
||||
Services.cpmm.removeMessageListener("FormAutofill:Profiles", getResult);
|
||||
@ -161,6 +164,8 @@ let ProfileAutocomplete = {
|
||||
return;
|
||||
}
|
||||
|
||||
FormAutofillUtils.defineLazyLogGetter(this, "ProfileAutocomplete");
|
||||
this.log.debug("ensureRegistered");
|
||||
this._factory = new AutocompleteFactory();
|
||||
this._factory.register(AutofillProfileAutoCompleteSearch);
|
||||
this._registered = true;
|
||||
@ -173,6 +178,7 @@ let ProfileAutocomplete = {
|
||||
return;
|
||||
}
|
||||
|
||||
this.log.debug("ensureUnregistered");
|
||||
this._factory.unregister();
|
||||
this._factory = null;
|
||||
this._registered = false;
|
||||
@ -206,6 +212,7 @@ let ProfileAutocomplete = {
|
||||
},
|
||||
|
||||
_fillFromAutocompleteRow(focusedInput) {
|
||||
this.log.debug("_fillFromAutocompleteRow:", focusedInput);
|
||||
let formDetails = FormAutofillContent.getFormDetails(focusedInput);
|
||||
if (!formDetails) {
|
||||
// The observer notification is for a different frame.
|
||||
@ -250,11 +257,13 @@ let ProfileAutocomplete = {
|
||||
*/
|
||||
var FormAutofillContent = {
|
||||
/**
|
||||
* @type {WeakMap} mapping FormLike root HTML elements to form details.
|
||||
* @type {WeakMap} mapping FormLike root HTML elements to FormAutofillHandler objects.
|
||||
*/
|
||||
_formsDetails: new WeakMap(),
|
||||
|
||||
init() {
|
||||
FormAutofillUtils.defineLazyLogGetter(this, "FormAutofillContent");
|
||||
|
||||
Services.cpmm.addMessageListener("FormAutofill:enabledStatus", (result) => {
|
||||
if (result.data) {
|
||||
ProfileAutocomplete.ensureRegistered();
|
||||
@ -306,6 +315,7 @@ var FormAutofillContent = {
|
||||
},
|
||||
|
||||
_identifyAutofillFields(doc) {
|
||||
this.log.debug("_identifyAutofillFields:", "" + doc.location);
|
||||
let forms = [];
|
||||
|
||||
// Collects root forms from inputs.
|
||||
@ -322,18 +332,22 @@ var FormAutofillContent = {
|
||||
}
|
||||
}
|
||||
|
||||
this.log.debug("Found", forms.length, "forms");
|
||||
|
||||
// Collects the fields that can be autofilled from each form and marks them
|
||||
// as autofill fields if the amount is above the threshold.
|
||||
forms.forEach(form => {
|
||||
let formHandler = new FormAutofillHandler(form);
|
||||
formHandler.collectFormFields();
|
||||
if (formHandler.fieldDetails.length < AUTOFILL_FIELDS_THRESHOLD) {
|
||||
this.log.debug("Ignoring form since it has only", formHandler.fieldDetails.length,
|
||||
"field(s)");
|
||||
return;
|
||||
}
|
||||
|
||||
this._formsDetails.set(form.rootElement, formHandler);
|
||||
formHandler.fieldDetails.forEach(
|
||||
detail => this._markAsAutofillField(detail.element));
|
||||
this.log.debug("Adding form handler to _formsDetails:", formHandler);
|
||||
formHandler.fieldDetails.forEach(detail => this._markAsAutofillField(detail.element));
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -14,9 +14,14 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillHeuristics",
|
||||
"resource://formautofill/FormAutofillHeuristics.jsm");
|
||||
|
||||
this.log = null;
|
||||
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
|
||||
|
||||
/**
|
||||
* Handles profile autofill for a DOM Form element.
|
||||
* @param {FormLike} form Form that need to be auto filled
|
||||
@ -71,6 +76,7 @@ FormAutofillHandler.prototype = {
|
||||
f.contactType == info.contactType &&
|
||||
f.fieldName == info.fieldName)) {
|
||||
// A field with the same identifier already exists.
|
||||
log.debug("Not collecting a field matching another with the same info:", info);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -90,6 +96,8 @@ FormAutofillHandler.prototype = {
|
||||
this.fieldDetails.push(formatWithElement);
|
||||
}
|
||||
|
||||
log.debug("Collected details on", autofillData.length, "fields");
|
||||
|
||||
return autofillData;
|
||||
},
|
||||
|
||||
@ -110,6 +118,7 @@ FormAutofillHandler.prototype = {
|
||||
* }
|
||||
*/
|
||||
autofillFormFields(autofillResult) {
|
||||
log.debug("autofillFormFields:", autofillResult);
|
||||
for (let field of autofillResult) {
|
||||
// TODO: Skip filling the value of focused input which is filled in
|
||||
// FormFillController.
|
||||
|
@ -29,12 +29,16 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["FormAutofillParent"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProfileStorage",
|
||||
@ -42,6 +46,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "ProfileStorage",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillPreferences",
|
||||
"resource://formautofill/FormAutofillPreferences.jsm");
|
||||
|
||||
this.log = null;
|
||||
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
|
||||
|
||||
const PROFILE_JSON_FILE_NAME = "autofill-profiles.json";
|
||||
const ENABLED_PREF = "browser.formautofill.enabled";
|
||||
|
||||
@ -63,6 +70,7 @@ FormAutofillParent.prototype = {
|
||||
* Initializes ProfileStorage and registers the message handler.
|
||||
*/
|
||||
init() {
|
||||
log.debug("init");
|
||||
let storePath = OS.Path.join(OS.Constants.Path.profileDir, PROFILE_JSON_FILE_NAME);
|
||||
this._profileStore = new ProfileStorage(storePath);
|
||||
this._profileStore.initialize();
|
||||
@ -79,6 +87,7 @@ FormAutofillParent.prototype = {
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
log.debug("observe:", topic, "with data:", data);
|
||||
switch (topic) {
|
||||
case "advanced-pane-loaded": {
|
||||
let formAutofillPreferences = new FormAutofillPreferences();
|
||||
@ -111,6 +120,7 @@ FormAutofillParent.prototype = {
|
||||
* form autofill status changed.
|
||||
*/
|
||||
_onStatusChanged() {
|
||||
log.debug("_onStatusChanged: Status changed to", this._enabled);
|
||||
if (this._enabled) {
|
||||
Services.ppmm.addMessageListener("FormAutofill:GetProfiles", this);
|
||||
} else {
|
||||
@ -199,5 +209,3 @@ FormAutofillParent.prototype = {
|
||||
target.sendAsyncMessage("FormAutofill:Profiles", profiles);
|
||||
},
|
||||
};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["FormAutofillParent"];
|
||||
|
@ -6,7 +6,21 @@
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["FormAutofillUtils"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
this.FormAutofillUtils = {
|
||||
defineLazyLogGetter(scope, logPrefix) {
|
||||
XPCOMUtils.defineLazyGetter(scope, "log", () => {
|
||||
let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
|
||||
return new ConsoleAPI({
|
||||
maxLogLevelPref: "browser.formautofill.loglevel",
|
||||
prefix: logPrefix,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
generateFullName(firstName, lastName, middleName) {
|
||||
// TODO: The implementation should depend on the L10N spec, but a simplified
|
||||
// rule is used here.
|
||||
|
@ -9,15 +9,18 @@ this.EXPORTED_SYMBOLS = ["ProfileAutoCompleteResult"];
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
this.log = null;
|
||||
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillUtils",
|
||||
"resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
this.ProfileAutoCompleteResult = function(searchString,
|
||||
focusedFieldName,
|
||||
allFieldNames,
|
||||
matchingProfiles,
|
||||
{resultCode = null}) {
|
||||
log.debug("Constructing new ProfileAutoCompleteResult:", [...arguments]);
|
||||
this.searchString = searchString;
|
||||
this._focusedFieldName = focusedFieldName;
|
||||
this._allFieldNames = allFieldNames;
|
||||
|
@ -39,12 +39,16 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ProfileStorage"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
|
||||
"resource://gre/modules/JSONFile.jsm");
|
||||
|
||||
@ -52,6 +56,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
this.log = null;
|
||||
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
|
||||
|
||||
const SCHEMA_VERSION = 1;
|
||||
|
||||
// Name-related fields will be handled in follow-up bugs due to the complexity.
|
||||
@ -107,6 +114,7 @@ ProfileStorage.prototype = {
|
||||
* The new profile for saving.
|
||||
*/
|
||||
add(profile) {
|
||||
log.debug("add:", profile);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let profileToSave = this._normalizeProfile(profile);
|
||||
@ -135,6 +143,7 @@ ProfileStorage.prototype = {
|
||||
* The new profile used to overwrite the old one.
|
||||
*/
|
||||
update(guid, profile) {
|
||||
log.debug("update:", guid, profile);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let profileFound = this._findByGUID(guid);
|
||||
@ -184,6 +193,7 @@ ProfileStorage.prototype = {
|
||||
* Indicates which profile to remove.
|
||||
*/
|
||||
remove(guid) {
|
||||
log.debug("remove:", guid);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
this._store.data.profiles =
|
||||
@ -200,6 +210,7 @@ ProfileStorage.prototype = {
|
||||
* A clone of the profile.
|
||||
*/
|
||||
get(guid) {
|
||||
log.debug("get:", guid);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
let profileFound = this._findByGUID(guid);
|
||||
@ -218,6 +229,7 @@ ProfileStorage.prototype = {
|
||||
* An array containing clones of all profiles.
|
||||
*/
|
||||
getAll() {
|
||||
log.debug("getAll");
|
||||
this._store.ensureDataReady();
|
||||
|
||||
// Profiles are cloned to avoid accidental modifications from outside.
|
||||
@ -231,10 +243,13 @@ ProfileStorage.prototype = {
|
||||
* An array containing clones of matched profiles.
|
||||
*/
|
||||
getByFilter({info, searchString}) {
|
||||
log.debug("getByFilter:", info, searchString);
|
||||
this._store.ensureDataReady();
|
||||
|
||||
// Profiles are cloned to avoid accidental modifications from outside.
|
||||
return this._findByFilter({info, searchString}).map(this._clone);
|
||||
let result = this._findByFilter({info, searchString}).map(this._clone);
|
||||
log.debug("getByFilter: Returning", result.length, "result(s)");
|
||||
return result;
|
||||
},
|
||||
|
||||
_clone(profile) {
|
||||
@ -291,5 +306,3 @@ ProfileStorage.prototype = {
|
||||
return this._store._save();
|
||||
},
|
||||
};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ProfileStorage"];
|
||||
|
@ -636,6 +636,7 @@
|
||||
@RESPATH@/greprefs.js
|
||||
@RESPATH@/defaults/autoconfig/prefcalls.js
|
||||
@RESPATH@/browser/defaults/permissions
|
||||
@RESPATH@/browser/defaults/blocklists
|
||||
|
||||
; Warning: changing the path to channel-prefs.js can cause bugs (Bug 756325)
|
||||
; Technically this is an app pref file, but we are keeping it in the original
|
||||
|
@ -125,12 +125,15 @@ cookiesAll=The following cookies are stored on your computer:
|
||||
cookiesFiltered=The following cookies match your search:
|
||||
|
||||
# LOCALIZATION NOTE (removeAllCookies, removeAllShownCookies):
|
||||
# removeAllCookies and removeAllShownCookies are both used on the same one button,
|
||||
# never displayed together and can share the same accesskey.
|
||||
# When only partial cookies are shown as a result of keyword search,
|
||||
# removeAllShownCookies is displayed as button label.
|
||||
# removeAllCookies is displayed when no keyword search and all cookies are shown.
|
||||
removeAllCookies.label=Remove All
|
||||
removeAllShownCookies.label=Remove All Shown
|
||||
removeAllCookies.accesskey=A
|
||||
removeAllShownCookies.label=Remove All Shown
|
||||
removeAllShownCookies.accesskey=A
|
||||
|
||||
# LOCALIZATION NOTE (removeSelectedCookies):
|
||||
# Semicolon-separated list of plural forms. See:
|
||||
@ -187,13 +190,16 @@ clearSiteDataNow=Clear Now
|
||||
important=Important
|
||||
default=Default
|
||||
siteUsage=%1$S %2$S
|
||||
# LOCALIZATION NOTE (removeAll, removeAllShown):
|
||||
# LOCALIZATION NOTE (removeAllSiteData, removeAllSiteDataShown):
|
||||
# removeAllSiteData and removeAllSiteDataShown are both used on the same one button,
|
||||
# never displayed together and can share the same accesskey.
|
||||
# When only partial sites are shown as a result of keyword search,
|
||||
# removeAllShown is displayed as button label.
|
||||
# removeAll is displayed when no keyword search and all sites are shown.
|
||||
removeAll.label=Remove All
|
||||
removeAllShown.label=Remove All Shown
|
||||
removeAll.accesskey=e
|
||||
removeAllSiteData.label=Remove All
|
||||
removeAllSiteData.accesskey=e
|
||||
removeAllSiteDataShown.label=Remove All Shown
|
||||
removeAllSiteDataShown.accesskey=e
|
||||
|
||||
# LOCALIZATION NOTE (featureEnableRequiresRestart, featureDisableRequiresRestart, restartTitle): %S = brandShortName
|
||||
featureEnableRequiresRestart=%S must restart to enable this feature.
|
||||
|
32
build/gen_test_backend.py
Normal file
32
build/gen_test_backend.py
Normal file
@ -0,0 +1,32 @@
|
||||
# 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/.
|
||||
|
||||
import sys
|
||||
|
||||
from mozbuild.backend.test_manifest import TestManifestBackend
|
||||
from mozbuild.base import BuildEnvironmentNotFoundException, MozbuildObject
|
||||
from mozbuild.frontend.emitter import TreeMetadataEmitter
|
||||
from mozbuild.frontend.reader import BuildReader, EmptyConfig
|
||||
|
||||
|
||||
def gen_test_backend():
|
||||
build_obj = MozbuildObject.from_environment()
|
||||
try:
|
||||
config = build_obj.config_environment
|
||||
except BuildEnvironmentNotFoundException:
|
||||
print("No build detected, test metadata may be incomplete.")
|
||||
config = EmptyConfig(build_obj.topsrcdir)
|
||||
config.topobjdir = build_obj.topobjdir
|
||||
|
||||
reader = BuildReader(config)
|
||||
emitter = TreeMetadataEmitter(config)
|
||||
backend = TestManifestBackend(config)
|
||||
|
||||
context = reader.read_topsrcdir()
|
||||
data = emitter.emit(context, emitfn=emitter._process_test_manifests)
|
||||
backend.consume(data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(gen_test_backend())
|
@ -25,9 +25,7 @@ $(subst .,%,$(BUILD_BACKEND_FILES)):
|
||||
$(PYTHON) $(BACKEND_GENERATION_SCRIPT)
|
||||
|
||||
define build_backend_rule
|
||||
$(1)_files := $$(shell cat $(1).in)
|
||||
$(1): $$($(1)_files)
|
||||
$$($(1)_files):
|
||||
$(1): $$(wildcard $$(shell cat $(1).in))
|
||||
|
||||
endef
|
||||
$(foreach file,$(BUILD_BACKEND_FILES),$(eval $(call build_backend_rule,$(file))))
|
||||
|
@ -307,7 +307,7 @@ Tools.netMonitor = {
|
||||
visibilityswitch: "devtools.netmonitor.enabled",
|
||||
icon: "chrome://devtools/skin/images/tool-network.svg",
|
||||
invertIconForDarkTheme: true,
|
||||
url: "chrome://devtools/content/netmonitor/netmonitor.xul",
|
||||
url: "chrome://devtools/content/netmonitor/netmonitor.xhtml",
|
||||
label: l10n("netmonitor.label"),
|
||||
panelLabel: l10n("netmonitor.panelLabel"),
|
||||
get tooltip() {
|
||||
|
@ -24,7 +24,6 @@ add_task(function* () {
|
||||
|
||||
let monitor = yield toolbox.selectTool("netmonitor");
|
||||
let { gStore, windowRequire } = monitor.panelWin;
|
||||
let Actions = windowRequire("devtools/client/netmonitor/actions/index");
|
||||
|
||||
is(gStore.getState().requests.requests.size, 0, "No network requests appear in the network panel");
|
||||
|
||||
|
@ -10,6 +10,17 @@ module.exports = {
|
||||
// code. Some files in the inspector disable this rule still. The
|
||||
// goal is to enable the rule globally on all files.
|
||||
/* eslint-disable max-len */
|
||||
"mozilla/reject-some-requires": ["error", "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
"mozilla/reject-some-requires": ["error",
|
||||
"^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm|devtools/shared/platform/(chome|content)/.*)$"],
|
||||
|
||||
// The webpack bundle does not support trailing commas in functions, so disabled it
|
||||
// explicitly with linting here.
|
||||
"comma-dangle": ["error", {
|
||||
"arrays": "ignore",
|
||||
"objects": "ignore",
|
||||
"imports": "ignore",
|
||||
"exports": "ignore",
|
||||
"functions": "never",
|
||||
}]
|
||||
},
|
||||
};
|
||||
|
@ -54,8 +54,7 @@ module.exports = createClass({
|
||||
boxModel,
|
||||
})
|
||||
:
|
||||
null,
|
||||
null
|
||||
);
|
||||
},
|
||||
|
||||
});
|
||||
|
@ -65,15 +65,15 @@ module.exports = createClass({
|
||||
className: "boxmodel-properties-expander theme-twisty",
|
||||
open: this.state.isOpen,
|
||||
onClick: this.onToggleExpander,
|
||||
},
|
||||
}
|
||||
),
|
||||
dom.span(
|
||||
{
|
||||
className: "boxmodel-properties-label",
|
||||
title: BOXMODEL_L10N.getStr("boxmodel.propertiesLabel"),
|
||||
},
|
||||
BOXMODEL_L10N.getStr("boxmodel.propertiesLabel"),
|
||||
),
|
||||
BOXMODEL_L10N.getStr("boxmodel.propertiesLabel")
|
||||
)
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
@ -81,8 +81,8 @@ module.exports = createClass({
|
||||
hidden: !this.state.isOpen,
|
||||
tabIndex: 0,
|
||||
},
|
||||
properties,
|
||||
),
|
||||
properties
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
},
|
||||
"author": "",
|
||||
"dependencies": {
|
||||
"devtools-launchpad": "0.0.29",
|
||||
"devtools-launchpad": "=0.0.43",
|
||||
"raw-loader": "^0.5.1",
|
||||
"json-loader": "^0.5.4"
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ add_task(function* () {
|
||||
function* isHiddenByDefault({isElementHidden}) {
|
||||
info("Checking the highlighter is hidden by default");
|
||||
|
||||
let hidden = yield isElementHidden("elements");
|
||||
let hidden = yield isElementHidden("root");
|
||||
ok(hidden, "highlighter's root is hidden by default");
|
||||
|
||||
hidden = yield isElementHidden("label-size");
|
||||
|
@ -9,22 +9,15 @@
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,<div>zoom me</div>";
|
||||
|
||||
// TEST_LEVELS entries should contain the following properties:
|
||||
// - level: the zoom level to test
|
||||
// - expected: the style attribute value to check for on the root highlighter
|
||||
// element.
|
||||
const TEST_LEVELS = [{
|
||||
level: 2,
|
||||
expected: "position:absolute;transform-origin:top left;" +
|
||||
"transform:scale(0.5);width:200%;height:200%;"
|
||||
}, {
|
||||
level: 1,
|
||||
expected: "position:absolute;width:100%;height:100%;"
|
||||
}, {
|
||||
level: .5,
|
||||
expected: "position:absolute;transform-origin:top left;" +
|
||||
"transform:scale(2);width:50%;height:50%;"
|
||||
}];
|
||||
// TEST_LEVELS entries should contain the zoom level to test.
|
||||
const TEST_LEVELS = [2, 1, .5];
|
||||
|
||||
// Returns the expected style attribute value to check for on the root highlighter
|
||||
// element, for the values given.
|
||||
const expectedStyle = (w, h, z) =>
|
||||
(z !== 1 ? `transform-origin:top left; transform:scale(${1 / z}); ` : "") +
|
||||
`position:absolute; width:${w * z}px;height:${h * z}px; ` +
|
||||
"overflow:hidden";
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
|
||||
@ -35,7 +28,7 @@ add_task(function* () {
|
||||
let isVisible = yield testActor.isHighlighting();
|
||||
ok(isVisible, "The highlighter is visible");
|
||||
|
||||
for (let {level, expected} of TEST_LEVELS) {
|
||||
for (let level of TEST_LEVELS) {
|
||||
info("Zoom to level " + level +
|
||||
" and check that the highlighter is correct");
|
||||
|
||||
@ -48,7 +41,9 @@ add_task(function* () {
|
||||
info("Check that the highlighter root wrapper node was scaled down");
|
||||
|
||||
let style = yield getRootNodeStyle(testActor);
|
||||
is(style, expected, "The style attribute of the root element is correct");
|
||||
let { width, height } = yield testActor.getWindowDimensions();
|
||||
is(style, expectedStyle(width, height, level),
|
||||
"The style attribute of the root element is correct");
|
||||
}
|
||||
});
|
||||
|
||||
|
4004
devtools/client/inspector/yarn.lock
Normal file
4004
devtools/client/inspector/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ devtools.jar:
|
||||
content/shared/widgets/VariablesView.xul (shared/widgets/VariablesView.xul)
|
||||
content/projecteditor/chrome/content/projecteditor.xul (projecteditor/chrome/content/projecteditor.xul)
|
||||
content/projecteditor/lib/helpers/readdir.js (projecteditor/lib/helpers/readdir.js)
|
||||
content/netmonitor/netmonitor.xul (netmonitor/netmonitor.xul)
|
||||
content/netmonitor/netmonitor.xhtml (netmonitor/netmonitor.xhtml)
|
||||
content/netmonitor/netmonitor.js (netmonitor/netmonitor.js)
|
||||
content/webconsole/webconsole.xul (webconsole/webconsole.xul)
|
||||
* content/scratchpad/scratchpad.xul (scratchpad/scratchpad.xul)
|
||||
|
@ -5,6 +5,10 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
},
|
||||
|
||||
// Extend from the devtools eslintrc.
|
||||
"extends": "../../.eslintrc.js",
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
@ -48,7 +46,7 @@ function cloneSelectedRequest() {
|
||||
* Send a new HTTP request using the data in the custom request form.
|
||||
*/
|
||||
function sendCustomRequest() {
|
||||
if (!NetMonitorController.supportsCustomRequest) {
|
||||
if (!window.NetMonitorController.supportsCustomRequest) {
|
||||
return cloneSelectedRequest();
|
||||
}
|
||||
|
||||
@ -72,7 +70,7 @@ function sendCustomRequest() {
|
||||
data.body = selected.requestPostData.postData.text;
|
||||
}
|
||||
|
||||
NetMonitorController.webConsoleClient.sendHTTPRequest(data, (response) => {
|
||||
window.NetMonitorController.webConsoleClient.sendHTTPRequest(data, (response) => {
|
||||
return dispatch({
|
||||
type: SEND_CUSTOM_REQUEST,
|
||||
id: response.eventActor.actor,
|
||||
|
@ -5,6 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
ACTIVITY_TYPE,
|
||||
OPEN_NETWORK_DETAILS,
|
||||
OPEN_STATISTICS,
|
||||
SELECT_DETAILS_PANEL_TAB,
|
||||
@ -29,6 +30,9 @@ function openNetworkDetails(open) {
|
||||
* @param {boolean} visible - expected performance statistics panel open state
|
||||
*/
|
||||
function openStatistics(open) {
|
||||
if (open) {
|
||||
window.NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
|
||||
}
|
||||
return {
|
||||
type: OPEN_STATISTICS,
|
||||
open,
|
||||
|
136
devtools/client/netmonitor/components/monitor-panel.js
Normal file
136
devtools/client/netmonitor/components/monitor-panel.js
Normal file
@ -0,0 +1,136 @@
|
||||
/* 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 {
|
||||
createClass,
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
|
||||
const Actions = require("../actions/index");
|
||||
const { Prefs } = require("../prefs");
|
||||
const { getFormDataSections } = require("../request-utils");
|
||||
const { getSelectedRequest } = require("../selectors/index");
|
||||
|
||||
// Components
|
||||
const SplitBox = createFactory(require("devtools/client/shared/components/splitter/split-box"));
|
||||
const NetworkDetailsPanel = createFactory(require("../shared/components/network-details-panel"));
|
||||
const RequestList = createFactory(require("./request-list"));
|
||||
const Toolbar = createFactory(require("./toolbar"));
|
||||
|
||||
const { div } = DOM;
|
||||
const MediaQueryList = window.matchMedia("(min-width: 700px)");
|
||||
|
||||
/*
|
||||
* Monitor panel component
|
||||
* The main panel for displaying various network request information
|
||||
*/
|
||||
const MonitorPanel = createClass({
|
||||
displayName: "MonitorPanel",
|
||||
|
||||
propTypes: {
|
||||
isEmpty: PropTypes.bool.isRequired,
|
||||
networkDetailsOpen: PropTypes.bool.isRequired,
|
||||
openNetworkDetails: PropTypes.func.isRequired,
|
||||
request: PropTypes.object,
|
||||
updateRequest: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
isVerticalSpliter: MediaQueryList.matches,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
MediaQueryList.addListener(this.onLayoutChange);
|
||||
},
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
let {
|
||||
request = {},
|
||||
updateRequest,
|
||||
} = nextProps;
|
||||
let {
|
||||
formDataSections,
|
||||
requestHeaders,
|
||||
requestHeadersFromUploadStream,
|
||||
requestPostData,
|
||||
} = request;
|
||||
|
||||
if (!formDataSections && requestHeaders &&
|
||||
requestHeadersFromUploadStream && requestPostData) {
|
||||
getFormDataSections(
|
||||
requestHeaders,
|
||||
requestHeadersFromUploadStream,
|
||||
requestPostData,
|
||||
window.gNetwork.getString.bind(window.gNetwork),
|
||||
).then((newFormDataSections) => {
|
||||
updateRequest(
|
||||
request.id,
|
||||
{ formDataSections: newFormDataSections },
|
||||
true,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
MediaQueryList.removeListener(this.onLayoutChange);
|
||||
let { clientWidth, clientHeight } = findDOMNode(this.refs.networkDetailsPanel) || {};
|
||||
|
||||
if (this.state.isVerticalSpliter && clientWidth) {
|
||||
Prefs.networkDetailsWidth = clientWidth;
|
||||
} else if (clientHeight) {
|
||||
Prefs.networkDetailsHeight = clientHeight;
|
||||
}
|
||||
},
|
||||
|
||||
onLayoutChange() {
|
||||
this.setState({
|
||||
isVerticalSpliter: MediaQueryList.matches,
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
let { isEmpty, networkDetailsOpen } = this.props;
|
||||
return (
|
||||
div({ className: "monitor-panel" },
|
||||
Toolbar(),
|
||||
SplitBox({
|
||||
className: "devtools-responsive-container",
|
||||
initialWidth: `${Prefs.networkDetailsWidth}px`,
|
||||
initialHeight: `${Prefs.networkDetailsHeight}px`,
|
||||
minSize: "50px",
|
||||
maxSize: "80%",
|
||||
splitterSize: "1px",
|
||||
startPanel: RequestList({ isEmpty }),
|
||||
endPanel: networkDetailsOpen ?
|
||||
NetworkDetailsPanel({
|
||||
ref: "networkDetailsPanel",
|
||||
toolbox: window.NetMonitorController._toolbox,
|
||||
}) : null,
|
||||
endPanelControl: true,
|
||||
vert: this.state.isVerticalSpliter,
|
||||
}),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
isEmpty: state.requests.requests.isEmpty(),
|
||||
networkDetailsOpen: state.ui.networkDetailsOpen,
|
||||
request: getSelectedRequest(state),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
openNetworkDetails: (open) => dispatch(Actions.openNetworkDetails(open)),
|
||||
updateRequest: (id, data, batch) => dispatch(Actions.updateRequest(id, data, batch)),
|
||||
}),
|
||||
)(MonitorPanel);
|
@ -3,12 +3,12 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'monitor-panel.js',
|
||||
'network-monitor.js',
|
||||
'request-list-content.js',
|
||||
'request-list-context-menu.js',
|
||||
'request-list-empty.js',
|
||||
'request-list-header.js',
|
||||
'request-list-item.js',
|
||||
'request-list-tooltip.js',
|
||||
'request-list.js',
|
||||
'statistics-panel.js',
|
||||
'toolbar.js',
|
||||
|
39
devtools/client/netmonitor/components/network-monitor.js
Normal file
39
devtools/client/netmonitor/components/network-monitor.js
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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 {
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
// Components
|
||||
const MonitoPanel = createFactory(require("./monitor-panel"));
|
||||
const StatisticsPanel = createFactory(require("./statistics-panel"));
|
||||
|
||||
const { div } = DOM;
|
||||
|
||||
/*
|
||||
* Network monitor component
|
||||
*/
|
||||
function NetworkMonitor({ statisticsOpen }) {
|
||||
return (
|
||||
div({ className: "network-monitor" },
|
||||
!statisticsOpen ? MonitoPanel() : StatisticsPanel()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
NetworkMonitor.displayName = "NetworkMonitor";
|
||||
|
||||
NetworkMonitor.propTypes = {
|
||||
statisticsOpen: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({ statisticsOpen: state.ui.statisticsOpen }),
|
||||
)(NetworkMonitor);
|
@ -2,8 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
||||
@ -15,12 +13,11 @@ const {
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const Actions = require("../actions/index");
|
||||
const {
|
||||
setTooltipImageContent,
|
||||
setTooltipStackTraceContent,
|
||||
} = require("./request-list-tooltip");
|
||||
} = require("../request-list-tooltip");
|
||||
const {
|
||||
getDisplayedRequests,
|
||||
getWaterfallScale,
|
||||
@ -28,7 +25,7 @@ const {
|
||||
|
||||
// Components
|
||||
const RequestListItem = createFactory(require("./request-list-item"));
|
||||
const RequestListContextMenu = require("./request-list-context-menu");
|
||||
const RequestListContextMenu = require("../request-list-context-menu");
|
||||
|
||||
const { div } = DOM;
|
||||
|
||||
@ -42,7 +39,6 @@ const RequestListContent = createClass({
|
||||
displayName: "RequestListContent",
|
||||
|
||||
propTypes: {
|
||||
contextMenu: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
displayedRequests: PropTypes.object.isRequired,
|
||||
firstRequestStartedMillis: PropTypes.number.isRequired,
|
||||
@ -51,11 +47,6 @@ const RequestListContent = createClass({
|
||||
onSelectDelta: PropTypes.func.isRequired,
|
||||
scale: PropTypes.number,
|
||||
selectedRequestId: PropTypes.string,
|
||||
tooltip: PropTypes.shape({
|
||||
hide: PropTypes.func.isRequired,
|
||||
startTogglingOnHover: PropTypes.func.isRequired,
|
||||
stopTogglingOnHover: PropTypes.func.isRequired,
|
||||
}).isRequired
|
||||
},
|
||||
|
||||
componentWillMount() {
|
||||
@ -64,7 +55,10 @@ const RequestListContent = createClass({
|
||||
cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
|
||||
openStatistics: (open) => dispatch(Actions.openStatistics(open)),
|
||||
});
|
||||
this.tooltip = new HTMLTooltip(NetMonitorController._toolbox.doc, { type: "arrow" });
|
||||
this.tooltip = new HTMLTooltip(
|
||||
window.NetMonitorController._toolbox.doc,
|
||||
{ type: "arrow" }
|
||||
);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
@ -150,7 +144,7 @@ const RequestListContent = createClass({
|
||||
* The current tooltip instance.
|
||||
* @return {Promise}
|
||||
*/
|
||||
onHover: Task.async(function* (target, tooltip) {
|
||||
onHover(target, tooltip) {
|
||||
let itemEl = target.closest(".request-list-item");
|
||||
if (!itemEl) {
|
||||
return false;
|
||||
@ -171,7 +165,7 @@ const RequestListContent = createClass({
|
||||
}
|
||||
|
||||
return false;
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Scroll listener for the requests menu view.
|
||||
@ -231,15 +225,6 @@ const RequestListContent = createClass({
|
||||
this.shouldScrollBottom = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* If a focused item was unmounted, transfer the focus to the container element.
|
||||
*/
|
||||
onFocusedNodeUnmount() {
|
||||
if (this.refs.contentEl) {
|
||||
this.refs.contentEl.focus();
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
displayedRequests,
|
||||
@ -257,15 +242,14 @@ const RequestListContent = createClass({
|
||||
onKeyDown: this.onKeyDown,
|
||||
},
|
||||
displayedRequests.map((item, index) => RequestListItem({
|
||||
key: item.id,
|
||||
firstRequestStartedMillis,
|
||||
item,
|
||||
index,
|
||||
isSelected: item.id === selectedRequestId,
|
||||
firstRequestStartedMillis,
|
||||
onMouseDown: () => onItemMouseDown(item.id),
|
||||
key: item.id,
|
||||
onContextMenu: this.onContextMenu,
|
||||
onFocusedNodeChange: this.onFocusedNodeChange,
|
||||
onFocusedNodeUnmount: this.onFocusedNodeUnmount,
|
||||
onMouseDown: () => onItemMouseDown(item.id),
|
||||
onSecurityIconClick: () => onSecurityIconClick(item.securityState),
|
||||
}))
|
||||
)
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
@ -69,6 +67,7 @@ module.exports = connect(
|
||||
dispatch => ({
|
||||
onPerfClick: () => dispatch(Actions.openStatistics(true)),
|
||||
onReloadClick: () =>
|
||||
NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
|
||||
window.NetMonitorController
|
||||
.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
|
||||
})
|
||||
)(RequestListEmptyNotice);
|
||||
|
@ -2,14 +2,12 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals document */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react");
|
||||
const { div, button } = DOM;
|
||||
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { setNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { L10N } = require("../l10n");
|
||||
const { getWaterfallScale } = require("../selectors/index");
|
||||
const Actions = require("../actions/index");
|
||||
@ -50,19 +48,11 @@ const RequestListHeader = createClass({
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
// This is the first time the waterfall column header is actually rendered.
|
||||
// Measure its width and update the 'waterfallWidth' property in the store.
|
||||
// The 'waterfallWidth' will be further updated on every window resize.
|
||||
const waterfallHeaderEl = findDOMNode(this)
|
||||
.querySelector("#requests-menu-waterfall-header-box");
|
||||
if (waterfallHeaderEl) {
|
||||
const { width } = waterfallHeaderEl.getBoundingClientRect();
|
||||
this.props.resizeWaterfall(width);
|
||||
}
|
||||
|
||||
// Create the object that takes care of drawing the waterfall canvas background
|
||||
this.background = new WaterfallBackground(document);
|
||||
this.background.draw(this.props);
|
||||
this.resizeWaterfall();
|
||||
window.addEventListener("resize", this.resizeWaterfall);
|
||||
},
|
||||
|
||||
componentDidUpdate() {
|
||||
@ -72,6 +62,16 @@ const RequestListHeader = createClass({
|
||||
componentWillUnmount() {
|
||||
this.background.destroy();
|
||||
this.background = null;
|
||||
window.removeEventListener("resize", this.resizeWaterfall);
|
||||
},
|
||||
|
||||
resizeWaterfall() {
|
||||
// Measure its width and update the 'waterfallWidth' property in the store.
|
||||
// The 'waterfallWidth' will be further updated on every window resize.
|
||||
setNamedTimeout("resize-events", 50, () => {
|
||||
const { width } = this.refs.header.getBoundingClientRect();
|
||||
this.props.resizeWaterfall(width);
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
@ -97,8 +97,9 @@ const RequestListHeader = createClass({
|
||||
return div(
|
||||
{
|
||||
id: `requests-menu-${boxName}-header-box`,
|
||||
key: name,
|
||||
className: `requests-menu-header requests-menu-${boxName}`,
|
||||
key: name,
|
||||
ref: "header",
|
||||
// Used to style the next column.
|
||||
"data-active": active,
|
||||
},
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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 react/prop-types */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
@ -69,7 +67,6 @@ const RequestListItem = createClass({
|
||||
firstRequestStartedMillis: PropTypes.number.isRequired,
|
||||
onContextMenu: PropTypes.func.isRequired,
|
||||
onFocusedNodeChange: PropTypes.func,
|
||||
onFocusedNodeUnmount: PropTypes.func,
|
||||
onMouseDown: PropTypes.func.isRequired,
|
||||
onSecurityIconClick: PropTypes.func.isRequired,
|
||||
},
|
||||
@ -94,20 +91,6 @@ const RequestListItem = createClass({
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
// If this node is being destroyed and has focus, transfer the focus manually
|
||||
// to the parent tree component. Otherwise, the focus will get lost and keyboard
|
||||
// navigation in the tree will stop working. This is a workaround for a XUL bug.
|
||||
// See bugs 1259228 and 1152441 for details.
|
||||
// DE-XUL: Remove this hack once all usages are only in HTML documents.
|
||||
if (this.props.isSelected) {
|
||||
this.refs.el.blur();
|
||||
if (this.props.onFocusedNodeUnmount) {
|
||||
this.props.onFocusedNodeUnmount();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
item,
|
||||
@ -119,7 +102,7 @@ const RequestListItem = createClass({
|
||||
onSecurityIconClick
|
||||
} = this.props;
|
||||
|
||||
let classList = [ "request-list-item" ];
|
||||
let classList = ["request-list-item"];
|
||||
if (isSelected) {
|
||||
classList.push("selected");
|
||||
}
|
||||
@ -158,6 +141,10 @@ const UPDATED_STATUS_PROPS = [
|
||||
const StatusColumn = createFactory(createClass({
|
||||
displayName: "StatusColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_STATUS_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
@ -199,6 +186,10 @@ const StatusColumn = createFactory(createClass({
|
||||
const MethodColumn = createFactory(createClass({
|
||||
displayName: "MethodColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.method !== nextProps.item.method;
|
||||
},
|
||||
@ -221,6 +212,10 @@ const UPDATED_FILE_PROPS = [
|
||||
const FileColumn = createFactory(createClass({
|
||||
displayName: "FileColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_FILE_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
@ -256,6 +251,11 @@ const UPDATED_DOMAIN_PROPS = [
|
||||
const DomainColumn = createFactory(createClass({
|
||||
displayName: "DomainColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
onSecurityIconClick: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_DOMAIN_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
@ -264,7 +264,7 @@ const DomainColumn = createFactory(createClass({
|
||||
const { item, onSecurityIconClick } = this.props;
|
||||
const { urlDetails, remoteAddress, securityState } = item;
|
||||
|
||||
let iconClassList = [ "requests-security-state-icon" ];
|
||||
let iconClassList = ["requests-security-state-icon"];
|
||||
let iconTitle;
|
||||
if (urlDetails.isLocal) {
|
||||
iconClassList.push("security-state-local");
|
||||
@ -292,6 +292,10 @@ const DomainColumn = createFactory(createClass({
|
||||
const CauseColumn = createFactory(createClass({
|
||||
displayName: "CauseColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.cause !== nextProps.item.cause;
|
||||
},
|
||||
@ -334,6 +338,10 @@ const CONTENT_MIME_TYPE_ABBREVIATIONS = {
|
||||
const TypeColumn = createFactory(createClass({
|
||||
displayName: "TypeColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.mimeType !== nextProps.item.mimeType;
|
||||
},
|
||||
@ -366,6 +374,10 @@ const UPDATED_TRANSFERRED_PROPS = [
|
||||
const TransferredSizeColumn = createFactory(createClass({
|
||||
displayName: "TransferredSizeColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_TRANSFERRED_PROPS, this.props.item, nextProps.item);
|
||||
},
|
||||
@ -401,6 +413,10 @@ const TransferredSizeColumn = createFactory(createClass({
|
||||
const ContentSizeColumn = createFactory(createClass({
|
||||
displayName: "ContentSizeColumn",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.item.contentSize !== nextProps.item.contentSize;
|
||||
},
|
||||
@ -434,6 +450,11 @@ const UPDATED_WATERFALL_PROPS = [
|
||||
const WaterfallColumn = createFactory(createClass({
|
||||
displayName: "WaterfallColumn",
|
||||
|
||||
propTypes: {
|
||||
firstRequestStartedMillis: PropTypes.number.isRequired,
|
||||
item: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return this.props.firstRequestStartedMillis !== nextProps.firstRequestStartedMillis ||
|
||||
!propertiesEqual(UPDATED_WATERFALL_PROPS, this.props.item, nextProps.item);
|
||||
@ -485,12 +506,12 @@ function timingBoxes(item) {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof totalTime == "number") {
|
||||
if (typeof totalTime === "number") {
|
||||
let text = L10N.getFormatStr("networkMenu.totalMS", totalTime);
|
||||
boxes.push(div({
|
||||
key: "total",
|
||||
className: "requests-menu-timings-total",
|
||||
title: text
|
||||
title: text,
|
||||
}, text));
|
||||
}
|
||||
|
||||
@ -498,5 +519,3 @@ function timingBoxes(item) {
|
||||
}
|
||||
|
||||
module.exports = RequestListItem;
|
||||
|
||||
/* eslint-enable react/prop-types */
|
||||
|
@ -2,26 +2,13 @@
|
||||
* 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-env browser */
|
||||
/* globals gNetwork */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { setNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const Actions = require("../actions/index");
|
||||
const { Prefs } = require("../prefs");
|
||||
const { getFormDataSections } = require("../request-utils");
|
||||
const {
|
||||
getActiveFilters,
|
||||
getSelectedRequest,
|
||||
} = require("../selectors/index");
|
||||
|
||||
// Components
|
||||
const RequestListContent = createFactory(require("./request-list-content"));
|
||||
@ -33,94 +20,19 @@ const { div } = DOM;
|
||||
/**
|
||||
* Request panel component
|
||||
*/
|
||||
const RequestList = createClass({
|
||||
displayName: "RequestList",
|
||||
function RequestList({ isEmpty }) {
|
||||
return (
|
||||
div({ className: "request-list-container" },
|
||||
RequestListHeader(),
|
||||
isEmpty ? RequestListEmptyNotice() : RequestListContent(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
propTypes: {
|
||||
activeFilters: PropTypes.array,
|
||||
dispatch: PropTypes.func,
|
||||
isEmpty: PropTypes.bool.isRequired,
|
||||
request: PropTypes.object,
|
||||
networkDetailsOpen: PropTypes.bool,
|
||||
},
|
||||
RequestList.displayName = "RequestList";
|
||||
|
||||
componentDidMount() {
|
||||
const { dispatch } = this.props;
|
||||
RequestList.propTypes = {
|
||||
isEmpty: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
Prefs.filters.forEach((type) => dispatch(Actions.toggleRequestFilterType(type)));
|
||||
this.splitter = document.querySelector("#network-inspector-view-splitter");
|
||||
this.splitter.addEventListener("mouseup", this.resize);
|
||||
window.addEventListener("resize", this.resize);
|
||||
},
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { dispatch, request = {}, networkDetailsOpen } = this.props;
|
||||
|
||||
if (nextProps.request && nextProps.request !== request) {
|
||||
dispatch(Actions.openNetworkDetails(true));
|
||||
}
|
||||
|
||||
if (nextProps.networkDetailsOpen !== networkDetailsOpen) {
|
||||
this.resize();
|
||||
}
|
||||
|
||||
const {
|
||||
formDataSections,
|
||||
requestHeaders,
|
||||
requestHeadersFromUploadStream,
|
||||
requestPostData,
|
||||
} = nextProps.request || {};
|
||||
|
||||
if (!formDataSections && requestHeaders &&
|
||||
requestHeadersFromUploadStream && requestPostData) {
|
||||
getFormDataSections(
|
||||
requestHeaders,
|
||||
requestHeadersFromUploadStream,
|
||||
requestPostData,
|
||||
gNetwork.getString.bind(gNetwork),
|
||||
).then((newFormDataSections) => {
|
||||
dispatch(Actions.updateRequest(
|
||||
request.id,
|
||||
{ formDataSections: newFormDataSections },
|
||||
true,
|
||||
));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
this.splitter.removeEventListener("mouseup", this.resize);
|
||||
window.removeEventListener("resize", this.resize);
|
||||
},
|
||||
|
||||
resize() {
|
||||
const { dispatch } = this.props;
|
||||
// Allow requests to settle down first.
|
||||
setNamedTimeout("resize-events", 50, () => {
|
||||
const waterfallHeaderEl =
|
||||
document.querySelector("#requests-menu-waterfall-header-box");
|
||||
if (waterfallHeaderEl) {
|
||||
const { width } = waterfallHeaderEl.getBoundingClientRect();
|
||||
dispatch(Actions.resizeWaterfall(width));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
div({ className: "request-list-container" },
|
||||
RequestListHeader(),
|
||||
this.props.isEmpty ? RequestListEmptyNotice() : RequestListContent(),
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
activeFilters: getActiveFilters(state),
|
||||
isEmpty: state.requests.requests.isEmpty(),
|
||||
request: getSelectedRequest(state),
|
||||
networkDetailsOpen: state.ui.networkDetailsOpen,
|
||||
})
|
||||
)(RequestList);
|
||||
module.exports = RequestList;
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals document */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
@ -23,6 +21,7 @@ const {
|
||||
} = require("../utils/format-utils");
|
||||
|
||||
const { button, div } = DOM;
|
||||
const MediaQueryList = window.matchMedia("(min-width: 700px)");
|
||||
|
||||
const NETWORK_ANALYSIS_PIE_CHART_DIAMETER = 200;
|
||||
const BACK_BUTTON = L10N.getStr("netmonitor.backButton");
|
||||
@ -43,9 +42,17 @@ const StatisticsPanel = createClass({
|
||||
requests: PropTypes.object,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
isVerticalSpliter: MediaQueryList.matches,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
MediaQueryList.addListener(this.onLayoutChange);
|
||||
|
||||
const { requests } = this.props;
|
||||
let ready = requests && requests.every((req) =>
|
||||
let ready = requests && !requests.isEmpty() && requests.every((req) =>
|
||||
req.contentSize !== undefined && req.mimeType && req.responseHeaders &&
|
||||
req.status !== undefined && req.totalTime !== undefined
|
||||
);
|
||||
@ -53,16 +60,20 @@ const StatisticsPanel = createClass({
|
||||
this.createChart({
|
||||
id: "primedCacheChart",
|
||||
title: CHARTS_CACHE_ENABLED,
|
||||
data: ready ? this.sanitizeChartDataSource(requests, false) : null
|
||||
data: ready ? this.sanitizeChartDataSource(requests, false) : null,
|
||||
});
|
||||
|
||||
this.createChart({
|
||||
id: "emptyCacheChart",
|
||||
title: CHARTS_CACHE_DISABLED,
|
||||
data: ready ? this.sanitizeChartDataSource(requests, true) : null
|
||||
data: ready ? this.sanitizeChartDataSource(requests, true) : null,
|
||||
});
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
MediaQueryList.removeListener(this.onLayoutChange);
|
||||
},
|
||||
|
||||
createChart({ id, title, data }) {
|
||||
// Create a new chart.
|
||||
let chart = Chart.PieTable(document, {
|
||||
@ -74,7 +85,7 @@ const StatisticsPanel = createClass({
|
||||
label: L10N.getStr("charts.type"),
|
||||
size: L10N.getStr("charts.size"),
|
||||
transferredSize: L10N.getStr("charts.transferred"),
|
||||
time: L10N.getStr("charts.time")
|
||||
time: L10N.getStr("charts.time"),
|
||||
},
|
||||
data,
|
||||
strings: {
|
||||
@ -84,7 +95,7 @@ const StatisticsPanel = createClass({
|
||||
L10N.getFormatStr("charts.transferredSizeKB",
|
||||
getSizeWithDecimals(value / 1024)),
|
||||
time: (value) =>
|
||||
L10N.getFormatStr("charts.totalS", getTimeWithDecimals(value / 1000))
|
||||
L10N.getFormatStr("charts.totalS", getTimeWithDecimals(value / 1000)),
|
||||
},
|
||||
totals: {
|
||||
cached: (total) => L10N.getFormatStr("charts.totalCached", total),
|
||||
@ -129,7 +140,7 @@ const StatisticsPanel = createClass({
|
||||
label: type,
|
||||
size: 0,
|
||||
transferredSize: 0,
|
||||
time: 0
|
||||
time: 0,
|
||||
}));
|
||||
|
||||
for (let request of requests) {
|
||||
@ -219,19 +230,33 @@ const StatisticsPanel = createClass({
|
||||
return false;
|
||||
},
|
||||
|
||||
onLayoutChange() {
|
||||
this.setState({
|
||||
isVerticalSpliter: MediaQueryList.matches,
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
const { closeStatistics } = this.props;
|
||||
let splitterClassName = ["splitter"];
|
||||
|
||||
if (this.state.isVerticalSpliter) {
|
||||
splitterClassName.push("devtools-side-splitter");
|
||||
} else {
|
||||
splitterClassName.push("devtools-horizontal-splitter");
|
||||
}
|
||||
|
||||
return (
|
||||
div({ className: "statistics-panel" },
|
||||
button({
|
||||
className: "back-button devtools-toolbarbutton",
|
||||
className: "back-button devtools-button",
|
||||
"data-text-only": "true",
|
||||
title: BACK_BUTTON,
|
||||
onClick: closeStatistics,
|
||||
}, BACK_BUTTON),
|
||||
div({ className: "charts-container devtools-responsive-container" },
|
||||
div({ className: "charts-container" },
|
||||
div({ ref: "primedCacheChart", className: "charts primed-cache-chart" }),
|
||||
div({ className: "splitter devtools-side-splitter" }),
|
||||
div({ className: splitterClassName.join(" ") }),
|
||||
div({ ref: "emptyCacheChart", className: "charts empty-cache-chart" }),
|
||||
),
|
||||
)
|
||||
|
@ -5,6 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
@ -13,8 +14,10 @@ const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { PluralForm } = require("devtools/shared/plural-form");
|
||||
const Actions = require("../actions/index");
|
||||
const { L10N } = require("../l10n");
|
||||
const { Prefs } = require("../prefs");
|
||||
const {
|
||||
getDisplayedRequestsSummary,
|
||||
getRequestFilterTypes,
|
||||
isNetworkDetailsToggleButtonDisabled,
|
||||
} = require("../selectors/index");
|
||||
const {
|
||||
@ -38,123 +41,132 @@ const TOOLBAR_CLEAR = L10N.getStr("netmonitor.toolbar.clear");
|
||||
* Network monitor toolbar component
|
||||
* Toolbar contains a set of useful tools to control network requests
|
||||
*/
|
||||
function Toolbar({
|
||||
clearRequests,
|
||||
openStatistics,
|
||||
requestFilterTypes,
|
||||
setRequestFilterText,
|
||||
networkDetailsToggleDisabled,
|
||||
networkDetailsOpen,
|
||||
summary,
|
||||
toggleNetworkDetails,
|
||||
toggleRequestFilterType,
|
||||
}) {
|
||||
let toggleButtonClassName = [
|
||||
"network-details-panel-toggle",
|
||||
"devtools-button",
|
||||
];
|
||||
if (!networkDetailsOpen) {
|
||||
toggleButtonClassName.push("pane-collapsed");
|
||||
}
|
||||
const Toolbar = createClass({
|
||||
displayName: "Toolbar",
|
||||
|
||||
let { count, contentSize, transferredSize, millis } = summary;
|
||||
const text = (count === 0) ? L10N.getStr("networkMenu.empty") :
|
||||
PluralForm.get(count, L10N.getStr("networkMenu.summary2"))
|
||||
.replace("#1", count)
|
||||
.replace("#2", getSizeWithDecimals(contentSize / 1024))
|
||||
.replace("#3", getSizeWithDecimals(transferredSize / 1024))
|
||||
.replace("#4", getTimeWithDecimals(millis / 1000));
|
||||
propTypes: {
|
||||
clearRequests: PropTypes.func.isRequired,
|
||||
openStatistics: PropTypes.func.isRequired,
|
||||
requestFilterTypes: PropTypes.array.isRequired,
|
||||
setRequestFilterText: PropTypes.func.isRequired,
|
||||
networkDetailsToggleDisabled: PropTypes.bool.isRequired,
|
||||
networkDetailsOpen: PropTypes.bool.isRequired,
|
||||
summary: PropTypes.object.isRequired,
|
||||
toggleNetworkDetails: PropTypes.func.isRequired,
|
||||
toggleRequestFilterType: PropTypes.func.isRequired,
|
||||
},
|
||||
|
||||
const buttons = requestFilterTypes.entrySeq().map(([type, checked]) => {
|
||||
let classList = ["devtools-button"];
|
||||
checked && classList.push("checked");
|
||||
componentDidMount() {
|
||||
Prefs.filters.forEach(this.props.toggleRequestFilterType);
|
||||
},
|
||||
|
||||
toggleRequestFilterType(evt) {
|
||||
if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) {
|
||||
return;
|
||||
}
|
||||
this.props.toggleRequestFilterType(evt.target.dataset.key);
|
||||
},
|
||||
|
||||
render() {
|
||||
let {
|
||||
clearRequests,
|
||||
openStatistics,
|
||||
requestFilterTypes,
|
||||
setRequestFilterText,
|
||||
networkDetailsToggleDisabled,
|
||||
networkDetailsOpen,
|
||||
summary,
|
||||
toggleNetworkDetails,
|
||||
} = this.props;
|
||||
|
||||
let toggleButtonClassName = [
|
||||
"network-details-panel-toggle",
|
||||
"devtools-button",
|
||||
];
|
||||
if (!networkDetailsOpen) {
|
||||
toggleButtonClassName.push("pane-collapsed");
|
||||
}
|
||||
|
||||
let { count, contentSize, transferredSize, millis } = summary;
|
||||
let text = (count === 0) ? L10N.getStr("networkMenu.empty") :
|
||||
PluralForm.get(count, L10N.getStr("networkMenu.summary2"))
|
||||
.replace("#1", count)
|
||||
.replace("#2", getSizeWithDecimals(contentSize / 1024))
|
||||
.replace("#3", getSizeWithDecimals(transferredSize / 1024))
|
||||
.replace("#4", getTimeWithDecimals(millis / 1000));
|
||||
|
||||
let buttons = requestFilterTypes.map(([type, checked]) => {
|
||||
let classList = ["devtools-button"];
|
||||
checked && classList.push("checked");
|
||||
|
||||
return (
|
||||
button({
|
||||
id: `requests-menu-filter-${type}-button`,
|
||||
className: classList.join(" "),
|
||||
key: type,
|
||||
onClick: this.toggleRequestFilterType,
|
||||
onKeyDown: this.toggleRequestFilterType,
|
||||
"aria-pressed": checked,
|
||||
"data-key": type,
|
||||
},
|
||||
L10N.getStr(`netmonitor.toolbar.filter.${type}`)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
button({
|
||||
id: `requests-menu-filter-${type}-button`,
|
||||
className: classList.join(" "),
|
||||
key: type,
|
||||
onClick: toggleRequestFilterType,
|
||||
onKeyDown: toggleRequestFilterType,
|
||||
"aria-pressed": checked,
|
||||
"data-key": type,
|
||||
},
|
||||
L10N.getStr(`netmonitor.toolbar.filter.${type}`)
|
||||
span({ className: "devtools-toolbar devtools-toolbar-container" },
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
button({
|
||||
id: "requests-menu-clear-button",
|
||||
className: "devtools-button devtools-clear-icon",
|
||||
title: TOOLBAR_CLEAR,
|
||||
onClick: clearRequests,
|
||||
}),
|
||||
div({ id: "requests-menu-filter-buttons" }, buttons),
|
||||
),
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
button({
|
||||
id: "requests-menu-network-summary-button",
|
||||
className: "devtools-button",
|
||||
title: count ? text : L10N.getStr("netmonitor.toolbar.perf"),
|
||||
onClick: openStatistics,
|
||||
},
|
||||
span({ className: "summary-info-icon" }),
|
||||
span({ className: "summary-info-text" }, text),
|
||||
),
|
||||
SearchBox({
|
||||
delay: FILTER_SEARCH_DELAY,
|
||||
keyShortcut: SEARCH_KEY_SHORTCUT,
|
||||
placeholder: SEARCH_PLACE_HOLDER,
|
||||
type: "filter",
|
||||
onChange: setRequestFilterText,
|
||||
}),
|
||||
button({
|
||||
className: toggleButtonClassName.join(" "),
|
||||
title: networkDetailsOpen ? COLLPASE_DETAILS_PANE : EXPAND_DETAILS_PANE,
|
||||
disabled: networkDetailsToggleDisabled,
|
||||
tabIndex: "0",
|
||||
onClick: toggleNetworkDetails,
|
||||
}),
|
||||
)
|
||||
)
|
||||
);
|
||||
}).toArray();
|
||||
|
||||
return (
|
||||
span({ className: "devtools-toolbar devtools-toolbar-container" },
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
button({
|
||||
id: "requests-menu-clear-button",
|
||||
className: "devtools-button devtools-clear-icon",
|
||||
title: TOOLBAR_CLEAR,
|
||||
onClick: clearRequests,
|
||||
}),
|
||||
div({ id: "requests-menu-filter-buttons" }, buttons),
|
||||
),
|
||||
span({ className: "devtools-toolbar-group" },
|
||||
button({
|
||||
id: "requests-menu-network-summary-button",
|
||||
className: "devtools-button",
|
||||
title: count ? text : L10N.getStr("netmonitor.toolbar.perf"),
|
||||
onClick: openStatistics,
|
||||
},
|
||||
span({ className: "summary-info-icon" }),
|
||||
span({ className: "summary-info-text" }, text),
|
||||
),
|
||||
SearchBox({
|
||||
delay: FILTER_SEARCH_DELAY,
|
||||
keyShortcut: SEARCH_KEY_SHORTCUT,
|
||||
placeholder: SEARCH_PLACE_HOLDER,
|
||||
type: "filter",
|
||||
onChange: setRequestFilterText,
|
||||
}),
|
||||
button({
|
||||
className: toggleButtonClassName.join(" "),
|
||||
title: networkDetailsOpen ? COLLPASE_DETAILS_PANE : EXPAND_DETAILS_PANE,
|
||||
disabled: networkDetailsToggleDisabled,
|
||||
tabIndex: "0",
|
||||
onClick: toggleNetworkDetails,
|
||||
}),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Toolbar.displayName = "Toolbar";
|
||||
|
||||
Toolbar.propTypes = {
|
||||
clearRequests: PropTypes.func.isRequired,
|
||||
openStatistics: PropTypes.func.isRequired,
|
||||
requestFilterTypes: PropTypes.object.isRequired,
|
||||
setRequestFilterText: PropTypes.func.isRequired,
|
||||
networkDetailsToggleDisabled: PropTypes.bool.isRequired,
|
||||
networkDetailsOpen: PropTypes.bool.isRequired,
|
||||
summary: PropTypes.object.isRequired,
|
||||
toggleNetworkDetails: PropTypes.func.isRequired,
|
||||
toggleRequestFilterType: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
networkDetailsToggleDisabled: isNetworkDetailsToggleButtonDisabled(state),
|
||||
networkDetailsOpen: state.ui.networkDetailsOpen,
|
||||
requestFilterTypes: state.filters.requestFilterTypes,
|
||||
requestFilterTypes: getRequestFilterTypes(state),
|
||||
summary: getDisplayedRequestsSummary(state),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
clearRequests: () => dispatch(Actions.clearRequests()),
|
||||
openStatistics: () => dispatch(Actions.openStatistics(true)),
|
||||
setRequestFilterText: (text) => dispatch(Actions.setRequestFilterText(text)),
|
||||
toggleRequestFilterType: (evt) => {
|
||||
if (evt.type === "keydown" && (evt.key !== "" || evt.key !== "Enter")) {
|
||||
return;
|
||||
}
|
||||
dispatch(Actions.toggleRequestFilterType(evt.target.dataset.key));
|
||||
},
|
||||
toggleRequestFilterType: (type) => dispatch(Actions.toggleRequestFilterType(type)),
|
||||
toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),
|
||||
})
|
||||
}),
|
||||
)(Toolbar);
|
||||
|
@ -14,7 +14,7 @@ add_task(function* () {
|
||||
let { document, gStore, windowRequire } = monitor.panelWin;
|
||||
let Actions = windowRequire("devtools/client/netmonitor/actions/index");
|
||||
let RequestListContextMenu = windowRequire(
|
||||
"devtools/client/netmonitor/components/request-list-context-menu");
|
||||
"devtools/client/netmonitor/request-list-context-menu");
|
||||
|
||||
gStore.dispatch(Actions.batchEnable(false));
|
||||
|
||||
|
@ -15,7 +15,7 @@ add_task(function* () {
|
||||
let { document, gStore, windowRequire } = monitor.panelWin;
|
||||
let Actions = windowRequire("devtools/client/netmonitor/actions/index");
|
||||
let RequestListContextMenu = windowRequire(
|
||||
"devtools/client/netmonitor/components/request-list-context-menu");
|
||||
"devtools/client/netmonitor/request-list-context-menu");
|
||||
|
||||
gStore.dispatch(Actions.batchEnable(false));
|
||||
|
||||
|
@ -19,7 +19,7 @@ function* throttleUploadTest(actuallyThrottle) {
|
||||
let { document, gStore, windowRequire, NetMonitorController } = monitor.panelWin;
|
||||
let Actions = windowRequire("devtools/client/netmonitor/actions/index");
|
||||
let RequestListContextMenu = windowRequire(
|
||||
"devtools/client/netmonitor/components/request-list-context-menu");
|
||||
"devtools/client/netmonitor/request-list-context-menu");
|
||||
|
||||
gStore.dispatch(Actions.batchEnable(false));
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
|
||||
const NET_STRINGS_URI = "devtools/client/locales/netmonitor.properties";
|
||||
const WEBCONSOLE_STRINGS_URI = "devtools/client/locales/webconsole.properties";
|
||||
|
@ -9,7 +9,7 @@ const {
|
||||
TOGGLE_REQUEST_FILTER_TYPE,
|
||||
} = require("../constants");
|
||||
const { Prefs } = require("../prefs");
|
||||
const { getActiveFilters } = require("../selectors/index");
|
||||
const { getRequestFilterTypes } = require("../selectors/index");
|
||||
|
||||
/**
|
||||
* Whenever the User clicks on a filter in the network monitor, save the new
|
||||
@ -20,7 +20,9 @@ function prefsMiddleware(store) {
|
||||
const res = next(action);
|
||||
if (action.type === ENABLE_REQUEST_FILTER_TYPE_ONLY ||
|
||||
action.type === TOGGLE_REQUEST_FILTER_TYPE) {
|
||||
Prefs.filters = getActiveFilters(store.getState());
|
||||
Prefs.filters = getRequestFilterTypes(store.getState())
|
||||
.filter(([type, check]) => check)
|
||||
.map(([type, check]) => type);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
@ -19,9 +19,10 @@ DevToolsModules(
|
||||
'filter-predicates.js',
|
||||
'l10n.js',
|
||||
'netmonitor-controller.js',
|
||||
'netmonitor-view.js',
|
||||
'panel.js',
|
||||
'prefs.js',
|
||||
'request-list-context-menu.js',
|
||||
'request-list-tooltip.js',
|
||||
'request-utils.js',
|
||||
'sort-predicates.js',
|
||||
'store.js',
|
||||
|
@ -2,9 +2,6 @@
|
||||
* 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 mozilla/reject-some-requires */
|
||||
/* globals window, NetMonitorView, gStore, gNetwork, dumpn */
|
||||
|
||||
"use strict";
|
||||
|
||||
const promise = require("promise");
|
||||
@ -12,7 +9,6 @@ const Services = require("Services");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { TimelineFront } = require("devtools/shared/fronts/timeline");
|
||||
const { CurlUtils } = require("devtools/client/shared/curl");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { ACTIVITY_TYPE } = require("./constants");
|
||||
const { EVENTS } = require("./events");
|
||||
const { configureStore } = require("./store");
|
||||
@ -26,8 +22,7 @@ const {
|
||||
getDisplayedRequestById,
|
||||
} = require("./selectors/index");
|
||||
|
||||
// Initialize the global Redux store
|
||||
window.gStore = configureStore();
|
||||
const gStore = window.gStore = configureStore();
|
||||
|
||||
/**
|
||||
* Object defining the network monitor controller components.
|
||||
@ -39,18 +34,15 @@ var NetMonitorController = {
|
||||
* @return object
|
||||
* A promise that is resolved when the monitor finishes startup.
|
||||
*/
|
||||
startupNetMonitor: Task.async(function* () {
|
||||
async startupNetMonitor() {
|
||||
if (this._startup) {
|
||||
return this._startup.promise;
|
||||
}
|
||||
this._startup = promise.defer();
|
||||
{
|
||||
NetMonitorView.initialize();
|
||||
yield this.connect();
|
||||
}
|
||||
await this.connect();
|
||||
this._startup.resolve();
|
||||
return undefined;
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys the view and disconnects the monitor client from the server.
|
||||
@ -58,21 +50,18 @@ var NetMonitorController = {
|
||||
* @return object
|
||||
* A promise that is resolved when the monitor finishes shutdown.
|
||||
*/
|
||||
shutdownNetMonitor: Task.async(function* () {
|
||||
async shutdownNetMonitor() {
|
||||
if (this._shutdown) {
|
||||
return this._shutdown.promise;
|
||||
}
|
||||
this._shutdown = promise.defer();
|
||||
{
|
||||
gStore.dispatch(Actions.batchReset());
|
||||
NetMonitorView.destroy();
|
||||
this.TargetEventsHandler.disconnect();
|
||||
this.NetworkEventsHandler.disconnect();
|
||||
yield this.disconnect();
|
||||
}
|
||||
gStore.dispatch(Actions.batchReset());
|
||||
this.TargetEventsHandler.disconnect();
|
||||
this.NetworkEventsHandler.disconnect();
|
||||
await this.disconnect();
|
||||
this._shutdown.resolve();
|
||||
return undefined;
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Initiates remote or chrome network monitoring based on the current target,
|
||||
@ -83,7 +72,7 @@ var NetMonitorController = {
|
||||
* @return object
|
||||
* A promise that is resolved when the monitor finishes connecting.
|
||||
*/
|
||||
connect: Task.async(function* () {
|
||||
async connect() {
|
||||
if (this._connection) {
|
||||
return this._connection.promise;
|
||||
}
|
||||
@ -107,7 +96,7 @@ var NetMonitorController = {
|
||||
};
|
||||
|
||||
this.webConsoleClient = this._target.activeConsole;
|
||||
yield connectTimeline();
|
||||
await connectTimeline();
|
||||
|
||||
this.TargetEventsHandler.connect();
|
||||
this.NetworkEventsHandler.connect();
|
||||
@ -117,12 +106,12 @@ var NetMonitorController = {
|
||||
this._connection.resolve();
|
||||
this._connected = true;
|
||||
return undefined;
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnects the debugger client and removes event handlers as necessary.
|
||||
*/
|
||||
disconnect: Task.async(function* () {
|
||||
async disconnect() {
|
||||
if (this._disconnection) {
|
||||
return this._disconnection.promise;
|
||||
}
|
||||
@ -130,7 +119,7 @@ var NetMonitorController = {
|
||||
|
||||
// Wait for the connection to finish first.
|
||||
if (!this.isConnected()) {
|
||||
yield this._connection.promise;
|
||||
await this._connection.promise;
|
||||
}
|
||||
|
||||
// When debugging local or a remote instance, the connection is closed by
|
||||
@ -141,14 +130,14 @@ var NetMonitorController = {
|
||||
// The timeline front wasn't initialized and started if the server wasn't
|
||||
// recent enough to emit the markers we were interested in.
|
||||
if (this._target.getTrait("documentLoadingMarkers")) {
|
||||
yield this.timelineFront.destroy();
|
||||
await this.timelineFront.destroy();
|
||||
this.timelineFront = null;
|
||||
}
|
||||
|
||||
this._disconnection.resolve();
|
||||
this._connected = false;
|
||||
return undefined;
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether the netmonitor connection is active.
|
||||
@ -386,7 +375,6 @@ TargetEventsHandler.prototype = {
|
||||
* Listen for events emitted by the current tab target.
|
||||
*/
|
||||
connect: function () {
|
||||
dumpn("TargetEventsHandler is connecting...");
|
||||
this.target.on("close", this._onTabDetached);
|
||||
this.target.on("navigate", this._onTabNavigated);
|
||||
this.target.on("will-navigate", this._onTabNavigated);
|
||||
@ -399,7 +387,6 @@ TargetEventsHandler.prototype = {
|
||||
if (!this.target) {
|
||||
return;
|
||||
}
|
||||
dumpn("TargetEventsHandler is disconnecting...");
|
||||
this.target.off("close", this._onTabDetached);
|
||||
this.target.off("navigate", this._onTabNavigated);
|
||||
this.target.off("will-navigate", this._onTabNavigated);
|
||||
@ -449,6 +436,7 @@ TargetEventsHandler.prototype = {
|
||||
function NetworkEventsHandler() {
|
||||
this.addRequest = this.addRequest.bind(this);
|
||||
this.updateRequest = this.updateRequest.bind(this);
|
||||
this.getString = this.getString.bind(this);
|
||||
this._onNetworkEvent = this._onNetworkEvent.bind(this);
|
||||
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
|
||||
this._onDocLoadingMarker = this._onDocLoadingMarker.bind(this);
|
||||
@ -479,7 +467,6 @@ NetworkEventsHandler.prototype = {
|
||||
* Connect to the current target client.
|
||||
*/
|
||||
connect: function () {
|
||||
dumpn("NetworkEventsHandler is connecting...");
|
||||
this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
|
||||
this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
|
||||
|
||||
@ -497,7 +484,6 @@ NetworkEventsHandler.prototype = {
|
||||
if (!this.client) {
|
||||
return;
|
||||
}
|
||||
dumpn("NetworkEventsHandler is disconnecting...");
|
||||
this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
|
||||
this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
|
||||
|
||||
@ -579,9 +565,9 @@ NetworkEventsHandler.prototype = {
|
||||
.then(() => window.emit(EVENTS.REQUEST_ADDED, id));
|
||||
},
|
||||
|
||||
updateRequest: Task.async(function* (id, data) {
|
||||
async updateRequest(id, data) {
|
||||
const action = Actions.updateRequest(id, data, true);
|
||||
yield gStore.dispatch(action);
|
||||
await gStore.dispatch(action);
|
||||
let {
|
||||
responseContent,
|
||||
responseCookies,
|
||||
@ -593,10 +579,9 @@ NetworkEventsHandler.prototype = {
|
||||
let request = getRequestById(gStore.getState(), action.id);
|
||||
|
||||
if (requestHeaders && requestHeaders.headers && requestHeaders.headers.length) {
|
||||
let headers = yield fetchHeaders(
|
||||
requestHeaders, gNetwork.getString.bind(gNetwork));
|
||||
let headers = await fetchHeaders(requestHeaders, this.getString);
|
||||
if (headers) {
|
||||
yield gStore.dispatch(Actions.updateRequest(
|
||||
await gStore.dispatch(Actions.updateRequest(
|
||||
action.id,
|
||||
{ requestHeaders: headers },
|
||||
true,
|
||||
@ -605,10 +590,9 @@ NetworkEventsHandler.prototype = {
|
||||
}
|
||||
|
||||
if (responseHeaders && responseHeaders.headers && responseHeaders.headers.length) {
|
||||
let headers = yield fetchHeaders(
|
||||
responseHeaders, gNetwork.getString.bind(gNetwork));
|
||||
let headers = await fetchHeaders(responseHeaders, this.getString);
|
||||
if (headers) {
|
||||
yield gStore.dispatch(Actions.updateRequest(
|
||||
await gStore.dispatch(Actions.updateRequest(
|
||||
action.id,
|
||||
{ responseHeaders: headers },
|
||||
true,
|
||||
@ -619,7 +603,7 @@ NetworkEventsHandler.prototype = {
|
||||
if (request && responseContent && responseContent.content) {
|
||||
let { mimeType } = request;
|
||||
let { text, encoding } = responseContent.content;
|
||||
let response = yield gNetwork.getString(text);
|
||||
let response = await this.getString(text);
|
||||
let payload = {};
|
||||
|
||||
if (mimeType.includes("image/")) {
|
||||
@ -629,7 +613,7 @@ NetworkEventsHandler.prototype = {
|
||||
responseContent.content.text = response;
|
||||
payload.responseContent = responseContent;
|
||||
|
||||
yield gStore.dispatch(Actions.updateRequest(action.id, payload, true));
|
||||
await gStore.dispatch(Actions.updateRequest(action.id, payload, true));
|
||||
|
||||
if (mimeType.includes("image/")) {
|
||||
window.emit(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
|
||||
@ -640,7 +624,7 @@ NetworkEventsHandler.prototype = {
|
||||
// them as a separate property, different from the classic headers.
|
||||
if (requestPostData && requestPostData.postData) {
|
||||
let { text } = requestPostData.postData;
|
||||
let postData = yield gNetwork.getString(text);
|
||||
let postData = await this.getString(text);
|
||||
const headers = CurlUtils.getHeadersFromMultipartText(postData);
|
||||
const headersSize = headers.reduce((acc, { name, value }) => {
|
||||
return acc + name.length + value.length + 2;
|
||||
@ -650,7 +634,7 @@ NetworkEventsHandler.prototype = {
|
||||
payload.requestPostData = Object.assign({}, requestPostData);
|
||||
payload.requestHeadersFromUploadStream = { headers, headersSize };
|
||||
|
||||
yield gStore.dispatch(Actions.updateRequest(action.id, payload, true));
|
||||
await gStore.dispatch(Actions.updateRequest(action.id, payload, true));
|
||||
}
|
||||
|
||||
// Fetch request and response cookies long value.
|
||||
@ -665,11 +649,11 @@ NetworkEventsHandler.prototype = {
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
reqCookies.push(Object.assign({}, cookie, {
|
||||
value: yield gNetwork.getString(cookie.value),
|
||||
value: await this.getString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (reqCookies.length) {
|
||||
yield gStore.dispatch(Actions.updateRequest(
|
||||
await gStore.dispatch(Actions.updateRequest(
|
||||
action.id,
|
||||
{ requestCookies: reqCookies },
|
||||
true));
|
||||
@ -686,18 +670,18 @@ NetworkEventsHandler.prototype = {
|
||||
if (typeof cookies[Symbol.iterator] === "function") {
|
||||
for (let cookie of cookies) {
|
||||
resCookies.push(Object.assign({}, cookie, {
|
||||
value: yield gNetwork.getString(cookie.value),
|
||||
value: await this.getString(cookie.value),
|
||||
}));
|
||||
}
|
||||
if (resCookies.length) {
|
||||
yield gStore.dispatch(Actions.updateRequest(
|
||||
await gStore.dispatch(Actions.updateRequest(
|
||||
action.id,
|
||||
{ responseCookies: resCookies },
|
||||
true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* The "networkEventUpdate" message type handler.
|
||||
@ -917,17 +901,6 @@ EventEmitter.decorate(window);
|
||||
*/
|
||||
NetMonitorController.TargetEventsHandler = new TargetEventsHandler();
|
||||
NetMonitorController.NetworkEventsHandler = new NetworkEventsHandler();
|
||||
|
||||
/**
|
||||
* Export some properties to the global scope for easier access.
|
||||
*/
|
||||
Object.defineProperties(window, {
|
||||
"gNetwork": {
|
||||
get: function () {
|
||||
return NetMonitorController.NetworkEventsHandler;
|
||||
},
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
window.gNetwork = NetMonitorController.NetworkEventsHandler;
|
||||
|
||||
exports.NetMonitorController = NetMonitorController;
|
||||
|
@ -1,97 +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/. */
|
||||
|
||||
/* eslint-env browser */
|
||||
/* globals gStore, NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { ACTIVITY_TYPE } = require("./constants");
|
||||
const { createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
|
||||
|
||||
// Components
|
||||
const NetworkDetailsPanel = createFactory(require("./shared/components/network-details-panel"));
|
||||
const RequestList = createFactory(require("./components/request-list"));
|
||||
const StatisticsPanel = createFactory(require("./components/statistics-panel"));
|
||||
const Toolbar = createFactory(require("./components/toolbar"));
|
||||
|
||||
/**
|
||||
* Object defining the network monitor view components.
|
||||
*/
|
||||
exports.NetMonitorView = {
|
||||
/**
|
||||
* Initializes the network monitor view.
|
||||
*/
|
||||
initialize: function () {
|
||||
this._body = document.querySelector("#body");
|
||||
|
||||
this.networkDetailsPanel = document.querySelector(
|
||||
"#react-network-details-panel-hook");
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
NetworkDetailsPanel({ toolbox: NetMonitorController._toolbox }),
|
||||
), this.networkDetailsPanel);
|
||||
|
||||
this.requestList = document.querySelector("#react-request-list-hook");
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
RequestList({ toolbox: NetMonitorController._toolbox })
|
||||
), this.requestList);
|
||||
|
||||
this.statisticsPanel = document.querySelector("#react-statistics-panel-hook");
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
StatisticsPanel(),
|
||||
), this.statisticsPanel);
|
||||
|
||||
this.toolbar = document.querySelector("#react-toolbar-hook");
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
Toolbar(),
|
||||
), this.toolbar);
|
||||
|
||||
// Store watcher here is for observing the statisticsOpen state change.
|
||||
// It should be removed once we migrate to react and apply react/redex binding.
|
||||
this.unsubscribeStore = gStore.subscribe(storeWatcher(
|
||||
false,
|
||||
() => gStore.getState().ui.statisticsOpen,
|
||||
this.toggleFrontendMode.bind(this)
|
||||
));
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys the network monitor view.
|
||||
*/
|
||||
destroy: function () {
|
||||
ReactDOM.unmountComponentAtNode(this.networkDetailsPanel);
|
||||
ReactDOM.unmountComponentAtNode(this.requestList);
|
||||
ReactDOM.unmountComponentAtNode(this.statisticsPanel);
|
||||
ReactDOM.unmountComponentAtNode(this.toolbar);
|
||||
this.unsubscribeStore();
|
||||
},
|
||||
|
||||
toggleFrontendMode: function () {
|
||||
if (gStore.getState().ui.statisticsOpen) {
|
||||
this._body.selectedPanel = document.querySelector("#react-statistics-panel-hook");
|
||||
NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
|
||||
} else {
|
||||
this._body.selectedPanel = document.querySelector("#inspector-panel");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// A smart store watcher to notify store changes as necessary
|
||||
function storeWatcher(initialValue, reduceValue, onChange) {
|
||||
let currentValue = initialValue;
|
||||
|
||||
return () => {
|
||||
const newValue = reduceValue();
|
||||
if (newValue !== currentValue) {
|
||||
onChange();
|
||||
currentValue = newValue;
|
||||
}
|
||||
};
|
||||
}
|
@ -2,59 +2,40 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals window, document, NetMonitorController, NetMonitorView */
|
||||
/* exported Netmonitor, NetMonitorController, NetMonitorView, $, $all, dumpn */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
|
||||
|
||||
function Netmonitor(toolbox) {
|
||||
const { require } = BrowserLoader({
|
||||
baseURI: "resource://devtools/client/netmonitor/",
|
||||
window,
|
||||
commonLibRequire: toolbox.browserRequire,
|
||||
});
|
||||
|
||||
window.windowRequire = require;
|
||||
|
||||
const { NetMonitorController } = require("./netmonitor-controller.js");
|
||||
const { NetMonitorView } = require("./netmonitor-view.js");
|
||||
|
||||
window.NetMonitorController = NetMonitorController;
|
||||
window.NetMonitorView = NetMonitorView;
|
||||
|
||||
NetMonitorController._toolbox = toolbox;
|
||||
NetMonitorController._target = toolbox.target;
|
||||
window.NetMonitorController = require("./netmonitor-controller").NetMonitorController;
|
||||
window.NetMonitorController._toolbox = toolbox;
|
||||
window.NetMonitorController._target = toolbox.target;
|
||||
}
|
||||
|
||||
Netmonitor.prototype = {
|
||||
init() {
|
||||
const require = window.windowRequire;
|
||||
const { createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const { render } = require("devtools/client/shared/vendor/react-dom");
|
||||
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
|
||||
|
||||
// Components
|
||||
const NetworkMonitor = createFactory(require("./components/network-monitor"));
|
||||
|
||||
this.networkMonitor = document.querySelector(".root");
|
||||
|
||||
render(Provider(
|
||||
{ store: window.gStore },
|
||||
NetworkMonitor({ toolbox: window.NetMonitorController._toolbox }),
|
||||
), this.networkMonitor);
|
||||
|
||||
return window.NetMonitorController.startupNetMonitor();
|
||||
},
|
||||
|
||||
destroy() {
|
||||
const require = window.windowRequire;
|
||||
const { unmountComponentAtNode } = require("devtools/client/shared/vendor/react-dom");
|
||||
|
||||
unmountComponentAtNode(this.networkMonitor);
|
||||
|
||||
return window.NetMonitorController.shutdownNetMonitor();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* DOM query helper.
|
||||
* TODO: Move it into "dom-utils.js" module and "require" it when needed.
|
||||
*/
|
||||
var $ = (selector, target = document) => target.querySelector(selector);
|
||||
var $all = (selector, target = document) => target.querySelectorAll(selector);
|
||||
|
||||
/**
|
||||
* Helper method for debugging.
|
||||
* @param string
|
||||
*/
|
||||
function dumpn(str) {
|
||||
if (wantLogging) {
|
||||
dump("NET-FRONTEND: " + str + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
var wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
||||
|
29
devtools/client/netmonitor/netmonitor.xhtml
Normal file
29
devtools/client/netmonitor/netmonitor.xhtml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" dir="">
|
||||
<head>
|
||||
<link rel="stylesheet" href="chrome://devtools/content/shared/widgets/widgets.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/widgets.css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/netmonitor.css"/>
|
||||
|
||||
<script src="chrome://devtools/content/shared/theme-switching.js"/>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
const { BrowserLoader } = Components.utils.import(
|
||||
"resource://devtools/client/shared/browser-loader.js", {});
|
||||
const { require } = BrowserLoader({
|
||||
baseURI: "resource://devtools/client/netmonitor/",
|
||||
window,
|
||||
});
|
||||
window.windowRequire = require;
|
||||
</script>
|
||||
</head>
|
||||
<body class="theme-sidebar" role="application">
|
||||
<div class="root"></div>
|
||||
<script src="netmonitor.js" defer="true"/>
|
||||
</body>
|
||||
</html>
|
@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/netmonitor.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://devtools/content/shared/theme-switching.js"/>
|
||||
<script type="text/javascript" src="netmonitor.js"/>
|
||||
|
||||
<deck id="body"
|
||||
class="theme-sidebar"
|
||||
flex="1"
|
||||
data-localization-bundle="devtools/client/locales/netmonitor.properties">
|
||||
|
||||
<vbox id="inspector-panel" flex="1">
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-toolbar-hook"/>
|
||||
<hbox id="network-table-and-sidebar"
|
||||
class="devtools-responsive-container"
|
||||
flex="1">
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-request-list-hook"
|
||||
class="devtools-main-content">
|
||||
</html:div>
|
||||
|
||||
<splitter id="network-inspector-view-splitter"
|
||||
class="devtools-side-splitter"/>
|
||||
|
||||
<box id="splitter-adjustable-box"
|
||||
hidden="true">
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-network-details-panel-hook">
|
||||
</html:div>
|
||||
</box>
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-statistics-panel-hook">
|
||||
</html:div>
|
||||
</deck>
|
||||
|
||||
</window>
|
@ -4,71 +4,29 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const promise = require("promise");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { localizeMarkup } = require("devtools/shared/l10n");
|
||||
|
||||
function NetMonitorPanel(iframeWindow, toolbox) {
|
||||
this.panelWin = iframeWindow;
|
||||
this.panelDoc = iframeWindow.document;
|
||||
this._toolbox = toolbox;
|
||||
|
||||
this._netmonitor = new iframeWindow.Netmonitor(toolbox);
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
this.toolbox = toolbox;
|
||||
this.netmonitor = new iframeWindow.Netmonitor(toolbox);
|
||||
}
|
||||
|
||||
exports.NetMonitorPanel = NetMonitorPanel;
|
||||
|
||||
NetMonitorPanel.prototype = {
|
||||
/**
|
||||
* Open is effectively an asynchronous constructor.
|
||||
*
|
||||
* @return object
|
||||
* A promise that is resolved when the NetMonitor completes opening.
|
||||
*/
|
||||
open: Task.async(function* () {
|
||||
if (this._opening) {
|
||||
return this._opening;
|
||||
async open() {
|
||||
if (!this.toolbox.target.isRemote) {
|
||||
await this.toolbox.target.makeRemote();
|
||||
}
|
||||
// Localize all the nodes containing a data-localization attribute.
|
||||
localizeMarkup(this.panelDoc);
|
||||
|
||||
let deferred = promise.defer();
|
||||
this._opening = deferred.promise;
|
||||
|
||||
// Local monitoring needs to make the target remote.
|
||||
if (!this.target.isRemote) {
|
||||
yield this.target.makeRemote();
|
||||
}
|
||||
|
||||
yield this._netmonitor.init();
|
||||
|
||||
this.isReady = true;
|
||||
await this.netmonitor.init();
|
||||
this.emit("ready");
|
||||
|
||||
deferred.resolve(this);
|
||||
return this._opening;
|
||||
}),
|
||||
|
||||
// DevToolPanel API
|
||||
|
||||
get target() {
|
||||
return this._toolbox.target;
|
||||
this.isReady = true;
|
||||
return this;
|
||||
},
|
||||
|
||||
destroy: Task.async(function* () {
|
||||
if (this._destroying) {
|
||||
return this._destroying;
|
||||
}
|
||||
let deferred = promise.defer();
|
||||
this._destroying = deferred.promise;
|
||||
|
||||
yield this._netmonitor.destroy();
|
||||
async destroy() {
|
||||
await this.netmonitor.destroy();
|
||||
this.emit("destroyed");
|
||||
|
||||
deferred.resolve();
|
||||
return this._destroying;
|
||||
})
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
||||
exports.NetMonitorPanel = NetMonitorPanel;
|
||||
|
@ -4,12 +4,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const {PrefsHelper} = require("devtools/client/shared/prefs");
|
||||
const { PrefsHelper } = require("devtools/client/shared/prefs");
|
||||
|
||||
/**
|
||||
* Shortcuts for accessing various network monitor preferences.
|
||||
*/
|
||||
|
||||
exports.Prefs = new PrefsHelper("devtools.netmonitor", {
|
||||
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
||||
networkDetailsHeight: ["Int", "panes-network-details-height"],
|
||||
|
@ -6,9 +6,13 @@
|
||||
|
||||
const I = require("devtools/client/shared/vendor/immutable");
|
||||
const {
|
||||
CLEAR_REQUESTS,
|
||||
OPEN_NETWORK_DETAILS,
|
||||
OPEN_STATISTICS,
|
||||
REMOVE_SELECTED_CUSTOM_REQUEST,
|
||||
SELECT_DETAILS_PANEL_TAB,
|
||||
SEND_CUSTOM_REQUEST,
|
||||
SELECT_REQUEST,
|
||||
WATERFALL_RESIZE,
|
||||
} = require("../constants");
|
||||
|
||||
@ -40,12 +44,19 @@ function setDetailsPanelTab(state, action) {
|
||||
|
||||
function ui(state = new UI(), action) {
|
||||
switch (action.type) {
|
||||
case CLEAR_REQUESTS:
|
||||
return openNetworkDetails(state, { open: false });
|
||||
case OPEN_NETWORK_DETAILS:
|
||||
return openNetworkDetails(state, action);
|
||||
case OPEN_STATISTICS:
|
||||
return openStatistics(state, action);
|
||||
case REMOVE_SELECTED_CUSTOM_REQUEST:
|
||||
case SEND_CUSTOM_REQUEST:
|
||||
return openNetworkDetails(state, { open: false });
|
||||
case SELECT_DETAILS_PANEL_TAB:
|
||||
return setDetailsPanelTab(state, action);
|
||||
case SELECT_REQUEST:
|
||||
return openNetworkDetails(state, { open: true });
|
||||
case WATERFALL_RESIZE:
|
||||
return resizeWaterfall(state, action);
|
||||
default:
|
||||
|
@ -2,27 +2,24 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals NetMonitorController, gNetwork, gStore */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { Curl } = require("devtools/client/shared/curl");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
const Menu = require("devtools/client/framework/menu");
|
||||
const MenuItem = require("devtools/client/framework/menu-item");
|
||||
const { L10N } = require("../l10n");
|
||||
const { L10N } = require("./l10n");
|
||||
const {
|
||||
formDataURI,
|
||||
getFormDataSections,
|
||||
getUrlQuery,
|
||||
parseQueryString,
|
||||
} = require("../request-utils");
|
||||
} = require("./request-utils");
|
||||
const {
|
||||
getSelectedRequest,
|
||||
getSortedRequests,
|
||||
} = require("../selectors/index");
|
||||
} = require("./selectors/index");
|
||||
|
||||
loader.lazyRequireGetter(this, "HarExporter",
|
||||
"devtools/client/netmonitor/har/har-exporter", true);
|
||||
@ -40,11 +37,11 @@ function RequestListContextMenu({
|
||||
|
||||
RequestListContextMenu.prototype = {
|
||||
get selectedRequest() {
|
||||
return getSelectedRequest(gStore.getState());
|
||||
return getSelectedRequest(window.gStore.getState());
|
||||
},
|
||||
|
||||
get sortedRequests() {
|
||||
return getSortedRequests(gStore.getState());
|
||||
return getSortedRequests(window.gStore.getState());
|
||||
},
|
||||
|
||||
/**
|
||||
@ -160,7 +157,7 @@ RequestListContextMenu.prototype = {
|
||||
id: "request-menu-context-resend",
|
||||
label: L10N.getStr("netmonitor.context.editAndResend"),
|
||||
accesskey: L10N.getStr("netmonitor.context.editAndResend.accesskey"),
|
||||
visible: !!(NetMonitorController.supportsCustomRequest &&
|
||||
visible: !!(window.NetMonitorController.supportsCustomRequest &&
|
||||
selectedRequest && !selectedRequest.isCustom),
|
||||
click: this.cloneSelectedRequest,
|
||||
}));
|
||||
@ -182,11 +179,11 @@ RequestListContextMenu.prototype = {
|
||||
id: "request-menu-context-perf",
|
||||
label: L10N.getStr("netmonitor.context.perfTools"),
|
||||
accesskey: L10N.getStr("netmonitor.context.perfTools.accesskey"),
|
||||
visible: !!NetMonitorController.supportsPerfStats,
|
||||
visible: !!window.NetMonitorController.supportsPerfStats,
|
||||
click: () => this.openStatistics(true)
|
||||
}));
|
||||
|
||||
menu.popup(screenX, screenY, NetMonitorController._toolbox);
|
||||
menu.popup(screenX, screenY, window.NetMonitorController._toolbox);
|
||||
return menu;
|
||||
},
|
||||
|
||||
@ -220,15 +217,15 @@ RequestListContextMenu.prototype = {
|
||||
* Copy the request form data parameters (or raw payload) from
|
||||
* the currently selected item.
|
||||
*/
|
||||
copyPostData: Task.async(function* () {
|
||||
async copyPostData() {
|
||||
let selected = this.selectedRequest;
|
||||
|
||||
// Try to extract any form data parameters.
|
||||
let formDataSections = yield getFormDataSections(
|
||||
let formDataSections = await getFormDataSections(
|
||||
selected.requestHeaders,
|
||||
selected.requestHeadersFromUploadStream,
|
||||
selected.requestPostData,
|
||||
gNetwork.getString.bind(gNetwork));
|
||||
window.gNetwork.getString.bind(window.gNetwork));
|
||||
|
||||
let params = [];
|
||||
formDataSections.forEach(section => {
|
||||
@ -245,19 +242,19 @@ RequestListContextMenu.prototype = {
|
||||
// Fall back to raw payload.
|
||||
if (!string) {
|
||||
let postData = selected.requestPostData.postData.text;
|
||||
string = yield gNetwork.getString(postData);
|
||||
string = await window.gNetwork.getString(postData);
|
||||
if (Services.appinfo.OS !== "WINNT") {
|
||||
string = string.replace(/\r/g, "");
|
||||
}
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(string);
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy a cURL command from the currently selected item.
|
||||
*/
|
||||
copyAsCurl: Task.async(function* () {
|
||||
async copyAsCurl() {
|
||||
let selected = this.selectedRequest;
|
||||
|
||||
// Create a sanitized object for the Curl command generator.
|
||||
@ -271,18 +268,18 @@ RequestListContextMenu.prototype = {
|
||||
|
||||
// Fetch header values.
|
||||
for (let { name, value } of selected.requestHeaders.headers) {
|
||||
let text = yield gNetwork.getString(value);
|
||||
let text = await window.gNetwork.getString(value);
|
||||
data.headers.push({ name: name, value: text });
|
||||
}
|
||||
|
||||
// Fetch the request payload.
|
||||
if (selected.requestPostData) {
|
||||
let postData = selected.requestPostData.postData.text;
|
||||
data.postDataText = yield gNetwork.getString(postData);
|
||||
data.postDataText = await window.gNetwork.getString(postData);
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(Curl.generateCommand(data));
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the raw request headers from the currently selected item.
|
||||
@ -312,7 +309,7 @@ RequestListContextMenu.prototype = {
|
||||
copyImageAsDataUri() {
|
||||
const { mimeType, text, encoding } = this.selectedRequest.responseContent.content;
|
||||
|
||||
gNetwork.getString(text).then(string => {
|
||||
window.gNetwork.getString(text).then(string => {
|
||||
let data = formDataURI(mimeType, encoding, string);
|
||||
clipboardHelper.copyString(data);
|
||||
});
|
||||
@ -324,7 +321,7 @@ RequestListContextMenu.prototype = {
|
||||
copyResponse() {
|
||||
const { text } = this.selectedRequest.responseContent.content;
|
||||
|
||||
gNetwork.getString(text).then(string => {
|
||||
window.gNetwork.getString(text).then(string => {
|
||||
clipboardHelper.copyString(string);
|
||||
});
|
||||
},
|
||||
@ -346,11 +343,11 @@ RequestListContextMenu.prototype = {
|
||||
},
|
||||
|
||||
getDefaultHarOptions() {
|
||||
let form = NetMonitorController._target.form;
|
||||
let form = window.NetMonitorController._target.form;
|
||||
let title = form.title || form.url;
|
||||
|
||||
return {
|
||||
getString: gNetwork.getString.bind(gNetwork),
|
||||
getString: window.gNetwork.getString.bind(window.gNetwork),
|
||||
items: this.sortedRequests,
|
||||
title: title
|
||||
};
|
@ -2,17 +2,14 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals gNetwork, NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const {
|
||||
setImageTooltip,
|
||||
getImageDimensions,
|
||||
} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
|
||||
const { WEBCONSOLE_L10N } = require("../l10n");
|
||||
const { formDataURI } = require("../request-utils");
|
||||
const { WEBCONSOLE_L10N } = require("./l10n");
|
||||
const { formDataURI } = require("./request-utils");
|
||||
|
||||
// px
|
||||
const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400;
|
||||
@ -21,24 +18,24 @@ const REQUESTS_TOOLTIP_STACK_TRACE_WIDTH = 600;
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
const setTooltipImageContent = Task.async(function* (tooltip, itemEl, requestItem) {
|
||||
async function setTooltipImageContent(tooltip, itemEl, requestItem) {
|
||||
let { mimeType, text, encoding } = requestItem.responseContent.content;
|
||||
|
||||
if (!mimeType || !mimeType.includes("image/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let string = yield gNetwork.getString(text);
|
||||
let string = await window.gNetwork.getString(text);
|
||||
let src = formDataURI(mimeType, encoding, string);
|
||||
let maxDim = REQUESTS_TOOLTIP_IMAGE_MAX_DIM;
|
||||
let { naturalWidth, naturalHeight } = yield getImageDimensions(tooltip.doc, src);
|
||||
let { naturalWidth, naturalHeight } = await getImageDimensions(tooltip.doc, src);
|
||||
let options = { maxDim, naturalWidth, naturalHeight };
|
||||
setImageTooltip(tooltip, tooltip.doc, src, options);
|
||||
|
||||
return itemEl.querySelector(".requests-menu-icon");
|
||||
});
|
||||
}
|
||||
|
||||
const setTooltipStackTraceContent = Task.async(function* (tooltip, requestItem) {
|
||||
async function setTooltipStackTraceContent(tooltip, requestItem) {
|
||||
let {stacktrace} = requestItem.cause;
|
||||
|
||||
if (!stacktrace || stacktrace.length == 0) {
|
||||
@ -92,7 +89,7 @@ const setTooltipStackTraceContent = Task.async(function* (tooltip, requestItem)
|
||||
frameEl.addEventListener("click", () => {
|
||||
// hide the tooltip immediately, not after delay
|
||||
tooltip.hide();
|
||||
NetMonitorController.viewSourceInDebugger(filename, lineNumber);
|
||||
window.NetMonitorController.viewSourceInDebugger(filename, lineNumber);
|
||||
});
|
||||
|
||||
el.appendChild(frameEl);
|
||||
@ -101,7 +98,7 @@ const setTooltipStackTraceContent = Task.async(function* (tooltip, requestItem)
|
||||
tooltip.setContent(el, {width: REQUESTS_TOOLTIP_STACK_TRACE_WIDTH});
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setTooltipImageContent,
|
@ -6,8 +6,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
/**
|
||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||
* POST request.
|
||||
@ -18,8 +16,7 @@ const { Task } = require("devtools/shared/task");
|
||||
* @param {function} getString - callback to retrieve a string from a LongStringGrip.
|
||||
* @return {array} a promise list that is resolved with the extracted form data.
|
||||
*/
|
||||
const getFormDataSections = Task.async(function* (headers, uploadHeaders, postData,
|
||||
getString) {
|
||||
async function getFormDataSections(headers, uploadHeaders, postData, getString) {
|
||||
let formDataSections = [];
|
||||
|
||||
let requestHeaders = headers.headers;
|
||||
@ -32,11 +29,11 @@ const getFormDataSections = Task.async(function* (headers, uploadHeaders, postDa
|
||||
|
||||
let contentTypeLongString = contentTypeHeader ? contentTypeHeader.value : "";
|
||||
|
||||
let contentType = yield getString(contentTypeLongString);
|
||||
let contentType = await getString(contentTypeLongString);
|
||||
|
||||
if (contentType.includes("x-www-form-urlencoded")) {
|
||||
let postDataLongString = postData.postData.text;
|
||||
let text = yield getString(postDataLongString);
|
||||
let text = await getString(postDataLongString);
|
||||
|
||||
for (let section of text.split(/\r\n|\r|\n/)) {
|
||||
// Before displaying it, make sure this section of the POST data
|
||||
@ -48,7 +45,7 @@ const getFormDataSections = Task.async(function* (headers, uploadHeaders, postDa
|
||||
}
|
||||
|
||||
return formDataSections;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch headers full content from actor server
|
||||
@ -57,13 +54,12 @@ const getFormDataSections = Task.async(function* (headers, uploadHeaders, postDa
|
||||
* @param {function} getString - callback to retrieve a string from a LongStringGrip
|
||||
* @return {object} a headers object with updated content payload
|
||||
*/
|
||||
const fetchHeaders = Task.async(function* (headers, getString) {
|
||||
async function fetchHeaders(headers, getString) {
|
||||
for (let { value } of headers.headers) {
|
||||
headers.headers.value = yield getString(value);
|
||||
headers.headers.value = await getString(value);
|
||||
}
|
||||
|
||||
return headers;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Form a data: URI given a mime type, encoding, and some text.
|
||||
|
@ -4,11 +4,10 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
function getActiveFilters(state) {
|
||||
return state.filters.requestFilterTypes.toSeq()
|
||||
.filter(checked => checked).keySeq().toArray();
|
||||
function getRequestFilterTypes(state) {
|
||||
return state.filters.requestFilterTypes.entrySeq().toArray();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getActiveFilters
|
||||
getRequestFilterTypes,
|
||||
};
|
||||
|
@ -92,8 +92,8 @@ const getDisplayedRequestsSummary = createSelector(
|
||||
return {
|
||||
count: requests.size,
|
||||
contentSize: totalBytes.contentSize,
|
||||
transferredSize: totalBytes.transferredSize,
|
||||
millis: totalMillis,
|
||||
transferredSize: totalBytes.transferredSize,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
@ -162,7 +160,7 @@ const HeadersPanel = createClass({
|
||||
readOnly: true,
|
||||
value: `${status} ${statusText}`,
|
||||
}),
|
||||
NetMonitorController.supportsCustomRequest && button({
|
||||
window.NetMonitorController.supportsCustomRequest && button({
|
||||
className: "devtools-button",
|
||||
onClick: cloneSelectedRequest,
|
||||
}, EDIT_AND_RESEND),
|
||||
|
@ -2,12 +2,9 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals document */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
@ -15,84 +12,58 @@ const {
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const Actions = require("../../actions/index");
|
||||
const { getSelectedRequest } = require("../../selectors/index");
|
||||
const { Prefs } = require("../../prefs");
|
||||
|
||||
// Components
|
||||
const CustomRequestPanel = createFactory(require("./custom-request-panel"));
|
||||
const TabboxPanel = createFactory(require("./tabbox-panel"));
|
||||
|
||||
const { div } = DOM;
|
||||
|
||||
/*
|
||||
* Network details panel component
|
||||
*/
|
||||
const NetworkDetailsPanel = createClass({
|
||||
displayName: "NetworkDetailsPanel",
|
||||
|
||||
propTypes: {
|
||||
activeTabId: PropTypes.string,
|
||||
cloneSelectedRequest: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool,
|
||||
request: PropTypes.object,
|
||||
selectTab: PropTypes.func.isRequired,
|
||||
toolbox: PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
// FIXME: Workaround should be removed in bug 1309183
|
||||
document.getElementById("splitter-adjustable-box")
|
||||
.setAttribute("width", Prefs.networkDetailsWidth);
|
||||
document.getElementById("splitter-adjustable-box")
|
||||
.setAttribute("height", Prefs.networkDetailsHeight);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
// FIXME: Workaround should be removed in bug 1309183
|
||||
Prefs.networkDetailsWidth =
|
||||
document.getElementById("splitter-adjustable-box").getAttribute("width");
|
||||
Prefs.networkDetailsHeight =
|
||||
document.getElementById("splitter-adjustable-box").getAttribute("height");
|
||||
},
|
||||
|
||||
render() {
|
||||
let {
|
||||
activeTabId,
|
||||
cloneSelectedRequest,
|
||||
open,
|
||||
request,
|
||||
selectTab,
|
||||
toolbox,
|
||||
} = this.props;
|
||||
|
||||
if (!open || !request) {
|
||||
// FIXME: Workaround should be removed in bug 1309183
|
||||
document.getElementById("splitter-adjustable-box").setAttribute("hidden", true);
|
||||
return null;
|
||||
}
|
||||
// FIXME: Workaround should be removed in bug 1309183
|
||||
document.getElementById("splitter-adjustable-box").removeAttribute("hidden");
|
||||
|
||||
return (
|
||||
div({ className: "network-details-panel" },
|
||||
!request.isCustom ?
|
||||
TabboxPanel({
|
||||
activeTabId,
|
||||
request,
|
||||
selectTab,
|
||||
toolbox,
|
||||
}) :
|
||||
CustomRequestPanel({
|
||||
cloneSelectedRequest,
|
||||
request,
|
||||
})
|
||||
)
|
||||
);
|
||||
function NetworkDetailsPanel({
|
||||
activeTabId,
|
||||
cloneSelectedRequest,
|
||||
request,
|
||||
selectTab,
|
||||
toolbox,
|
||||
}) {
|
||||
if (!request) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
div({ className: "network-details-panel" },
|
||||
!request.isCustom ?
|
||||
TabboxPanel({
|
||||
activeTabId,
|
||||
request,
|
||||
selectTab,
|
||||
toolbox,
|
||||
}) :
|
||||
CustomRequestPanel({
|
||||
cloneSelectedRequest,
|
||||
request,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
NetworkDetailsPanel.displayName = "NetworkDetailsPanel";
|
||||
|
||||
NetworkDetailsPanel.propTypes = {
|
||||
activeTabId: PropTypes.string,
|
||||
cloneSelectedRequest: PropTypes.func.isRequired,
|
||||
open: PropTypes.bool,
|
||||
request: PropTypes.object,
|
||||
selectTab: PropTypes.func.isRequired,
|
||||
toolbox: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
activeTabId: state.ui.detailsPanelSelectedTab,
|
||||
open: state.ui.networkDetailsOpen,
|
||||
request: getSelectedRequest(state),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
|
@ -128,7 +128,6 @@ skip-if = (os == 'linux' && debug && bits == 32) # Bug 1303439
|
||||
[browser_net_post-data-04.js]
|
||||
[browser_net_prefs-and-l10n.js]
|
||||
[browser_net_prefs-reload.js]
|
||||
skip-if = true # bug 1309183, it should be fixed by SplitBox support
|
||||
[browser_net_raw_headers.js]
|
||||
[browser_net_reload-button.js]
|
||||
[browser_net_reload-markers.js]
|
||||
|
@ -25,42 +25,49 @@ add_task(function* () {
|
||||
yield wait;
|
||||
|
||||
wait = waitForDOM(document, "#params-panel .tree-section", 2);
|
||||
gStore.dispatch(Actions.selectRequestByIndex(0));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[0]);
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#params-tab"));
|
||||
yield wait;
|
||||
testParamsTab1("a", '""', '{ "foo": "bar" }', '""');
|
||||
|
||||
wait = waitForDOM(document, "#params-panel .tree-section", 2);
|
||||
gStore.dispatch(Actions.selectRequestByIndex(1));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[1]);
|
||||
yield wait;
|
||||
testParamsTab1("a", '"b"', '{ "foo": "bar" }', '""');
|
||||
|
||||
wait = waitForDOM(document, "#params-panel .tree-section", 2);
|
||||
gStore.dispatch(Actions.selectRequestByIndex(2));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[2]);
|
||||
yield wait;
|
||||
testParamsTab1("a", '"b"', "foo", '"bar"');
|
||||
|
||||
wait = waitForDOM(document, "#params-panel tr:not(.tree-section).treeRow", 2);
|
||||
gStore.dispatch(Actions.selectRequestByIndex(3));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[3]);
|
||||
yield wait;
|
||||
testParamsTab2("a", '""', '{ "foo": "bar" }', "js");
|
||||
|
||||
wait = waitForDOM(document, "#params-panel tr:not(.tree-section).treeRow", 2);
|
||||
gStore.dispatch(Actions.selectRequestByIndex(4));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[4]);
|
||||
yield wait;
|
||||
testParamsTab2("a", '"b"', '{ "foo": "bar" }', "js");
|
||||
|
||||
// Wait for all tree sections and editor updated by react
|
||||
let waitSections = waitForDOM(document, "#params-panel .tree-section", 2);
|
||||
let waitEditor = waitForDOM(document, "#params-panel .editor-mount iframe");
|
||||
gStore.dispatch(Actions.selectRequestByIndex(5));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[5]);
|
||||
let [, editorFrames] = yield Promise.all([waitSections, waitEditor]);
|
||||
yield once(editorFrames[0], "DOMContentLoaded");
|
||||
yield waitForDOM(editorFrames[0].contentDocument, ".CodeMirror-code");
|
||||
testParamsTab2("a", '"b"', "?foo=bar", "text");
|
||||
|
||||
gStore.dispatch(Actions.selectRequestByIndex(6));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[6]);
|
||||
testParamsTab3();
|
||||
|
||||
yield teardown(monitor);
|
||||
|
@ -57,8 +57,8 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-as-curl").click();
|
||||
}, function validate(result) {
|
||||
if (typeof result !== "string") {
|
||||
|
@ -42,8 +42,8 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-request-headers").click();
|
||||
}, function validate(result) {
|
||||
// Sometimes, a "Cookie" header is left over from other tests. Remove it:
|
||||
@ -67,8 +67,8 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// _oolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#response-menu-context-copy-response-headers").click();
|
||||
}, function validate(result) {
|
||||
// Fake the "Last-Modified" and "Date" headers because they will vary:
|
||||
|
@ -26,8 +26,8 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-image-as-data-uri").click();
|
||||
}, TEST_IMAGE_DATA_URI);
|
||||
|
||||
|
@ -62,7 +62,7 @@ add_task(function* () {
|
||||
document.querySelectorAll(".request-list-item")[index]);
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" },
|
||||
document.querySelectorAll(".request-list-item")[index]);
|
||||
let copyUrlParamsNode = monitor._toolbox.doc
|
||||
let copyUrlParamsNode = monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-url-params");
|
||||
is(!!copyUrlParamsNode, !hidden,
|
||||
"The \"Copy URL Parameters\" context menu item should" + (hidden ? " " : " not ") +
|
||||
@ -75,7 +75,7 @@ add_task(function* () {
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" },
|
||||
document.querySelectorAll(".request-list-item")[index]);
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
monitor._toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-url-params").click();
|
||||
}, queryString);
|
||||
ok(true, "The url query string copied from the selected item is correct.");
|
||||
@ -86,7 +86,7 @@ add_task(function* () {
|
||||
document.querySelectorAll(".request-list-item")[index]);
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" },
|
||||
document.querySelectorAll(".request-list-item")[index]);
|
||||
let copyPostDataNode = monitor._toolbox.doc
|
||||
let copyPostDataNode = monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-post-data");
|
||||
is(!!copyPostDataNode, !hidden,
|
||||
"The \"Copy POST Data\" context menu item should" + (hidden ? " " : " not ") +
|
||||
@ -99,7 +99,7 @@ add_task(function* () {
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" },
|
||||
document.querySelectorAll(".request-list-item")[index]);
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
monitor._toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-post-data").click();
|
||||
}, postData);
|
||||
ok(true, "The post data string copied from the selected item is correct.");
|
||||
|
@ -28,8 +28,8 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-response").click();
|
||||
}, EXPECTED_RESULT);
|
||||
|
||||
|
@ -28,8 +28,8 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-image-as-data-uri").click();
|
||||
}, function check(text) {
|
||||
return text.startsWith("data:") && !/undefined/.test(text);
|
||||
|
@ -29,8 +29,8 @@ add_task(function* () {
|
||||
|
||||
yield waitForClipboardPromise(function setup() {
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-copy-url").click();
|
||||
}, requestItem.url);
|
||||
|
||||
|
@ -21,7 +21,7 @@ add_task(function* test() {
|
||||
getDisplayedRequests,
|
||||
getSortedRequests,
|
||||
} = windowRequire("devtools/client/netmonitor/selectors/index");
|
||||
let toolboxDoc = monitor._toolbox.doc;
|
||||
let toolboxDoc = monitor.toolbox.doc;
|
||||
|
||||
gStore.dispatch(Actions.batchEnable(false));
|
||||
|
||||
@ -38,7 +38,7 @@ add_task(function* test() {
|
||||
// Hide tooltip before next test, to avoid the situation that tooltip covers
|
||||
// the icon for the request of the next test.
|
||||
info("Checking the image thumbnail gets hidden...");
|
||||
yield hideTooltipAndVerify(monitor._toolbox.doc,
|
||||
yield hideTooltipAndVerify(monitor.toolbox.doc,
|
||||
document.querySelectorAll(".request-list-item")[0]);
|
||||
|
||||
// +1 extra document reload
|
||||
|
@ -33,8 +33,8 @@ add_task(function* () {
|
||||
|
||||
let onTabOpen = once(gBrowser.tabContainer, "TabOpen", false);
|
||||
// Context menu is appending in XUL document, we must select it from
|
||||
// _toolbox.doc
|
||||
monitor._toolbox.doc
|
||||
// toolbox.doc
|
||||
monitor.toolbox.doc
|
||||
.querySelector("#request-menu-context-newtab").click();
|
||||
yield onTabOpen;
|
||||
|
||||
|
@ -8,11 +8,10 @@
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
let Actions = require("devtools/client/netmonitor/actions/index");
|
||||
let { getActiveFilters } = require("devtools/client/netmonitor/selectors/index");
|
||||
|
||||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
let { document, gStore, Prefs } = monitor.panelWin;
|
||||
let { getRequestFilterTypes } = monitor.panelWin
|
||||
.windowRequire("devtools/client/netmonitor/selectors/index");
|
||||
let Actions = monitor.panelWin.windowRequire("devtools/client/netmonitor/actions/index");
|
||||
info("Starting test... ");
|
||||
|
||||
// This test reopens the network monitor a bunch of times, for different
|
||||
@ -22,7 +21,9 @@ add_task(function* () {
|
||||
// Use these getters instead of caching instances inside the panel win,
|
||||
// since the tool is reopened a bunch of times during this test
|
||||
// and the instances will differ.
|
||||
let getStore = () => gStore;
|
||||
let getDoc = () => monitor.panelWin.document;
|
||||
let getPrefs = () => monitor.panelWin.windowRequire("devtools/client/netmonitor/prefs").Prefs;
|
||||
let getStore = () => monitor.panelWin.gStore;
|
||||
let getState = () => getStore().getState();
|
||||
|
||||
let prefsToCheck = {
|
||||
@ -31,7 +32,9 @@ add_task(function* () {
|
||||
newValue: ["html", "css"],
|
||||
// Getter used to retrieve the current value from the frontend, in order
|
||||
// to verify that the pref was applied properly.
|
||||
validateValue: () => getActiveFilters(getState()),
|
||||
validateValue: () => getRequestFilterTypes(getState())
|
||||
.filter(([type, check]) => check)
|
||||
.map(([type, check]) => type),
|
||||
// Predicate used to modify the frontend when setting the new pref value,
|
||||
// before trying to validate the changes.
|
||||
modifyFrontend: (value) => value.forEach(e =>
|
||||
@ -40,16 +43,16 @@ add_task(function* () {
|
||||
networkDetailsWidth: {
|
||||
newValue: ~~(Math.random() * 200 + 100),
|
||||
validateValue: () =>
|
||||
~~document.querySelector(".network-details-panel").getAttribute("width"),
|
||||
getDoc().querySelector(".monitor-panel .split-box .controlled").clientWidth,
|
||||
modifyFrontend: (value) =>
|
||||
document.querySelector(".network-details-panel").setAttribute("width", value)
|
||||
getDoc().querySelector(".monitor-panel .split-box .controlled").style.width = `${value}px`,
|
||||
},
|
||||
networkDetailsHeight: {
|
||||
newValue: ~~(Math.random() * 300 + 100),
|
||||
validateValue: () =>
|
||||
~~document.querySelector(".network-details-panel").getAttribute("height"),
|
||||
getDoc().querySelector(".monitor-panel .split-box .controlled").clientHeight,
|
||||
modifyFrontend: (value) =>
|
||||
document.querySelector(".network-details-panel").setAttribute("height", value)
|
||||
getDoc().querySelector(".monitor-panel .split-box .controlled").style.height = `${value}px`
|
||||
}
|
||||
/* add more prefs here... */
|
||||
};
|
||||
@ -59,38 +62,48 @@ add_task(function* () {
|
||||
yield testWindow();
|
||||
|
||||
info("Moving toolbox back to the bottom...");
|
||||
yield monitor._toolbox.switchHost(Toolbox.HostType.BOTTOM);
|
||||
yield monitor.toolbox.switchHost(Toolbox.HostType.BOTTOM);
|
||||
return teardown(monitor);
|
||||
|
||||
function storeFirstPrefValues() {
|
||||
info("Caching initial pref values.");
|
||||
|
||||
for (let name in prefsToCheck) {
|
||||
let currentValue = Prefs[name];
|
||||
let currentValue = getPrefs()[name];
|
||||
prefsToCheck[name].firstValue = currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
function validateFirstPrefValues() {
|
||||
function validateFirstPrefValues(isVerticalSplitter) {
|
||||
info("Validating current pref values to the UI elements.");
|
||||
|
||||
for (let name in prefsToCheck) {
|
||||
let currentValue = Prefs[name];
|
||||
if ((isVerticalSplitter && name === "networkDetailsHeight") ||
|
||||
(!isVerticalSplitter && name === "networkDetailsWidth")) {
|
||||
continue
|
||||
}
|
||||
|
||||
let currentValue = getPrefs()[name];
|
||||
let firstValue = prefsToCheck[name].firstValue;
|
||||
let validateValue = prefsToCheck[name].validateValue;
|
||||
|
||||
is(currentValue.toSource(), firstValue.toSource(),
|
||||
"Pref " + name + " should be equal to first value: " + firstValue);
|
||||
is(currentValue.toSource(), validateValue().toSource(),
|
||||
is(firstValue.toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should be equal to first value: " + currentValue);
|
||||
is(validateValue().toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should validate: " + currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
function modifyFrontend() {
|
||||
function modifyFrontend(isVerticalSplitter) {
|
||||
info("Modifying UI elements to the specified new values.");
|
||||
|
||||
for (let name in prefsToCheck) {
|
||||
let currentValue = Prefs[name];
|
||||
if ((isVerticalSplitter && name === "networkDetailsHeight") ||
|
||||
(!isVerticalSplitter && name === "networkDetailsWidth")) {
|
||||
continue
|
||||
}
|
||||
|
||||
let currentValue = getPrefs()[name];
|
||||
let firstValue = prefsToCheck[name].firstValue;
|
||||
let newValue = prefsToCheck[name].newValue;
|
||||
let validateValue = prefsToCheck[name].validateValue;
|
||||
@ -99,38 +112,48 @@ add_task(function* () {
|
||||
modFrontend(newValue);
|
||||
info("Modified UI element affecting " + name + " to: " + newValue);
|
||||
|
||||
is(currentValue.toSource(), firstValue.toSource(),
|
||||
"Pref " + name + " should still be equal to first value: " + firstValue);
|
||||
isnot(currentValue.toSource(), newValue.toSource(),
|
||||
"Pref " + name + " should't yet be equal to second value: " + newValue);
|
||||
is(newValue.toSource(), validateValue().toSource(),
|
||||
is(firstValue.toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should still be equal to first value: " + currentValue);
|
||||
isnot(newValue.toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should't yet be equal to second value: " + currentValue);
|
||||
is(validateValue().toSource(), newValue.toSource(),
|
||||
"The UI element affecting " + name + " should validate: " + newValue);
|
||||
}
|
||||
}
|
||||
|
||||
function validateNewPrefValues() {
|
||||
function validateNewPrefValues(isVerticalSplitter) {
|
||||
info("Invalidating old pref values to the modified UI elements.");
|
||||
|
||||
for (let name in prefsToCheck) {
|
||||
let currentValue = Prefs[name];
|
||||
if ((isVerticalSplitter && name === "networkDetailsHeight") ||
|
||||
(!isVerticalSplitter && name === "networkDetailsWidth")) {
|
||||
continue
|
||||
}
|
||||
|
||||
let currentValue = getPrefs()[name];
|
||||
let firstValue = prefsToCheck[name].firstValue;
|
||||
let newValue = prefsToCheck[name].newValue;
|
||||
let validateValue = prefsToCheck[name].validateValue;
|
||||
|
||||
isnot(currentValue.toSource(), firstValue.toSource(),
|
||||
"Pref " + name + " should't be equal to first value: " + firstValue);
|
||||
is(currentValue.toSource(), newValue.toSource(),
|
||||
"Pref " + name + " should now be equal to second value: " + newValue);
|
||||
is(newValue.toSource(), validateValue().toSource(),
|
||||
isnot(firstValue.toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should't be equal to first value: " + currentValue);
|
||||
is(newValue.toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should now be equal to second value: " + currentValue);
|
||||
is(validateValue().toSource(), newValue.toSource(),
|
||||
"The UI element affecting " + name + " should validate: " + newValue);
|
||||
}
|
||||
}
|
||||
|
||||
function resetFrontend() {
|
||||
function resetFrontend(isVerticalSplitter) {
|
||||
info("Resetting UI elements to the cached initial pref values.");
|
||||
|
||||
for (let name in prefsToCheck) {
|
||||
let currentValue = Prefs[name];
|
||||
if ((isVerticalSplitter && name === "networkDetailsHeight") ||
|
||||
(!isVerticalSplitter && name === "networkDetailsWidth")) {
|
||||
continue
|
||||
}
|
||||
|
||||
let currentValue = getPrefs()[name];
|
||||
let firstValue = prefsToCheck[name].firstValue;
|
||||
let newValue = prefsToCheck[name].newValue;
|
||||
let validateValue = prefsToCheck[name].validateValue;
|
||||
@ -139,84 +162,98 @@ add_task(function* () {
|
||||
modFrontend(firstValue);
|
||||
info("Modified UI element affecting " + name + " to: " + firstValue);
|
||||
|
||||
isnot(currentValue.toSource(), firstValue.toSource(),
|
||||
"Pref " + name + " should't yet be equal to first value: " + firstValue);
|
||||
is(currentValue.toSource(), newValue.toSource(),
|
||||
"Pref " + name + " should still be equal to second value: " + newValue);
|
||||
is(firstValue.toSource(), validateValue().toSource(),
|
||||
isnot(firstValue.toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should't yet be equal to first value: " + currentValue);
|
||||
is(newValue.toSource(), currentValue.toSource(),
|
||||
"Pref " + name + " should still be equal to second value: " + currentValue);
|
||||
is(validateValue().toSource(), firstValue.toSource(),
|
||||
"The UI element affecting " + name + " should validate: " + firstValue);
|
||||
}
|
||||
}
|
||||
|
||||
function* restartNetMonitorAndSetupEnv() {
|
||||
let newMonitor = yield restartNetMonitor(monitor);
|
||||
monitor = newMonitor.monitor;
|
||||
|
||||
let networkEvent = waitForNetworkEvents(monitor, 1);
|
||||
newMonitor.tab.linkedBrowser.reload();
|
||||
yield networkEvent;
|
||||
|
||||
let wait = waitForDOM(getDoc(), ".network-details-panel");
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
getDoc().querySelector(".network-details-panel-toggle"));
|
||||
yield wait;
|
||||
}
|
||||
|
||||
function* testBottom() {
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
info("Testing prefs reload for a bottom host.");
|
||||
storeFirstPrefValues();
|
||||
|
||||
// Validate and modify while toolbox is on the bottom.
|
||||
validateFirstPrefValues();
|
||||
modifyFrontend();
|
||||
validateFirstPrefValues(true);
|
||||
modifyFrontend(true);
|
||||
|
||||
let newMonitor = yield restartNetMonitor(monitor);
|
||||
monitor = newMonitor.monitor;
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
// Revalidate and reset frontend while toolbox is on the bottom.
|
||||
validateNewPrefValues();
|
||||
resetFrontend();
|
||||
validateNewPrefValues(true);
|
||||
resetFrontend(true);
|
||||
|
||||
newMonitor = yield restartNetMonitor(monitor);
|
||||
monitor = newMonitor.monitor;
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
// Revalidate.
|
||||
validateFirstPrefValues();
|
||||
validateFirstPrefValues(true);
|
||||
}
|
||||
|
||||
function* testSide() {
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
info("Moving toolbox to the side...");
|
||||
|
||||
yield monitor._toolbox.switchHost(Toolbox.HostType.SIDE);
|
||||
yield monitor.toolbox.switchHost(Toolbox.HostType.SIDE);
|
||||
info("Testing prefs reload for a side host.");
|
||||
storeFirstPrefValues();
|
||||
|
||||
// Validate and modify frontend while toolbox is on the side.
|
||||
validateFirstPrefValues();
|
||||
modifyFrontend();
|
||||
validateFirstPrefValues(false);
|
||||
modifyFrontend(false);
|
||||
|
||||
let newMonitor = yield restartNetMonitor(monitor);
|
||||
monitor = newMonitor.monitor;
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
// Revalidate and reset frontend while toolbox is on the side.
|
||||
validateNewPrefValues();
|
||||
resetFrontend();
|
||||
validateNewPrefValues(false);
|
||||
resetFrontend(false);
|
||||
|
||||
newMonitor = yield restartNetMonitor(monitor);
|
||||
monitor = newMonitor.monitor;
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
// Revalidate.
|
||||
validateFirstPrefValues();
|
||||
validateFirstPrefValues(false);
|
||||
}
|
||||
|
||||
function* testWindow() {
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
info("Moving toolbox into a window...");
|
||||
|
||||
yield monitor._toolbox.switchHost(Toolbox.HostType.WINDOW);
|
||||
yield monitor.toolbox.switchHost(Toolbox.HostType.WINDOW);
|
||||
info("Testing prefs reload for a window host.");
|
||||
storeFirstPrefValues();
|
||||
|
||||
// Validate and modify frontend while toolbox is in a window.
|
||||
validateFirstPrefValues();
|
||||
modifyFrontend();
|
||||
validateFirstPrefValues(true);
|
||||
modifyFrontend(true);
|
||||
|
||||
let newMonitor = yield restartNetMonitor(monitor);
|
||||
monitor = newMonitor.monitor;
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
// Revalidate and reset frontend while toolbox is in a window.
|
||||
validateNewPrefValues();
|
||||
resetFrontend();
|
||||
validateNewPrefValues(true);
|
||||
resetFrontend(true);
|
||||
|
||||
newMonitor = yield restartNetMonitor(monitor);
|
||||
monitor = newMonitor.monitor;
|
||||
yield restartNetMonitorAndSetupEnv();
|
||||
|
||||
// Revalidate.
|
||||
validateFirstPrefValues();
|
||||
validateFirstPrefValues(true);
|
||||
}
|
||||
});
|
||||
|
@ -32,13 +32,13 @@ add_task(function* () {
|
||||
verifyRequest(0);
|
||||
|
||||
// Switch to the webconsole.
|
||||
let onWebConsole = monitor._toolbox.once("webconsole-selected");
|
||||
monitor._toolbox.selectTool("webconsole");
|
||||
let onWebConsole = monitor.toolbox.once("webconsole-selected");
|
||||
monitor.toolbox.selectTool("webconsole");
|
||||
yield onWebConsole;
|
||||
|
||||
// Switch back to the netmonitor.
|
||||
let onNetMonitor = monitor._toolbox.once("netmonitor-selected");
|
||||
monitor._toolbox.selectTool("netmonitor");
|
||||
let onNetMonitor = monitor.toolbox.once("netmonitor-selected");
|
||||
monitor.toolbox.selectTool("netmonitor");
|
||||
yield onNetMonitor;
|
||||
|
||||
// Reload debugee.
|
||||
|
@ -22,8 +22,6 @@ function test() {
|
||||
function checkIfInitialized(tag) {
|
||||
info(`Checking if initialization is ok (${tag}).`);
|
||||
|
||||
ok(monitor.panelWin.NetMonitorView,
|
||||
`The network monitor view object exists (${tag}).`);
|
||||
ok(monitor.panelWin.NetMonitorController,
|
||||
`The network monitor controller object exists (${tag}).`);
|
||||
ok(monitor.panelWin.NetMonitorController._startup,
|
||||
@ -43,8 +41,6 @@ function test() {
|
||||
function checkIfDestroyed(tag) {
|
||||
gInfo("Checking if destruction is ok.");
|
||||
|
||||
gOk(monitor.panelWin.NetMonitorView,
|
||||
`The network monitor view object still exists (${tag}).`);
|
||||
gOk(monitor.panelWin.NetMonitorController,
|
||||
`The network monitor controller object still exists (${tag}).`);
|
||||
gOk(monitor.panelWin.NetMonitorController._shutdown,
|
||||
|
@ -4,7 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if the statistics view is populated correctly.
|
||||
* Tests if the statistics panel displays correctly.
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
@ -15,36 +15,27 @@ add_task(function* () {
|
||||
let { document, gStore, windowRequire } = panel;
|
||||
let Actions = windowRequire("devtools/client/netmonitor/actions/index");
|
||||
|
||||
let body = document.querySelector("#body");
|
||||
|
||||
is(body.selectedPanel.id, "inspector-panel",
|
||||
ok(document.querySelector(".monitor-panel"),
|
||||
"The current main panel is correct.");
|
||||
|
||||
info("Displaying statistics view");
|
||||
info("Displaying statistics panel");
|
||||
gStore.dispatch(Actions.openStatistics(true));
|
||||
|
||||
is(body.selectedPanel.id, "react-statistics-panel-hook",
|
||||
ok(document.querySelector(".statistics-panel"),
|
||||
"The current main panel is correct.");
|
||||
|
||||
info("Waiting for placeholder to display");
|
||||
|
||||
is(document.querySelector(".primed-cache-chart").childNodes.length, 1,
|
||||
"There should be a placeholder primed cache chart created now.");
|
||||
is(document.querySelector(".empty-cache-chart").childNodes.length, 1,
|
||||
"There should be a placeholder empty cache chart created now.");
|
||||
yield waitUntil(
|
||||
() => document.querySelectorAll(".pie-chart-container[placeholder=true]").length == 2);
|
||||
ok(true, "Two placeholder pie charts appear to be rendered correctly.");
|
||||
|
||||
is(document.querySelectorAll(".pie-chart-container[placeholder=true]").length, 2,
|
||||
"Two placeholder pie chart appear to be rendered correctly.");
|
||||
is(document.querySelectorAll(".table-chart-container[placeholder=true]").length, 2,
|
||||
"Two placeholder table chart appear to be rendered correctly.");
|
||||
yield waitUntil(
|
||||
() => document.querySelectorAll(".table-chart-container[placeholder=true]").length == 2);
|
||||
ok(true, "Two placeholde table charts appear to be rendered correctly.");
|
||||
|
||||
info("Waiting for chart to display");
|
||||
|
||||
is(document.querySelector(".primed-cache-chart").childNodes.length, 1,
|
||||
"There should be a real primed cache chart created now.");
|
||||
is(document.querySelector(".empty-cache-chart").childNodes.length, 1,
|
||||
"There should be a real empty cache chart created now.");
|
||||
|
||||
yield waitUntil(
|
||||
() => document.querySelectorAll(".pie-chart-container:not([placeholder=true])").length == 2);
|
||||
ok(true, "Two real pie charts appear to be rendered correctly.");
|
||||
|
@ -31,9 +31,7 @@ add_task(function* () {
|
||||
|
||||
gStore.dispatch(Actions.openStatistics(true));
|
||||
|
||||
let body = document.querySelector("#body");
|
||||
|
||||
is(body.selectedPanel.id, "react-statistics-panel-hook",
|
||||
ok(document.querySelector(".statistics-panel"),
|
||||
"The main panel is switched to the statistics panel.");
|
||||
|
||||
yield waitUntil(
|
||||
@ -43,8 +41,8 @@ add_task(function* () {
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector(".pie-chart-slice"));
|
||||
|
||||
is(body.selectedPanel.id, "inspector-panel",
|
||||
"The main panel is switched back to the inspector panel.");
|
||||
ok(document.querySelector(".monitor-panel"),
|
||||
"The main panel is switched back to the monitor panel.");
|
||||
|
||||
testFilterButtons(monitor, "html");
|
||||
info("The correct filtering predicate is used when exiting perf. analysis mode.");
|
||||
|
@ -152,7 +152,7 @@ function restartNetMonitor(monitor, newUrl) {
|
||||
info("Restarting the specified network monitor.");
|
||||
|
||||
return Task.spawn(function* () {
|
||||
let tab = monitor.target.tab;
|
||||
let tab = monitor.toolbox.target.tab;
|
||||
let url = newUrl || tab.linkedBrowser.currentURI.spec;
|
||||
|
||||
let onDestroyed = monitor.once("destroyed");
|
||||
@ -167,7 +167,7 @@ function teardown(monitor) {
|
||||
info("Destroying the specified network monitor.");
|
||||
|
||||
return Task.spawn(function* () {
|
||||
let tab = monitor.target.tab;
|
||||
let tab = monitor.toolbox.target.tab;
|
||||
|
||||
let onDestroyed = monitor.once("destroyed");
|
||||
yield removeTab(tab);
|
||||
@ -249,16 +249,6 @@ function waitForNetworkEvents(aMonitor, aGetRequests, aPostRequests = 0) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a store record (model) to the rendered element. Tests that need to use
|
||||
* this should be rewritten - test the rendered markup at unit level, integration
|
||||
* mochitest should check only the store state.
|
||||
*/
|
||||
function getItemTarget(requestList, requestItem) {
|
||||
const items = requestList.mountPoint.querySelectorAll(".request-list-item");
|
||||
return [...items].find(el => el.dataset.id == requestItem.id);
|
||||
}
|
||||
|
||||
function verifyRequestItemTarget(document, requestList, requestItem, aMethod,
|
||||
aUrl, aData = {}) {
|
||||
info("> Verifying: " + aMethod + " " + aUrl + " " + aData.toSource());
|
||||
|
@ -20,23 +20,23 @@ const SplitBox = React.createClass({
|
||||
// Custom class name. You can use more names separated by a space.
|
||||
className: PropTypes.string,
|
||||
// Initial size of controlled panel.
|
||||
initialSize: PropTypes.number,
|
||||
initialSize: PropTypes.string,
|
||||
// Initial width of controlled panel.
|
||||
initialWidth: PropTypes.number,
|
||||
initialWidth: PropTypes.string,
|
||||
// Initial height of controlled panel.
|
||||
initialHeight: PropTypes.number,
|
||||
initialHeight: PropTypes.string,
|
||||
// Left/top panel
|
||||
startPanel: PropTypes.any,
|
||||
// Min panel size.
|
||||
minSize: PropTypes.number,
|
||||
minSize: PropTypes.string,
|
||||
// Max panel size.
|
||||
maxSize: PropTypes.number,
|
||||
maxSize: PropTypes.string,
|
||||
// Right/bottom panel
|
||||
endPanel: PropTypes.any,
|
||||
// True if the right/bottom panel should be controlled.
|
||||
endPanelControl: PropTypes.bool,
|
||||
// Size of the splitter handle bar.
|
||||
splitterSize: PropTypes.number,
|
||||
splitterSize: PropTypes.string,
|
||||
// True if the splitter bar is vertical (default is vertical).
|
||||
vert: PropTypes.bool,
|
||||
// Style object.
|
||||
@ -64,6 +64,14 @@ const SplitBox = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
let { vert } = nextProps;
|
||||
|
||||
if (vert !== this.props.vert) {
|
||||
this.setState({ vert });
|
||||
}
|
||||
},
|
||||
|
||||
// Dragging Events
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@ let Tabbar = createClass({
|
||||
displayName: "Tabbar",
|
||||
|
||||
propTypes: {
|
||||
children: PropTypes.object,
|
||||
children: PropTypes.array,
|
||||
onSelect: PropTypes.func,
|
||||
showAllTabsMenu: PropTypes.bool,
|
||||
activeTabId: PropTypes.string,
|
||||
|
@ -9,7 +9,9 @@
|
||||
// A helper actor for inspector and markupview tests.
|
||||
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const {getRect, getElementFromPoint, getAdjustedQuads} = require("devtools/shared/layout/utils");
|
||||
const {
|
||||
getRect, getElementFromPoint, getAdjustedQuads, getWindowDimensions
|
||||
} = require("devtools/shared/layout/utils");
|
||||
const defer = require("devtools/shared/defer");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
const {isContentStylesheet} = require("devtools/shared/inspector/css-logic");
|
||||
@ -289,6 +291,12 @@ var testSpec = protocol.generateActorSpec({
|
||||
response: {
|
||||
value: RetVal("json")
|
||||
}
|
||||
},
|
||||
getWindowDimensions: {
|
||||
request: {},
|
||||
response: {
|
||||
value: RetVal("json")
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -782,6 +790,16 @@ var TestActor = exports.TestActor = protocol.ActorClassWithSpec(testSpec, {
|
||||
}
|
||||
|
||||
return sheets;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the window's dimensions for the `window` given.
|
||||
*
|
||||
* @return {Object} An object with `width` and `height` properties, representing the
|
||||
* number of pixels for the document's size.
|
||||
*/
|
||||
getWindowDimensions: function () {
|
||||
return getWindowDimensions(this.content);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
* 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/. */
|
||||
|
||||
@import "resource://devtools/client/shared/components/splitter/split-box.css";
|
||||
@import "resource://devtools/client/shared/components/tree/tree-view.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/tabs.css";
|
||||
@import "resource://devtools/client/shared/components/tabs/tabbar.css";
|
||||
@ -85,6 +86,8 @@
|
||||
.request-list-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.request-list-empty-notice {
|
||||
@ -135,12 +138,8 @@
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
--timings-scale: 1;
|
||||
--timings-rev-scale: 1;
|
||||
|
||||
/* Devtools panel view height - tabbar height - toolbar height */
|
||||
height: calc(100vh - 48px);
|
||||
}
|
||||
|
||||
.requests-menu-subitem {
|
||||
@ -149,6 +148,7 @@
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
padding: 3px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.subitem-label {
|
||||
@ -757,10 +757,9 @@
|
||||
/* Custom request view */
|
||||
|
||||
.custom-request-panel {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
/* Full view hight - toolbar height */
|
||||
height: calc(100vh - 24px);
|
||||
padding: 6px 4px;
|
||||
padding: 0 4px;
|
||||
background-color: var(--theme-sidebar-background);
|
||||
}
|
||||
|
||||
@ -858,7 +857,7 @@
|
||||
border-color: rgba(0,0,0,0.2);
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.statistics-panel .charts-container {
|
||||
@ -872,12 +871,22 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pie-table-chart-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.statistics-panel .pie-chart-container {
|
||||
margin-inline-start: 3vw;
|
||||
margin-inline-end: 1vw;
|
||||
}
|
||||
|
||||
.statistics-panel .table-chart-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
min-width: 240px;
|
||||
margin-inline-start: 1vw;
|
||||
margin-inline-end: 3vw;
|
||||
}
|
||||
@ -922,6 +931,10 @@
|
||||
background: var(--theme-highlight-red);
|
||||
}
|
||||
|
||||
.table-chart-row {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.table-chart-row-label[name=cached] {
|
||||
display: none;
|
||||
}
|
||||
@ -933,14 +946,22 @@
|
||||
|
||||
.table-chart-row-label[name=label] {
|
||||
width: 7em;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.table-chart-row-label[name=size] {
|
||||
width: 7em;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.table-chart-row-label[name=time] {
|
||||
width: 7em;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.table-chart-totals {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Firebug theme support for network charts */
|
||||
@ -1002,15 +1023,6 @@
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.custom-request-panel {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#details-pane {
|
||||
margin: 0 !important;
|
||||
/* To prevent all the margin hacks to hide the sidebar. */
|
||||
}
|
||||
|
||||
.requests-menu-status {
|
||||
max-width: none;
|
||||
width: 10vw;
|
||||
@ -1048,11 +1060,13 @@
|
||||
|
||||
.statistics-panel .charts-container {
|
||||
flex-direction: column;
|
||||
/* Minus 4em for statistics back button width */
|
||||
width: calc(100% - 4em);
|
||||
}
|
||||
|
||||
.statistics-panel .splitter {
|
||||
width: 100vw;
|
||||
height: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1263,40 +1277,22 @@
|
||||
}
|
||||
|
||||
.network-details-panel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: normal html block element cannot fill outer XUL element
|
||||
* This workaround should be removed after netmonitor is migrated to react
|
||||
*/
|
||||
#network-table {
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#react-network-details-panel-hook,
|
||||
#react-statistics-panel-hook,
|
||||
#splitter-adjustable-box {
|
||||
.split-box {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
.root,
|
||||
.network-monitor,
|
||||
.monitor-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 50px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#splitter-adjustable-box[hidden=true] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#react-request-list-hook {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#primed-cache-chart,
|
||||
#empty-cache-chart {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
@ -35,8 +35,16 @@
|
||||
--highlighter-bubble-border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlighters are asbolute positioned in the page by default.
|
||||
* A single highlighter can have fixed position in its css class if needed (see below the
|
||||
* eye dropper or rulers highlighter, for example); but if it has to handle the
|
||||
* document's scrolling (as rulers does), it would lag a bit behind due the APZ (Async
|
||||
* Pan/Zoom module), that performs asynchronously panning and zooming on the compositor
|
||||
* thread rather than the main thread.
|
||||
*/
|
||||
:-moz-native-anonymous .highlighter-container {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* The container for all highlighters doesn't react to pointer-events by
|
||||
@ -383,6 +391,10 @@
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
:-moz-native-anonymous .measuring-tool-highlighter-elements {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
:-moz-native-anonymous .measuring-tool-highlighter-root path {
|
||||
shape-rendering: crispEdges;
|
||||
fill: rgba(135, 206, 235, 0.6);
|
||||
@ -443,7 +455,7 @@
|
||||
--label-height: 23px;
|
||||
--color: #e0e0e0;
|
||||
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
/* Tool start position. This should match the X/Y defines in JS */
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
|
@ -7,11 +7,41 @@
|
||||
const { Cu } = require("chrome");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { isNodeValid } = require("./utils/markup");
|
||||
const { getAdjustedQuads } = require("devtools/shared/layout/utils");
|
||||
const { getAdjustedQuads, getCurrentZoom,
|
||||
getWindowDimensions } = require("devtools/shared/layout/utils");
|
||||
|
||||
// Note that the order of items in this array is important because it is used
|
||||
// for drawing the BoxModelHighlighter's path elements correctly.
|
||||
const BOX_MODEL_REGIONS = ["margin", "border", "padding", "content"];
|
||||
const QUADS_PROPS = ["p1", "p2", "p3", "p4", "bounds"];
|
||||
|
||||
function areValuesDifferent(oldValue, newValue, zoom) {
|
||||
let delta = Math.abs(oldValue.toFixed(4) - newValue.toFixed(4));
|
||||
return delta / zoom > 1 / zoom;
|
||||
}
|
||||
|
||||
function areQuadsDifferent(oldQuads, newQuads, zoom) {
|
||||
for (let region of BOX_MODEL_REGIONS) {
|
||||
if (oldQuads[region].length !== newQuads[region].length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let i = 0; i < oldQuads[region].length; i++) {
|
||||
for (let prop of QUADS_PROPS) {
|
||||
let oldProp = oldQuads[region][i][prop];
|
||||
let newProp = newQuads[region][i][prop];
|
||||
|
||||
for (let key of Object.keys(oldProp)) {
|
||||
if (areValuesDifferent(oldProp[key], newProp[key], zoom)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for auto-refresh-on-change highlighters. Sub classes will have a
|
||||
@ -41,6 +71,8 @@ function AutoRefreshHighlighter(highlighterEnv) {
|
||||
this.currentNode = null;
|
||||
this.currentQuads = {};
|
||||
|
||||
this._winDimensions = getWindowDimensions(this.win);
|
||||
|
||||
this.update = this.update.bind(this);
|
||||
}
|
||||
|
||||
@ -139,6 +171,8 @@ AutoRefreshHighlighter.prototype = {
|
||||
* Update the stored box quads by reading the current node's box quads.
|
||||
*/
|
||||
_updateAdjustedQuads: function () {
|
||||
this.currentQuads = {};
|
||||
|
||||
for (let region of BOX_MODEL_REGIONS) {
|
||||
this.currentQuads[region] = getAdjustedQuads(
|
||||
this.win,
|
||||
@ -152,17 +186,32 @@ AutoRefreshHighlighter.prototype = {
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_hasMoved: function () {
|
||||
let oldQuads = JSON.stringify(this.currentQuads);
|
||||
let oldQuads = this.currentQuads;
|
||||
this._updateAdjustedQuads();
|
||||
let newQuads = JSON.stringify(this.currentQuads);
|
||||
return oldQuads !== newQuads;
|
||||
|
||||
return areQuadsDifferent(oldQuads, this.currentQuads, getCurrentZoom(this.win));
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the knowledge we have of the current window's dimensions and return `true`
|
||||
* if they have changed since.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
_haveWindowDimensionsChanged: function () {
|
||||
let { width, height } = getWindowDimensions(this.win);
|
||||
let haveChanged = (this._winDimensions.width !== width ||
|
||||
this._winDimensions.height !== height);
|
||||
|
||||
this._winDimensions = { width, height };
|
||||
return haveChanged;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the highlighter if the node has moved since the last update.
|
||||
*/
|
||||
update: function () {
|
||||
if (!this._isNodeValid(this.currentNode) || !this._hasMoved()) {
|
||||
if (!this._isNodeValid(this.currentNode) ||
|
||||
(!this._hasMoved() && !this._haveWindowDimensionsChanged())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,8 @@ const {
|
||||
} = require("./utils/markup");
|
||||
const {
|
||||
getCurrentZoom,
|
||||
setIgnoreLayoutChanges
|
||||
setIgnoreLayoutChanges,
|
||||
getWindowDimensions
|
||||
} = require("devtools/shared/layout/utils");
|
||||
const { stringifyGridFragments } = require("devtools/server/actors/utils/css-grid-utils");
|
||||
|
||||
@ -118,11 +119,20 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
let root = createNode(this.win, {
|
||||
parent: container,
|
||||
attributes: {
|
||||
"id": "root",
|
||||
"class": "root"
|
||||
},
|
||||
prefix: this.ID_CLASS_PREFIX
|
||||
});
|
||||
|
||||
// We use a <canvas> element so that we can draw an arbitrary number of lines
|
||||
// which wouldn't be possible with HTML or SVG without having to insert and remove
|
||||
// the whole markup on every update.
|
||||
createNode(this.win, {
|
||||
parent: container,
|
||||
parent: root,
|
||||
nodeType: "canvas",
|
||||
attributes: {
|
||||
"id": "canvas",
|
||||
@ -135,7 +145,7 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
||||
// Build the SVG element
|
||||
let svg = createSVGNode(this.win, {
|
||||
nodeType: "svg",
|
||||
parent: container,
|
||||
parent: root,
|
||||
attributes: {
|
||||
"id": "elements",
|
||||
"width": "100%",
|
||||
@ -355,8 +365,16 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
||||
_update() {
|
||||
setIgnoreLayoutChanges(true);
|
||||
|
||||
let root = this.getElement("root");
|
||||
// Hide the root element and force the reflow in order to get the proper window's
|
||||
// dimensions without increasing them.
|
||||
root.setAttribute("style", "display: none");
|
||||
this.currentNode.offsetWidth;
|
||||
|
||||
let { width, height } = getWindowDimensions(this.win);
|
||||
|
||||
// Clear the canvas the grid area highlights.
|
||||
this.clearCanvas();
|
||||
this.clearCanvas(width, height);
|
||||
this.clearGridAreas();
|
||||
|
||||
// Start drawing the grid fragments.
|
||||
@ -375,6 +393,9 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
||||
|
||||
this._showGrid();
|
||||
|
||||
root.setAttribute("style",
|
||||
`position:absolute; width:${width}px;height:${height}px; overflow:hidden`);
|
||||
|
||||
setIgnoreLayoutChanges(false, this.highlighterEnv.window.document.documentElement);
|
||||
return true;
|
||||
},
|
||||
@ -434,15 +455,13 @@ CssGridHighlighter.prototype = extend(AutoRefreshHighlighter.prototype, {
|
||||
moveInfobar(container, bounds, this.win);
|
||||
},
|
||||
|
||||
clearCanvas() {
|
||||
clearCanvas(width, height) {
|
||||
let ratio = parseFloat((this.win.devicePixelRatio || 1).toFixed(2));
|
||||
let width = this.win.innerWidth;
|
||||
let height = this.win.innerHeight;
|
||||
|
||||
// Resize the canvas taking the dpr into account so as to have crisp lines.
|
||||
this.canvas.setAttribute("width", width * ratio);
|
||||
this.canvas.setAttribute("height", height * ratio);
|
||||
this.canvas.setAttribute("style", `width:${width}px;height:${height}px`);
|
||||
this.canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
|
||||
this.ctx.scale(ratio, ratio);
|
||||
|
||||
this.ctx.clearRect(0, 0, width, height);
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const events = require("sdk/event/core");
|
||||
const { getCurrentZoom,
|
||||
const { getCurrentZoom, getWindowDimensions,
|
||||
setIgnoreLayoutChanges } = require("devtools/shared/layout/utils");
|
||||
const {
|
||||
CanvasFrameAnonymousContentHelper,
|
||||
@ -65,6 +65,7 @@ MeasuringToolHighlighter.prototype = {
|
||||
attributes: {
|
||||
"id": "root",
|
||||
"class": "root",
|
||||
"hidden": "true",
|
||||
},
|
||||
prefix
|
||||
});
|
||||
@ -77,7 +78,6 @@ MeasuringToolHighlighter.prototype = {
|
||||
"class": "elements",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
hidden: "true"
|
||||
},
|
||||
prefix
|
||||
});
|
||||
@ -157,23 +157,7 @@ MeasuringToolHighlighter.prototype = {
|
||||
|
||||
let zoom = getCurrentZoom(window);
|
||||
|
||||
let { documentElement } = window.document;
|
||||
|
||||
let width = Math.max(documentElement.clientWidth,
|
||||
documentElement.scrollWidth,
|
||||
documentElement.offsetWidth);
|
||||
|
||||
let height = Math.max(documentElement.clientHeight,
|
||||
documentElement.scrollHeight,
|
||||
documentElement.offsetHeight);
|
||||
|
||||
let { body } = window.document;
|
||||
|
||||
// get the size of the content document despite the compatMode
|
||||
if (body) {
|
||||
width = Math.max(width, body.scrollWidth, body.offsetWidth);
|
||||
height = Math.max(height, body.scrollHeight, body.offsetHeight);
|
||||
}
|
||||
let { width, height } = getWindowDimensions(window);
|
||||
|
||||
let { coords } = this;
|
||||
|
||||
@ -198,7 +182,7 @@ MeasuringToolHighlighter.prototype = {
|
||||
this.updateViewport();
|
||||
}
|
||||
|
||||
setIgnoreLayoutChanges(false, documentElement);
|
||||
setIgnoreLayoutChanges(false, window.document.documentElement);
|
||||
|
||||
this._rafID = window.requestAnimationFrame(() => this._update());
|
||||
},
|
||||
@ -232,7 +216,7 @@ MeasuringToolHighlighter.prototype = {
|
||||
show() {
|
||||
setIgnoreLayoutChanges(true);
|
||||
|
||||
this.getElement("elements").removeAttribute("hidden");
|
||||
this.getElement("root").removeAttribute("hidden");
|
||||
|
||||
this._update();
|
||||
|
||||
@ -245,7 +229,7 @@ MeasuringToolHighlighter.prototype = {
|
||||
this.hideLabel("size");
|
||||
this.hideLabel("position");
|
||||
|
||||
this.getElement("elements").setAttribute("hidden", "true");
|
||||
this.getElement("root").setAttribute("hidden", "true");
|
||||
|
||||
this._cancelUpdate();
|
||||
|
||||
@ -390,7 +374,7 @@ MeasuringToolHighlighter.prototype = {
|
||||
},
|
||||
|
||||
updateViewport() {
|
||||
let { scrollX, scrollY, devicePixelRatio } = this.env.window;
|
||||
let { devicePixelRatio } = this.env.window;
|
||||
let { documentWidth, documentHeight, zoom } = this.coords;
|
||||
|
||||
// Because `devicePixelRatio` is affected by zoom (see bug 809788),
|
||||
@ -401,13 +385,12 @@ MeasuringToolHighlighter.prototype = {
|
||||
// width we can actually assign: on retina, for instance, it would be 0.5,
|
||||
// where on non high dpi monitor would be 1.
|
||||
let minWidth = 1 / pixelRatio;
|
||||
let strokeWidth = Math.min(minWidth, minWidth / zoom);
|
||||
let strokeWidth = minWidth / zoom;
|
||||
|
||||
this.getElement("root").setAttribute("style",
|
||||
`stroke-width:${strokeWidth};
|
||||
width:${documentWidth}px;
|
||||
height:${documentHeight}px;
|
||||
transform: translate(${-scrollX}px,${-scrollY}px)`);
|
||||
height:${documentHeight}px;`);
|
||||
},
|
||||
|
||||
updateGuides() {
|
||||
@ -549,10 +532,7 @@ MeasuringToolHighlighter.prototype = {
|
||||
}
|
||||
break;
|
||||
case "scroll":
|
||||
setIgnoreLayoutChanges(true);
|
||||
this.updateViewport();
|
||||
setIgnoreLayoutChanges(false, this.env.window.document.documentElement);
|
||||
|
||||
this.hideLabel("position");
|
||||
break;
|
||||
case "pagehide":
|
||||
this.destroy();
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { getCurrentZoom,
|
||||
const { getCurrentZoom, getWindowDimensions,
|
||||
getRootBindingParent } = require("devtools/shared/layout/utils");
|
||||
const { on, emit } = require("sdk/event/core");
|
||||
|
||||
@ -529,15 +529,24 @@ CanvasFrameAnonymousContentHelper.prototype = {
|
||||
* @param {String} id The ID of the root element inserted with this API.
|
||||
*/
|
||||
scaleRootElement: function (node, id) {
|
||||
let boundaryWindow = this.highlighterEnv.window;
|
||||
let zoom = getCurrentZoom(node);
|
||||
let value = "position:absolute;width:100%;height:100%;";
|
||||
// Hide the root element and force the reflow in order to get the proper window's
|
||||
// dimensions without increasing them.
|
||||
this.setAttributeForElement(id, "style", "display: none");
|
||||
node.offsetWidth;
|
||||
|
||||
let { width, height } = getWindowDimensions(boundaryWindow);
|
||||
let value = "";
|
||||
|
||||
if (zoom !== 1) {
|
||||
value = "position:absolute;";
|
||||
value += "transform-origin:top left;transform:scale(" + (1 / zoom) + ");";
|
||||
value += "width:" + (100 * zoom) + "%;height:" + (100 * zoom) + "%;";
|
||||
value = `transform-origin:top left; transform:scale(${1 / zoom}); `;
|
||||
width *= zoom;
|
||||
height *= zoom;
|
||||
}
|
||||
|
||||
value += `position:absolute; width:${width}px;height:${height}px; overflow:hidden`;
|
||||
|
||||
this.setAttributeForElement(id, "style", value);
|
||||
}
|
||||
};
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
/* globals StopIteration */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu, CC} = require("chrome");
|
||||
@ -1766,7 +1764,9 @@ StorageActors.createActor({
|
||||
if (!DebuggerServer.isInChildProcess) {
|
||||
this.backToChild = (func, rv) => rv;
|
||||
this.clearDBStore = indexedDBHelpers.clearDBStore;
|
||||
this.gatherFilesOrFolders = indexedDBHelpers.gatherFilesOrFolders;
|
||||
this.findIDBPathsForHost = indexedDBHelpers.findIDBPathsForHost;
|
||||
this.findSqlitePathsForHost = indexedDBHelpers.findSqlitePathsForHost;
|
||||
this.findStorageTypePaths = indexedDBHelpers.findStorageTypePaths;
|
||||
this.getDBMetaData = indexedDBHelpers.getDBMetaData;
|
||||
this.getDBNamesForHost = indexedDBHelpers.getDBNamesForHost;
|
||||
this.getNameFromDatabaseFile = indexedDBHelpers.getNameFromDatabaseFile;
|
||||
@ -2043,35 +2043,23 @@ var indexedDBHelpers = {
|
||||
// idb/1556056096MeysDaabta.sqlite
|
||||
// - PathToProfileDir/storage/temporary/http+++www.example.com/
|
||||
// idb/1556056096MeysDaabta.sqlite
|
||||
//
|
||||
// The subdirectory inside the storage folder is determined by the storage
|
||||
// type:
|
||||
// - default: { storage: "default" } or not specified.
|
||||
// - permanent: { storage: "persistent" }.
|
||||
// - temporary: { storage: "temporary" }.
|
||||
let sqliteFiles = yield this.gatherFilesOrFolders(storagePath, path => {
|
||||
if (path.endsWith(".sqlite")) {
|
||||
let { components } = OS.Path.split(path);
|
||||
let isIDB = components[components.length - 2] === "idb";
|
||||
|
||||
return isIDB;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
let sqliteFiles = yield this.findSqlitePathsForHost(storagePath, sanitizedHost);
|
||||
|
||||
for (let file of sqliteFiles) {
|
||||
let splitPath = OS.Path.split(file).components;
|
||||
let idbIndex = splitPath.indexOf("idb");
|
||||
let name = splitPath[idbIndex - 1];
|
||||
let storage = splitPath[idbIndex - 2];
|
||||
let relative = file.substr(profileDir.length + 1);
|
||||
|
||||
if (name.startsWith(sanitizedHost)) {
|
||||
files.push({
|
||||
file: relative,
|
||||
storage: storage === "permanent" ? "persistent" : storage
|
||||
});
|
||||
}
|
||||
files.push({
|
||||
file: relative,
|
||||
storage: storage === "permanent" ? "persistent" : storage
|
||||
});
|
||||
}
|
||||
|
||||
if (files.length > 0) {
|
||||
@ -2090,48 +2078,55 @@ var indexedDBHelpers = {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Gather together all of the files in path and pass each path through a
|
||||
* validation function.
|
||||
*
|
||||
* @param {String}
|
||||
* Path in which to begin searching.
|
||||
* @param {Function}
|
||||
* Validation function, which checks each file path. If this function
|
||||
* Returns true the file path is kept.
|
||||
*
|
||||
* @returns {Array}
|
||||
* An array of file paths.
|
||||
* Find all SQLite files that hold IndexedDB data for a host, such as:
|
||||
* storage/temporary/http+++www.example.com/idb/1556056096MeysDaabta.sqlite
|
||||
*/
|
||||
gatherFilesOrFolders: Task.async(function* (path, validationFunc) {
|
||||
let files = [];
|
||||
let iterator;
|
||||
let paths = [path];
|
||||
|
||||
while (paths.length > 0) {
|
||||
try {
|
||||
iterator = new OS.File.DirectoryIterator(paths.pop());
|
||||
|
||||
for (let child in iterator) {
|
||||
child = yield child;
|
||||
|
||||
path = child.path;
|
||||
|
||||
if (child.isDir) {
|
||||
paths.push(path);
|
||||
} else if (validationFunc(path)) {
|
||||
files.push(path);
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
// Ignore StopIteration to prevent exiting the loop.
|
||||
if (ex != StopIteration) {
|
||||
throw ex;
|
||||
findSqlitePathsForHost: Task.async(function* (storagePath, sanitizedHost) {
|
||||
let sqlitePaths = [];
|
||||
let idbPaths = yield this.findIDBPathsForHost(storagePath, sanitizedHost);
|
||||
for (let idbPath of idbPaths) {
|
||||
let iterator = new OS.File.DirectoryIterator(idbPath);
|
||||
yield iterator.forEach(entry => {
|
||||
if (!entry.isDir && entry.path.endsWith(".sqlite")) {
|
||||
sqlitePaths.push(entry.path);
|
||||
}
|
||||
});
|
||||
iterator.close();
|
||||
}
|
||||
return sqlitePaths;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Find all paths that hold IndexedDB data for a host, such as:
|
||||
* storage/temporary/http+++www.example.com/idb
|
||||
*/
|
||||
findIDBPathsForHost: Task.async(function* (storagePath, sanitizedHost) {
|
||||
let idbPaths = [];
|
||||
let typePaths = yield this.findStorageTypePaths(storagePath);
|
||||
for (let typePath of typePaths) {
|
||||
let idbPath = OS.Path.join(typePath, sanitizedHost, "idb");
|
||||
if (yield OS.File.exists(idbPath)) {
|
||||
idbPaths.push(idbPath);
|
||||
}
|
||||
}
|
||||
iterator.close();
|
||||
return idbPaths;
|
||||
}),
|
||||
|
||||
return files;
|
||||
/**
|
||||
* Find all the storage types, such as "default", "permanent", or "temporary".
|
||||
* These names have changed over time, so it seems simpler to look through all types
|
||||
* that currently exist in the profile.
|
||||
*/
|
||||
findStorageTypePaths: Task.async(function* (storagePath) {
|
||||
let iterator = new OS.File.DirectoryIterator(storagePath);
|
||||
let typePaths = [];
|
||||
yield iterator.forEach(entry => {
|
||||
if (entry.isDir) {
|
||||
typePaths.push(entry.path);
|
||||
}
|
||||
});
|
||||
iterator.close();
|
||||
return typePaths;
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -249,7 +249,7 @@ CssLogic.prototype = {
|
||||
cssSheet._passId = this._passId;
|
||||
|
||||
// Find import and keyframes rules.
|
||||
for (let aDomRule of domSheet.cssRules) {
|
||||
for (let aDomRule of cssSheet.getCssRules()) {
|
||||
if (aDomRule.type == CSSRule.IMPORT_RULE &&
|
||||
aDomRule.styleSheet &&
|
||||
this.mediaMatches(aDomRule)) {
|
||||
@ -819,9 +819,29 @@ CssSheet.prototype = {
|
||||
* @return {number} the number of nsIDOMCSSRule objects in this stylesheet.
|
||||
*/
|
||||
get ruleCount() {
|
||||
return this._ruleCount > -1 ?
|
||||
this._ruleCount :
|
||||
this.domSheet.cssRules.length;
|
||||
try {
|
||||
return this._ruleCount > -1 ?
|
||||
this._ruleCount :
|
||||
this.getCssRules().length;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the array of css rules for this stylesheet.
|
||||
*
|
||||
* Accessing cssRules on a stylesheet that is not completely loaded can throw a
|
||||
* DOMException (Bug 625013). This wrapper will return an empty array instead.
|
||||
*
|
||||
* @return {Array} array of css rules.
|
||||
**/
|
||||
getCssRules: function () {
|
||||
try {
|
||||
return this.domSheet.cssRules;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
/* eslint-env worker */
|
||||
/* eslint-env mozilla/chrome-worker */
|
||||
/* global worker, loadSubScript, global */
|
||||
|
||||
// This function is used to do remote procedure calls from the worker to the
|
||||
|
@ -1506,44 +1506,43 @@ getCoreDumpOutputStream(ErrorResult& rv, TimeStamp& start, nsAString& outFilePat
|
||||
if (NS_WARN_IF(rv.Failed()))
|
||||
return nullptr;
|
||||
|
||||
return outputStream.forget();
|
||||
} else {
|
||||
// Request a file descriptor from the parent process over IPDL.
|
||||
|
||||
auto cc = ContentChild::GetSingleton();
|
||||
if (!cc) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UniqueHeapSnapshotTempFileHelperChild helper(
|
||||
cc->SendPHeapSnapshotTempFileHelperConstructor());
|
||||
if (NS_WARN_IF(!helper)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OpenHeapSnapshotTempFileResponse response;
|
||||
if (!helper->SendOpenHeapSnapshotTempFile(&response)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
if (response.type() == OpenHeapSnapshotTempFileResponse::Tnsresult) {
|
||||
rv.Throw(response.get_nsresult());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto opened = response.get_OpenedFile();
|
||||
outFilePath = opened.path();
|
||||
nsCOMPtr<nsIOutputStream> outputStream =
|
||||
FileDescriptorOutputStream::Create(opened.descriptor());
|
||||
if (NS_WARN_IF(!outputStream)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return outputStream.forget();
|
||||
}
|
||||
// Request a file descriptor from the parent process over IPDL.
|
||||
|
||||
auto cc = ContentChild::GetSingleton();
|
||||
if (!cc) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UniqueHeapSnapshotTempFileHelperChild helper(
|
||||
cc->SendPHeapSnapshotTempFileHelperConstructor());
|
||||
if (NS_WARN_IF(!helper)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OpenHeapSnapshotTempFileResponse response;
|
||||
if (!helper->SendOpenHeapSnapshotTempFile(&response)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
if (response.type() == OpenHeapSnapshotTempFileResponse::Tnsresult) {
|
||||
rv.Throw(response.get_nsresult());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto opened = response.get_OpenedFile();
|
||||
outFilePath = opened.path();
|
||||
nsCOMPtr<nsIOutputStream> outputStream =
|
||||
FileDescriptorOutputStream::Create(opened.descriptor());
|
||||
if (NS_WARN_IF(!outputStream)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return outputStream.forget();
|
||||
}
|
||||
|
||||
} // namespace devtools
|
||||
|
@ -203,6 +203,10 @@ function getAdjustedQuads(boundaryWindow, node, region) {
|
||||
|
||||
let [xOffset, yOffset] = getFrameOffsets(boundaryWindow, node);
|
||||
let scale = getCurrentZoom(node);
|
||||
let { scrollX, scrollY } = boundaryWindow;
|
||||
|
||||
xOffset += scrollX * scale;
|
||||
yOffset += scrollY * scale;
|
||||
|
||||
let adjustedQuads = [];
|
||||
for (let quad of quads) {
|
||||
@ -320,7 +324,7 @@ function getNodeBounds(boundaryWindow, node) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let { scrollX, scrollY } = boundaryWindow;
|
||||
let scale = getCurrentZoom(node);
|
||||
|
||||
// Find out the offset of the node in its current frame
|
||||
@ -347,8 +351,8 @@ function getNodeBounds(boundaryWindow, node) {
|
||||
|
||||
// And add the potential frame offset if the node is nested
|
||||
let [xOffset, yOffset] = getFrameOffsets(boundaryWindow, node);
|
||||
xOffset += offsetLeft;
|
||||
yOffset += offsetTop;
|
||||
xOffset += offsetLeft + scrollX;
|
||||
yOffset += offsetTop + scrollY;
|
||||
|
||||
xOffset *= scale;
|
||||
yOffset *= scale;
|
||||
@ -628,6 +632,33 @@ function getCurrentZoom(node) {
|
||||
}
|
||||
exports.getCurrentZoom = getCurrentZoom;
|
||||
|
||||
/**
|
||||
* Returns the window's dimensions for the `window` given.
|
||||
*
|
||||
* @return {Object} An object with `width` and `height` properties, representing the
|
||||
* number of pixels for the document's size.
|
||||
*/
|
||||
function getWindowDimensions(window) {
|
||||
// First we'll try without flushing layout, because it's way faster.
|
||||
let windowUtils = utilsFor(window);
|
||||
let { width, height } = windowUtils.getRootBounds();
|
||||
|
||||
if (!width || !height) {
|
||||
// We need a flush after all :'(
|
||||
width = window.innerWidth + window.scrollMaxX - window.scrollMinX;
|
||||
height = window.innerHeight + window.scrollMaxY - window.scrollMinY;
|
||||
|
||||
let scrollbarHeight = {};
|
||||
let scrollbarWidth = {};
|
||||
windowUtils.getScrollbarSize(false, scrollbarWidth, scrollbarHeight);
|
||||
width -= scrollbarWidth.value;
|
||||
height -= scrollbarHeight.value;
|
||||
}
|
||||
|
||||
return { width, height };
|
||||
}
|
||||
exports.getWindowDimensions = getWindowDimensions;
|
||||
|
||||
/**
|
||||
* Return the default view for a given node, where node can be:
|
||||
* - a DOM node
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
: TimelineMarker("Styles", aTracingType)
|
||||
{
|
||||
if (aRestyleHint) {
|
||||
mRestyleHint.AssignWithConversion(RestyleManager::RestyleHintToString(aRestyleHint));
|
||||
mRestyleHint.AssignWithConversion(GeckoRestyleManager::RestyleHintToString(aRestyleHint));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/LayerAnimationInfo.h"
|
||||
#include "mozilla/RestyleManagerHandle.h"
|
||||
#include "mozilla/RestyleManagerHandleInlines.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "mozilla/RestyleManagerInlines.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
|
||||
#include "nsCSSPropertyIDSet.h"
|
||||
@ -314,7 +314,7 @@ EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
|
||||
// FIXME: stylo only supports Self and Subtree hints now, so we override it
|
||||
// for stylo if we are not in process of restyling.
|
||||
if (mPresContext->StyleSet()->IsServo() &&
|
||||
!mPresContext->RestyleManager()->AsBase()->IsInStyleRefresh()) {
|
||||
!mPresContext->RestyleManager()->IsInStyleRefresh()) {
|
||||
hint = eRestyle_Self | eRestyle_Subtree;
|
||||
}
|
||||
mPresContext->PresShell()->RestyleForAnimation(element, hint);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user