mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Merge m-c to graphics
MozReview-Commit-ID: AXRXwXgkOTv
This commit is contained in:
commit
96c394d70c
18
.cron.yml
18
.cron.yml
@ -11,8 +11,15 @@ jobs:
|
||||
target-tasks-method: nightly_linux
|
||||
run-on-projects:
|
||||
- mozilla-central
|
||||
- mozilla-aurora
|
||||
- date
|
||||
when: [] # never (temporary)
|
||||
when:
|
||||
by-project:
|
||||
# Match buildbot starts for now
|
||||
date: [{hour: 16, minute: 0}]
|
||||
mozilla-central: [{hour: 11, minute: 0}]
|
||||
mozilla-aurora: [{hour: 8, minute: 45}] # Buildbot uses minute 40
|
||||
# No default
|
||||
|
||||
- name: nightly-android
|
||||
job:
|
||||
@ -22,8 +29,15 @@ jobs:
|
||||
target-tasks-method: nightly_fennec
|
||||
run-on-projects:
|
||||
- mozilla-central
|
||||
- mozilla-aurora
|
||||
- date
|
||||
when: [] # never (temporary)
|
||||
when:
|
||||
by-project:
|
||||
# Match buildbot starts for now
|
||||
date: [{hour: 16, minute: 0}]
|
||||
mozilla-central: [{hour: 11, minute: 0}]
|
||||
mozilla-aurora: [{hour: 8, minute: 45}] # Buildbot uses minute 40
|
||||
# No default
|
||||
|
||||
- name: nightly-mochitest-valgrind
|
||||
job:
|
||||
|
@ -25,7 +25,6 @@ void
|
||||
ProxyAccessibleBase<Derived>::Shutdown()
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsDoc());
|
||||
NS_ASSERTION(!mOuterDoc, "Why do we still have a child doc?");
|
||||
xpcAccessibleDocument* xpcDoc =
|
||||
GetAccService()->GetCachedXPCDocument(Document());
|
||||
if (xpcDoc) {
|
||||
@ -34,15 +33,16 @@ ProxyAccessibleBase<Derived>::Shutdown()
|
||||
|
||||
// XXX Ideally this wouldn't be necessary, but it seems OuterDoc accessibles
|
||||
// can be destroyed before the doc they own.
|
||||
uint32_t childCount = mChildren.Length();
|
||||
if (!mOuterDoc) {
|
||||
uint32_t childCount = mChildren.Length();
|
||||
for (uint32_t idx = 0; idx < childCount; idx++)
|
||||
mChildren[idx]->Shutdown();
|
||||
} else {
|
||||
if (mChildren.Length() != 1)
|
||||
MOZ_CRASH("outer doc doesn't own adoc!");
|
||||
|
||||
mChildren[0]->AsDoc()->Unbind();
|
||||
if (childCount > 1) {
|
||||
MOZ_CRASH("outer doc has too many documents!");
|
||||
} else if (childCount == 1) {
|
||||
mChildren[0]->AsDoc()->Unbind();
|
||||
}
|
||||
}
|
||||
|
||||
mChildren.Clear();
|
||||
@ -76,9 +76,7 @@ ProxyAccessibleBase<Derived>::ClearChildDoc(DocAccessibleParent* aChildDoc)
|
||||
// in SetChildDoc(). This could result in two subsequent calls to
|
||||
// ClearChildDoc() even though mChildren.Length() == 1.
|
||||
MOZ_ASSERT(mChildren.Length() <= 1);
|
||||
if (mChildren.RemoveElement(aChildDoc)) {
|
||||
mOuterDoc = false;
|
||||
}
|
||||
mChildren.RemoveElement(aChildDoc);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
|
@ -24,9 +24,9 @@
|
||||
"size": 12072532
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -2143,12 +2143,16 @@
|
||||
<versionRange maxVersion="13.0.0.302" minVersion="13.0.0.302" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1495" os="Linux">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="libflashplayer\.so" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="24.0.0.186" minVersion="23.0.0.207" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1420">
|
||||
<pluginItem blockID="p1420" os="">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="23.0.0.205" minVersion="23.0.0.185" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
@ -2202,7 +2206,9 @@
|
||||
<versionRange maxVersion="*" minVersion="0"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1419" os="Linux">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="libflashplayer\.so" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="11.2.202.643" minVersion="11.2.202.637" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
@ -2459,8 +2465,10 @@
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="18.0.0.232" minVersion="18.0.0.204" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1274">
|
||||
<pluginItem blockID="p1274" os="">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="22.0.0.211" minVersion="22.0.0.192" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
@ -2571,8 +2579,10 @@
|
||||
</targetApplication>
|
||||
</versionRange>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1494">
|
||||
<pluginItem blockID="p1494" os="">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="24.0.0.186" minVersion="23.0.0.207" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
@ -2640,8 +2650,10 @@
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="18.0.0.352" minVersion="18.0.0.343" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p160">
|
||||
<pluginItem blockID="p160" os="">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="NPSWF32\.dll" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="10.2.9999" minVersion="0" severity="0" vulnerabilitystatus="1">
|
||||
<targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
||||
@ -2810,7 +2822,9 @@
|
||||
<match exp="NPFFAddOn.dll" name="filename"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1421" os="Linux">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="libflashplayer\.so" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="23.0.0.207" minVersion="11.2.202.643" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
@ -3006,8 +3020,10 @@
|
||||
<infoURL>https://get.adobe.com/reader</infoURL>
|
||||
<versionRange maxVersion="15.006.30174" minVersion="15.006.30174" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
<pluginItem blockID="p1422">
|
||||
<pluginItem blockID="p1422" os="">
|
||||
<match exp="" name="name"/>
|
||||
<match exp="(NPSWF32.*\.dll)|(NPSWF64.*\.dll)|(Flash\ Player\.plugin)" name="filename"/>
|
||||
<match exp="" name="description"/>
|
||||
<infoURL>https://get.adobe.com/flashplayer/</infoURL>
|
||||
<versionRange maxVersion="23.0.0.207" minVersion="23.0.0.205" severity="0" vulnerabilitystatus="1"/>
|
||||
</pluginItem>
|
||||
|
@ -31,24 +31,6 @@ var SidebarUI = {
|
||||
this.browser = document.getElementById("sidebar");
|
||||
this._title = document.getElementById("sidebar-title");
|
||||
this._splitter = document.getElementById("sidebar-splitter");
|
||||
|
||||
if (!this.adoptFromWindow(window.opener)) {
|
||||
let commandID = this._box.getAttribute("sidebarcommand");
|
||||
if (commandID) {
|
||||
let command = document.getElementById(commandID);
|
||||
if (command) {
|
||||
this._delayedLoad = true;
|
||||
this._box.hidden = false;
|
||||
this._splitter.hidden = false;
|
||||
command.setAttribute("checked", "true");
|
||||
} else {
|
||||
// Remove the |sidebarcommand| attribute, because the element it
|
||||
// refers to no longer exists, so we should assume this sidebar
|
||||
// panel has been uninstalled. (249883)
|
||||
this._box.removeAttribute("sidebarcommand");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
@ -69,14 +51,6 @@ var SidebarUI = {
|
||||
* initialize the state itself.
|
||||
*/
|
||||
adoptFromWindow(sourceWindow) {
|
||||
// No source window, or it being closed, or not chrome, or in a different
|
||||
// private-browsing context means we can't adopt.
|
||||
if (!sourceWindow || sourceWindow.closed ||
|
||||
!sourceWindow.document.documentURIObject.schemeIs("chrome") ||
|
||||
PrivateBrowsingUtils.isWindowPrivate(window) != PrivateBrowsingUtils.isWindowPrivate(sourceWindow)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the opener had a sidebar, open the same sidebar in our window.
|
||||
// The opener can be the hidden window too, if we're coming from the state
|
||||
// where no windows are open, and the hidden window has no sidebar box.
|
||||
@ -108,23 +82,55 @@ var SidebarUI = {
|
||||
// the <browser id="sidebar">. This lets us delay the actual load until
|
||||
// delayedStartup().
|
||||
this._box.setAttribute("src", sourceUI.browser.getAttribute("src"));
|
||||
this._delayedLoad = true;
|
||||
|
||||
this._box.hidden = false;
|
||||
this._splitter.hidden = false;
|
||||
commandElem.setAttribute("checked", "true");
|
||||
this.browser.setAttribute("src", this._box.getAttribute("src"));
|
||||
return true;
|
||||
},
|
||||
|
||||
windowPrivacyMatches(w1, w2) {
|
||||
return PrivateBrowsingUtils.isWindowPrivate(w1) === PrivateBrowsingUtils.isWindowPrivate(w2);
|
||||
},
|
||||
|
||||
/**
|
||||
* If loading a sidebar was delayed on startup, start the load now.
|
||||
*/
|
||||
startDelayedLoad() {
|
||||
if (!this._delayedLoad) {
|
||||
let sourceWindow = window.opener;
|
||||
// No source window means this is the initial window. If we're being
|
||||
// opened from another window, check that it is one we might open a sidebar
|
||||
// for.
|
||||
if (sourceWindow) {
|
||||
if (sourceWindow.closed || sourceWindow.location.protocol != "chrome:" ||
|
||||
!this.windowPrivacyMatches(sourceWindow, window)) {
|
||||
return;
|
||||
}
|
||||
// Try to adopt the sidebar state from the source window
|
||||
if (this.adoptFromWindow(sourceWindow)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're not adopting settings from a parent window, set them now.
|
||||
let commandID = this._box.getAttribute("sidebarcommand");
|
||||
if (!commandID) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.browser.setAttribute("src", this._box.getAttribute("src"));
|
||||
let command = document.getElementById(commandID);
|
||||
if (command) {
|
||||
this._box.hidden = false;
|
||||
this._splitter.hidden = false;
|
||||
command.setAttribute("checked", "true");
|
||||
this.browser.setAttribute("src", this._box.getAttribute("src"));
|
||||
} else {
|
||||
// Remove the |sidebarcommand| attribute, because the element it
|
||||
// refers to no longer exists, so we should assume this sidebar
|
||||
// panel has been uninstalled. (249883)
|
||||
this._box.removeAttribute("sidebarcommand");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -235,8 +241,7 @@ var SidebarUI = {
|
||||
this._box.setAttribute("src", url);
|
||||
|
||||
if (this.browser.contentDocument.location.href != url) {
|
||||
let onLoad = event => {
|
||||
this.browser.removeEventListener("load", onLoad, true);
|
||||
this.browser.addEventListener("load", event => {
|
||||
|
||||
// We're handling the 'load' event before it bubbles up to the usual
|
||||
// (non-capturing) event handlers. Let it bubble up before firing the
|
||||
@ -247,9 +252,7 @@ var SidebarUI = {
|
||||
sidebarOnLoad(event);
|
||||
|
||||
resolve();
|
||||
};
|
||||
|
||||
this.browser.addEventListener("load", onLoad, true);
|
||||
}, {capture: true, once: true});
|
||||
} else {
|
||||
// Older code handled this case, so we do it too.
|
||||
this._fireFocusedEvent();
|
||||
@ -303,7 +306,7 @@ var SidebarUI = {
|
||||
};
|
||||
|
||||
/**
|
||||
* This exists for backards compatibility - it will be called once a sidebar is
|
||||
* This exists for backwards compatibility - it will be called once a sidebar is
|
||||
* ready, following any request to show it.
|
||||
*
|
||||
* @deprecated
|
||||
@ -311,7 +314,7 @@ var SidebarUI = {
|
||||
function fireSidebarFocusedEvent() {}
|
||||
|
||||
/**
|
||||
* This exists for backards compatibility - it gets called when a sidebar has
|
||||
* This exists for backwards compatibility - it gets called when a sidebar has
|
||||
* been loaded.
|
||||
*
|
||||
* @deprecated
|
||||
@ -319,9 +322,9 @@ function fireSidebarFocusedEvent() {}
|
||||
function sidebarOnLoad(event) {}
|
||||
|
||||
/**
|
||||
* This exists for backards compatibility, and is equivilent to
|
||||
* This exists for backwards compatibility, and is equivilent to
|
||||
* SidebarUI.toggle() without the forceOpen param. With forceOpen set to true,
|
||||
* it is equalivent to SidebarUI.show().
|
||||
* it is equivalent to SidebarUI.show().
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
|
@ -324,6 +324,10 @@ toolbarpaletteitem > toolbaritem[sdkstylewidget="true"][cui-areatype="toolbar"]
|
||||
.webextension-page-action {
|
||||
list-style-image: var(--webextension-urlbar-image);
|
||||
}
|
||||
|
||||
.webextension-menuitem {
|
||||
list-style-image: var(--webextension-menuitem-image);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
@ -339,6 +343,10 @@ toolbarpaletteitem > toolbaritem[sdkstylewidget="true"][cui-areatype="toolbar"]
|
||||
.webextension-page-action {
|
||||
list-style-image: var(--webextension-urlbar-image-2x);
|
||||
}
|
||||
|
||||
.webextension-menuitem {
|
||||
list-style-image: var(--webextension-menuitem-image-2x);
|
||||
}
|
||||
}
|
||||
|
||||
toolbarpaletteitem[removable="false"] {
|
||||
|
@ -1285,8 +1285,6 @@ var gBrowserInit = {
|
||||
PanelUI.init();
|
||||
LightweightThemeListener.init();
|
||||
|
||||
SidebarUI.startDelayedLoad();
|
||||
|
||||
UpdateUrlbarSearchSplitterState();
|
||||
|
||||
if (!(isBlankPageURL(uriToLoad) || uriToLoad == "about:privatebrowsing") ||
|
||||
@ -1460,6 +1458,7 @@ var gBrowserInit = {
|
||||
// Enable the Restore Last Session command if needed
|
||||
RestoreLastSessionObserver.init();
|
||||
|
||||
SidebarUI.startDelayedLoad();
|
||||
SocialUI.init();
|
||||
|
||||
// Start monitoring slow add-ons
|
||||
|
@ -1,9 +1,8 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This test checks that a <select> with an <optgroup> opens and can be navigated
|
||||
// in a child process. This is different than single-process as a <menulist> is used
|
||||
// to implement the dropdown list.
|
||||
// This test tests <select> in a child process. This is different than
|
||||
// single-process as a <menulist> is used to implement the dropdown list.
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
@ -851,3 +850,35 @@ add_task(function* test_colors_applied_to_popup() {
|
||||
yield hideSelectPopup(selectPopup, "escape");
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
// This test checks that the popup is closed when the select element is blurred.
|
||||
add_task(function* test_blur_hides_popup() {
|
||||
const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
|
||||
content.addEventListener("blur", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}, true);
|
||||
|
||||
content.document.getElementById("one").focus();
|
||||
});
|
||||
|
||||
let menulist = document.getElementById("ContentSelectDropdown");
|
||||
let selectPopup = menulist.menupopup;
|
||||
|
||||
yield openSelectPopup(selectPopup);
|
||||
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
|
||||
content.document.getElementById("one").blur();
|
||||
});
|
||||
|
||||
yield popupHiddenPromise;
|
||||
|
||||
ok(true, "Blur closed popup");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
32
browser/base/content/webext-panels.js
Normal file
32
browser/base/content/webext-panels.js
Normal file
@ -0,0 +1,32 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
|
||||
"resource://gre/modules/ExtensionParent.jsm");
|
||||
|
||||
function loadWebPanel() {
|
||||
let sidebarURI = new URL(location);
|
||||
let uri = sidebarURI.searchParams.get("panel");
|
||||
let remote = sidebarURI.searchParams.get("remote");
|
||||
let browser = document.getElementById("webext-panels-browser");
|
||||
if (remote) {
|
||||
let remoteType = E10SUtils.getRemoteTypeForURI(uri, true,
|
||||
E10SUtils.EXTENSION_REMOTE_TYPE);
|
||||
browser.setAttribute("remote", "true");
|
||||
browser.setAttribute("remoteType", remoteType);
|
||||
} else {
|
||||
browser.removeAttribute("remote");
|
||||
browser.removeAttribute("remoteType");
|
||||
}
|
||||
browser.loadURI(uri);
|
||||
}
|
||||
|
||||
function load() {
|
||||
let browser = document.getElementById("webext-panels-browser");
|
||||
browser.messageManager.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
ExtensionParent.apiManager.emit("extension-browser-inserted", browser);
|
||||
|
||||
this.loadWebPanel();
|
||||
}
|
73
browser/base/content/webext-panels.xul
Normal file
73
browser/base/content/webext-panels.xul
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
# 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://browser/skin/" type="text/css"?>
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE page [
|
||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
|
||||
%browserDTD;
|
||||
<!ENTITY % textcontextDTD SYSTEM "chrome://global/locale/textcontext.dtd">
|
||||
%textcontextDTD;
|
||||
]>
|
||||
|
||||
<page id="webextpanels-window"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="load()">
|
||||
<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser-places.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser-social.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser-fxaccounts.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/webext-panels.js"/>
|
||||
|
||||
<stringbundleset id="stringbundleset">
|
||||
<stringbundle id="bundle_browser" src="chrome://browser/locale/browser.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<broadcasterset id="mainBroadcasterSet">
|
||||
<broadcaster id="isFrameImage"/>
|
||||
</broadcasterset>
|
||||
|
||||
<commandset id="mainCommandset">
|
||||
<command id="Browser:Back"
|
||||
oncommand="getPanelBrowser().webNavigation.goBack();"
|
||||
disabled="true"/>
|
||||
<command id="Browser:Forward"
|
||||
oncommand="getPanelBrowser().webNavigation.goForward();"
|
||||
disabled="true"/>
|
||||
<command id="Browser:Stop" oncommand="PanelBrowserStop();"/>
|
||||
<command id="Browser:Reload" oncommand="PanelBrowserReload();"/>
|
||||
</commandset>
|
||||
|
||||
<popupset id="mainPopupSet">
|
||||
<tooltip id="aHTMLTooltip" page="true"/>
|
||||
<menupopup id="contentAreaContextMenu" pagemenu="start"
|
||||
onpopupshowing="if (event.target != this)
|
||||
return true;
|
||||
gContextMenu = new nsContextMenu(this, event.shiftKey);
|
||||
if (gContextMenu.shouldDisplay)
|
||||
document.popupNode = this.triggerNode;
|
||||
return gContextMenu.shouldDisplay;"
|
||||
onpopuphiding="if (event.target != this)
|
||||
return;
|
||||
gContextMenu.hiding();
|
||||
gContextMenu = null;">
|
||||
#include browser-context.inc
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<commandset id="editMenuCommands"/>
|
||||
<browser id="webext-panels-browser"
|
||||
type="content" flex="1"
|
||||
webextension-view-type="sidebar"
|
||||
context="contentAreaContextMenu" tooltip="aHTMLTooltip"
|
||||
onclick="window.parent.contentAreaClick(event, true);"/>
|
||||
</page>
|
@ -155,6 +155,8 @@ browser.jar:
|
||||
content/browser/usercontext.svg (content/usercontext.svg)
|
||||
content/browser/web-panels.js (content/web-panels.js)
|
||||
* content/browser/web-panels.xul (content/web-panels.xul)
|
||||
content/browser/webext-panels.js (content/webext-panels.js)
|
||||
* content/browser/webext-panels.xul (content/webext-panels.xul)
|
||||
* content/browser/baseMenuOverlay.xul (content/baseMenuOverlay.xul)
|
||||
* content/browser/nsContextMenu.js (content/nsContextMenu.js)
|
||||
# XXX: We should exclude this one as well (bug 71895)
|
||||
|
@ -102,7 +102,7 @@ function updateCombinedWidgetStyle(aNode, aArea, aModifyCloseMenu) {
|
||||
function fillSubviewFromMenuItems(aMenuItems, aSubview) {
|
||||
let attrs = ["oncommand", "onclick", "label", "key", "disabled",
|
||||
"command", "observes", "hidden", "class", "origin",
|
||||
"image", "checked"];
|
||||
"image", "checked", "style"];
|
||||
|
||||
let doc = aSubview.ownerDocument;
|
||||
let fragment = doc.createDocumentFragment();
|
||||
|
@ -12,6 +12,7 @@ module.exports = { // eslint-disable-line no-undef
|
||||
"WindowEventManager": true,
|
||||
"browserActionFor": true,
|
||||
"getCookieStoreIdForTab": true,
|
||||
"getDevToolsTargetForContext": true,
|
||||
"makeWidgetId": true,
|
||||
"pageActionFor": true,
|
||||
"tabTracker": true,
|
||||
|
@ -355,17 +355,13 @@ BrowserAction.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
// These URLs should already be properly escaped, but make doubly sure CSS
|
||||
// string escape characters are escaped here, since they could lead to a
|
||||
// sandbox break.
|
||||
let escape = str => str.replace(/[\\\s"]/g, encodeURIComponent);
|
||||
|
||||
let getIcon = size => escape(IconDetails.getPreferredIcon(tabData.icon, this.extension, size).icon);
|
||||
let getIcon = size => IconDetails.escapeUrl(
|
||||
IconDetails.getPreferredIcon(tabData.icon, this.extension, size).icon);
|
||||
|
||||
node.setAttribute("style", `
|
||||
--webextension-menupanel-image: url("${getIcon(32)}");
|
||||
--webextension-menupanel-image-2x: url("${getIcon(64)}");
|
||||
--webextension-toolbar-image: url("${escape(icon)}");
|
||||
--webextension-toolbar-image: url("${IconDetails.escapeUrl(icon)}");
|
||||
--webextension-toolbar-image-2x: url("${getIcon(baseSize * 2)}");
|
||||
`);
|
||||
},
|
||||
|
35
browser/components/extensions/ext-devtools-network.js
Normal file
35
browser/components/extensions/ext-devtools-network.js
Normal file
@ -0,0 +1,35 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
const {
|
||||
SingletonEventManager,
|
||||
} = ExtensionUtils;
|
||||
|
||||
extensions.registerSchemaAPI("devtools.network", "devtools_parent", (context) => {
|
||||
return {
|
||||
devtools: {
|
||||
network: {
|
||||
onNavigated: new SingletonEventManager(context, "devtools.onNavigated", fire => {
|
||||
let listener = (event, data) => {
|
||||
fire.async(data.url);
|
||||
};
|
||||
|
||||
let targetPromise = getDevToolsTargetForContext(context);
|
||||
targetPromise.then(target => {
|
||||
target.on("will-navigate", listener);
|
||||
});
|
||||
return () => {
|
||||
targetPromise.then(target => {
|
||||
target.off("will-navigate", listener);
|
||||
});
|
||||
};
|
||||
}).api(),
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
349
browser/components/extensions/ext-sidebarAction.js
Normal file
349
browser/components/extensions/ext-sidebarAction.js
Normal file
@ -0,0 +1,349 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
let {
|
||||
ExtensionError,
|
||||
IconDetails,
|
||||
} = ExtensionUtils;
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
// WeakMap[Extension -> SidebarAction]
|
||||
let sidebarActionMap = new WeakMap();
|
||||
|
||||
const sidebarURL = "chrome://browser/content/webext-panels.xul";
|
||||
|
||||
/**
|
||||
* Responsible for the sidebar_action section of the manifest as well
|
||||
* as the associated sidebar browser.
|
||||
*/
|
||||
class SidebarAction {
|
||||
constructor(options, extension) {
|
||||
this.extension = extension;
|
||||
|
||||
// Add the extension to the sidebar menu. The sidebar widget will copy
|
||||
// from that when it is viewed, so we shouldn't need to update that.
|
||||
let widgetId = makeWidgetId(extension.id);
|
||||
this.id = `${widgetId}-sidebar-action`;
|
||||
this.menuId = `menu_${this.id}`;
|
||||
|
||||
this.defaults = {
|
||||
enabled: true,
|
||||
title: options.default_title || extension.name,
|
||||
icon: IconDetails.normalize({path: options.default_icon}, extension),
|
||||
panel: options.default_panel || "",
|
||||
};
|
||||
|
||||
this.tabContext = new TabContext(tab => Object.create(this.defaults),
|
||||
extension);
|
||||
|
||||
// We need to ensure our elements are available before session restore.
|
||||
this.windowOpenListener = (window) => {
|
||||
this.createMenuItem(window, this.defaults);
|
||||
};
|
||||
windowTracker.addOpenListener(this.windowOpenListener);
|
||||
}
|
||||
|
||||
build() {
|
||||
this.tabContext.on("tab-select", // eslint-disable-line mozilla/balanced-listeners
|
||||
(evt, tab) => { this.updateWindow(tab.ownerGlobal); });
|
||||
|
||||
let install = this.extension.startupReason === "ADDON_INSTALL";
|
||||
for (let window of windowTracker.browserWindows()) {
|
||||
this.updateWindow(window);
|
||||
if (install) {
|
||||
let {SidebarUI} = window;
|
||||
SidebarUI.show(this.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Bug 1331507: UX review/analysis of sidebar-button injection.
|
||||
if (AppConstants.RELEASE_OR_BETA) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (install && !Services.prefs.prefHasUserValue("extensions.sidebar-button.shown")) {
|
||||
Services.prefs.setBoolPref("extensions.sidebar-button.shown", true);
|
||||
// If the sidebar button has never been moved to the toolbar, move it now
|
||||
// so the user can see/access the sidebars.
|
||||
let widget = CustomizableUI.getWidget("sidebar-button");
|
||||
if (!widget.areaType) {
|
||||
CustomizableUI.addWidgetToArea("sidebar-button", CustomizableUI.AREA_NAVBAR, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sidebarUrl(panel) {
|
||||
if (this.extension.remote) {
|
||||
return `${sidebarURL}?remote=1&panel=${encodeURIComponent(panel)}`;
|
||||
}
|
||||
return `${sidebarURL}?&panel=${encodeURIComponent(panel)}`;
|
||||
}
|
||||
|
||||
createMenuItem(window, details) {
|
||||
let {document} = window;
|
||||
|
||||
// Use of the broadcaster allows browser-sidebar.js to properly manage the
|
||||
// checkmarks in the menus.
|
||||
let broadcaster = document.createElementNS(XUL_NS, "broadcaster");
|
||||
broadcaster.setAttribute("id", this.id);
|
||||
broadcaster.setAttribute("autoCheck", "false");
|
||||
broadcaster.setAttribute("type", "checkbox");
|
||||
broadcaster.setAttribute("group", "sidebar");
|
||||
broadcaster.setAttribute("label", details.title);
|
||||
broadcaster.setAttribute("sidebarurl", this.sidebarUrl(details.panel));
|
||||
// oncommand gets attached to menuitem, so we use the observes attribute to
|
||||
// get the command id we pass to SidebarUI.
|
||||
broadcaster.setAttribute("oncommand", "SidebarUI.toggle(this.getAttribute('observes'))");
|
||||
|
||||
let menuitem = document.createElementNS(XUL_NS, "menuitem");
|
||||
menuitem.setAttribute("id", this.menuId);
|
||||
menuitem.setAttribute("observes", this.id);
|
||||
menuitem.setAttribute("class", "menuitem-iconic webextension-menuitem");
|
||||
|
||||
document.getElementById("mainBroadcasterSet").appendChild(broadcaster);
|
||||
document.getElementById("viewSidebarMenu").appendChild(menuitem);
|
||||
|
||||
return menuitem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the broadcaster and menuitem `node` with the tab context data
|
||||
* in `tabData`.
|
||||
*
|
||||
* @param {ChromeWindow} window
|
||||
* Browser chrome window.
|
||||
* @param {object} tabData
|
||||
* Tab specific sidebar configuration.
|
||||
*/
|
||||
updateButton(window, tabData) {
|
||||
let {document, SidebarUI} = window;
|
||||
let title = tabData.title || this.extension.name;
|
||||
let menu = document.getElementById(this.menuId);
|
||||
if (!menu) {
|
||||
menu = this.createMenuItem(window, tabData);
|
||||
}
|
||||
|
||||
// Update the broadcaster first, it will update both menus.
|
||||
let broadcaster = document.getElementById(this.id);
|
||||
broadcaster.setAttribute("tooltiptext", title);
|
||||
broadcaster.setAttribute("label", title);
|
||||
|
||||
let url = this.sidebarUrl(tabData.panel);
|
||||
let urlChanged = url !== broadcaster.getAttribute("sidebarurl");
|
||||
if (urlChanged) {
|
||||
broadcaster.setAttribute("sidebarurl", url);
|
||||
}
|
||||
|
||||
let getIcon = size => IconDetails.escapeUrl(
|
||||
IconDetails.getPreferredIcon(tabData.icon, this.extension, size).icon);
|
||||
|
||||
menu.setAttribute("style", `
|
||||
--webextension-menuitem-image: url("${getIcon(16)}");
|
||||
--webextension-menuitem-image-2x: url("${getIcon(32)}");
|
||||
`);
|
||||
|
||||
// Update the sidebar if this extension is the current sidebar.
|
||||
if (SidebarUI.currentID === this.id) {
|
||||
SidebarUI.title = title;
|
||||
if (SidebarUI.isOpen && urlChanged) {
|
||||
SidebarUI.show(this.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the broadcaster and menuitem for a given window.
|
||||
*
|
||||
* @param {ChromeWindow} window
|
||||
* Browser chrome window.
|
||||
*/
|
||||
updateWindow(window) {
|
||||
let nativeTab = window.gBrowser.selectedTab;
|
||||
this.updateButton(window, this.tabContext.get(nativeTab));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the broadcaster and menuitem when the extension changes the icon,
|
||||
* title, url, etc. If it only changes a parameter for a single
|
||||
* tab, `tab` will be that tab. Otherwise it will be null.
|
||||
*
|
||||
* @param {XULElement|null} nativeTab
|
||||
* Browser tab, may be null.
|
||||
*/
|
||||
updateOnChange(nativeTab) {
|
||||
if (nativeTab) {
|
||||
if (nativeTab.selected) {
|
||||
this.updateWindow(nativeTab.ownerGlobal);
|
||||
}
|
||||
} else {
|
||||
for (let window of windowTracker.browserWindows()) {
|
||||
this.updateWindow(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default or tab specific property.
|
||||
*
|
||||
* @param {XULElement|null} nativeTab
|
||||
* Webextension tab object, may be null.
|
||||
* @param {string} prop
|
||||
* String property to retrieve ["icon", "title", or "panel"].
|
||||
* @param {string} value
|
||||
* Value for property.
|
||||
*/
|
||||
setProperty(nativeTab, prop, value) {
|
||||
if (nativeTab === null) {
|
||||
this.defaults[prop] = value;
|
||||
} else if (value !== null) {
|
||||
this.tabContext.get(nativeTab)[prop] = value;
|
||||
} else {
|
||||
delete this.tabContext.get(nativeTab)[prop];
|
||||
}
|
||||
|
||||
this.updateOnChange(nativeTab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a property from the tab or defaults if tab is null.
|
||||
*
|
||||
* @param {XULElement|null} nativeTab
|
||||
* Browser tab object, may be null.
|
||||
* @param {string} prop
|
||||
* String property to retrieve ["icon", "title", or "panel"]
|
||||
* @returns {string} value
|
||||
* Value for prop.
|
||||
*/
|
||||
getProperty(nativeTab, prop) {
|
||||
if (nativeTab === null) {
|
||||
return this.defaults[prop];
|
||||
}
|
||||
return this.tabContext.get(nativeTab)[prop];
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
this.tabContext.shutdown();
|
||||
for (let window of windowTracker.browserWindows()) {
|
||||
let {document, SidebarUI} = window;
|
||||
if (SidebarUI.currentID === this.id) {
|
||||
SidebarUI.hide();
|
||||
}
|
||||
let menu = document.getElementById(this.menuId);
|
||||
if (menu) {
|
||||
menu.remove();
|
||||
}
|
||||
let broadcaster = document.getElementById(this.id);
|
||||
if (broadcaster) {
|
||||
broadcaster.remove();
|
||||
}
|
||||
}
|
||||
windowTracker.removeOpenListener(this.windowOpenListener);
|
||||
}
|
||||
}
|
||||
|
||||
SidebarAction.for = (extension) => {
|
||||
return sidebarActionMap.get(extension);
|
||||
};
|
||||
|
||||
global.sidebarActionFor = SidebarAction.for;
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
extensions.on("manifest_sidebar_action", (type, directive, extension, manifest) => {
|
||||
let sidebarAction = new SidebarAction(manifest.sidebar_action, extension);
|
||||
sidebarActionMap.set(extension, sidebarAction);
|
||||
});
|
||||
|
||||
extensions.on("ready", (type, extension) => {
|
||||
// We build sidebars during ready to ensure the background scripts are ready.
|
||||
if (sidebarActionMap.has(extension)) {
|
||||
sidebarActionMap.get(extension).build();
|
||||
}
|
||||
});
|
||||
|
||||
extensions.on("shutdown", (type, extension) => {
|
||||
if (sidebarActionMap.has(extension)) {
|
||||
// Don't remove everything on app shutdown so session restore can handle
|
||||
// restoring open sidebars.
|
||||
if (extension.shutdownReason !== "APP_SHUTDOWN") {
|
||||
sidebarActionMap.get(extension).shutdown();
|
||||
}
|
||||
sidebarActionMap.delete(extension);
|
||||
}
|
||||
});
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
|
||||
extensions.registerSchemaAPI("sidebarAction", "addon_parent", context => {
|
||||
let {extension} = context;
|
||||
|
||||
function getTab(tabId) {
|
||||
if (tabId !== null) {
|
||||
return tabTracker.getTab(tabId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
sidebarAction: {
|
||||
async setTitle(details) {
|
||||
let nativeTab = getTab(details.tabId);
|
||||
|
||||
let title = details.title;
|
||||
// Clear the tab-specific title when given a null string.
|
||||
if (nativeTab && title === "") {
|
||||
title = null;
|
||||
}
|
||||
SidebarAction.for(extension).setProperty(nativeTab, "title", title);
|
||||
},
|
||||
|
||||
getTitle(details) {
|
||||
let nativeTab = getTab(details.tabId);
|
||||
|
||||
let title = SidebarAction.for(extension).getProperty(nativeTab, "title");
|
||||
return Promise.resolve(title);
|
||||
},
|
||||
|
||||
async setIcon(details) {
|
||||
let nativeTab = getTab(details.tabId);
|
||||
|
||||
let icon = IconDetails.normalize(details, extension, context);
|
||||
SidebarAction.for(extension).setProperty(nativeTab, "icon", icon);
|
||||
},
|
||||
|
||||
async setPanel(details) {
|
||||
let nativeTab = getTab(details.tabId);
|
||||
|
||||
let url;
|
||||
// Clear the tab-specific url when given a null string.
|
||||
if (nativeTab && details.panel === "") {
|
||||
url = null;
|
||||
} else if (details.panel !== "") {
|
||||
url = context.uri.resolve(details.panel);
|
||||
} else {
|
||||
throw new ExtensionError("Invalid url for sidebar panel.");
|
||||
}
|
||||
|
||||
SidebarAction.for(extension).setProperty(nativeTab, "panel", url);
|
||||
},
|
||||
|
||||
getPanel(details) {
|
||||
let nativeTab = getTab(details.tabId);
|
||||
|
||||
let panel = SidebarAction.for(extension).getProperty(nativeTab, "panel");
|
||||
return Promise.resolve(panel);
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
@ -7,10 +7,12 @@ category webextension-scripts contextMenus chrome://browser/content/ext-contextM
|
||||
category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
|
||||
category webextension-scripts devtools chrome://browser/content/ext-devtools.js
|
||||
category webextension-scripts devtools-inspectedWindow chrome://browser/content/ext-devtools-inspectedWindow.js
|
||||
category webextension-scripts devtools-network chrome://browser/content/ext-devtools-network.js
|
||||
category webextension-scripts history chrome://browser/content/ext-history.js
|
||||
category webextension-scripts omnibox chrome://browser/content/ext-omnibox.js
|
||||
category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
|
||||
category webextension-scripts sessions chrome://browser/content/ext-sessions.js
|
||||
category webextension-scripts sidebarAction chrome://browser/content/ext-sidebarAction.js
|
||||
category webextension-scripts tabs chrome://browser/content/ext-tabs.js
|
||||
category webextension-scripts theme chrome://browser/content/ext-theme.js
|
||||
category webextension-scripts url-overrides chrome://browser/content/ext-url-overrides.js
|
||||
@ -34,10 +36,12 @@ category webextension-schemas context_menus chrome://browser/content/schemas/con
|
||||
category webextension-schemas context_menus_internal chrome://browser/content/schemas/context_menus_internal.json
|
||||
category webextension-schemas devtools chrome://browser/content/schemas/devtools.json
|
||||
category webextension-schemas devtools_inspected_window chrome://browser/content/schemas/devtools_inspected_window.json
|
||||
category webextension-schemas devtools_network chrome://browser/content/schemas/devtools_network.json
|
||||
category webextension-schemas history chrome://browser/content/schemas/history.json
|
||||
category webextension-schemas omnibox chrome://browser/content/schemas/omnibox.json
|
||||
category webextension-schemas page_action chrome://browser/content/schemas/page_action.json
|
||||
category webextension-schemas sessions chrome://browser/content/schemas/sessions.json
|
||||
category webextension-schemas sidebar_action chrome://browser/content/schemas/sidebar_action.json
|
||||
category webextension-schemas tabs chrome://browser/content/schemas/tabs.json
|
||||
category webextension-schemas theme chrome://browser/content/schemas/theme.json
|
||||
category webextension-schemas url_overrides chrome://browser/content/schemas/url_overrides.json
|
||||
|
@ -20,10 +20,12 @@ browser.jar:
|
||||
content/browser/ext-desktop-runtime.js
|
||||
content/browser/ext-devtools.js
|
||||
content/browser/ext-devtools-inspectedWindow.js
|
||||
content/browser/ext-devtools-network.js
|
||||
content/browser/ext-history.js
|
||||
content/browser/ext-omnibox.js
|
||||
content/browser/ext-pageAction.js
|
||||
content/browser/ext-sessions.js
|
||||
content/browser/ext-sidebarAction.js
|
||||
content/browser/ext-tabs.js
|
||||
content/browser/ext-theme.js
|
||||
content/browser/ext-url-overrides.js
|
||||
|
93
browser/components/extensions/schemas/devtools_network.json
Normal file
93
browser/components/extensions/schemas/devtools_network.json
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
[
|
||||
{
|
||||
"namespace": "devtools.network",
|
||||
"allowedContexts": ["devtools", "devtools_only"],
|
||||
"defaultContexts": ["devtools", "devtools_only"],
|
||||
"description": "Use the <code>chrome.devtools.network</code> API to retrieve the information about network requests displayed by the Developer Tools in the Network panel.",
|
||||
"types": [
|
||||
{
|
||||
"id": "Request",
|
||||
"type": "object",
|
||||
"description": "Represents a network request for a document resource (script, image and so on). See HAR Specification for reference.",
|
||||
"functions": [
|
||||
{
|
||||
"name": "getContent",
|
||||
"type": "function",
|
||||
"description": "Returns content of the response body.",
|
||||
"async": "callback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "callback",
|
||||
"type": "function",
|
||||
"description": "A function that receives the response body when the request completes.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "content",
|
||||
"type": "string",
|
||||
"description": "Content of the response body (potentially encoded)."
|
||||
},
|
||||
{
|
||||
"name": "encoding",
|
||||
"type": "string",
|
||||
"description": "Empty if content is not encoded, encoding name otherwise. Currently, only base64 is supported."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"name": "getHAR",
|
||||
"unsupported": true,
|
||||
"type": "function",
|
||||
"description": "Returns HAR log that contains all known network requests.",
|
||||
"async": "callback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "callback",
|
||||
"type": "function",
|
||||
"description": "A function that receives the HAR log when the request completes.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "harLog",
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "any"},
|
||||
"description": "A HAR log. See HAR specification for details."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "onRequestFinished",
|
||||
"unsupported": true,
|
||||
"type": "function",
|
||||
"description": "Fired when a network request is finished and all request data are available.",
|
||||
"parameters": [
|
||||
{ "name": "request", "$ref": "Request", "description": "Description of a network request in the form of a HAR entry. See HAR specification for details." }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "onNavigated",
|
||||
"type": "function",
|
||||
"description": "Fired when the inspected window navigates to a new page.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"type": "string",
|
||||
"description": "URL of the new page."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -11,10 +11,12 @@ browser.jar:
|
||||
content/browser/schemas/context_menus_internal.json
|
||||
content/browser/schemas/devtools.json
|
||||
content/browser/schemas/devtools_inspected_window.json
|
||||
content/browser/schemas/devtools_network.json
|
||||
content/browser/schemas/history.json
|
||||
content/browser/schemas/omnibox.json
|
||||
content/browser/schemas/page_action.json
|
||||
content/browser/schemas/sessions.json
|
||||
content/browser/schemas/sidebar_action.json
|
||||
content/browser/schemas/tabs.json
|
||||
content/browser/schemas/theme.json
|
||||
content/browser/schemas/url_overrides.json
|
||||
|
183
browser/components/extensions/schemas/sidebar_action.json
Normal file
183
browser/components/extensions/schemas/sidebar_action.json
Normal file
@ -0,0 +1,183 @@
|
||||
/* 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/. */
|
||||
|
||||
[
|
||||
{
|
||||
"namespace": "manifest",
|
||||
"types": [
|
||||
{
|
||||
"$extend": "WebExtensionManifest",
|
||||
"properties": {
|
||||
"sidebar_action": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "$ref": "UnrecognizedProperty" },
|
||||
"properties": {
|
||||
"default_title": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"preprocess": "localize"
|
||||
},
|
||||
"default_icon": {
|
||||
"$ref": "IconPath",
|
||||
"optional": true
|
||||
},
|
||||
"default_panel": {
|
||||
"type": "string",
|
||||
"format": "strictRelativeUrl",
|
||||
"preprocess": "localize"
|
||||
}
|
||||
},
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"namespace": "sidebarAction",
|
||||
"description": "Use sidebar actions to add a sidebar to Firefox.",
|
||||
"permissions": ["manifest:sidebar_action"],
|
||||
"types": [
|
||||
{
|
||||
"id": "ImageDataType",
|
||||
"type": "object",
|
||||
"isInstanceOf": "ImageData",
|
||||
"additionalProperties": { "type": "any" },
|
||||
"postprocess": "convertImageDataToURL",
|
||||
"description": "Pixel data for an image. Must be an ImageData object (for example, from a <code>canvas</code> element)."
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"name": "setTitle",
|
||||
"type": "function",
|
||||
"description": "Sets the title of the sidebar action. This shows up in the tooltip.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "The string the sidebar action should display when moused over."
|
||||
},
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Sets the sidebar title for the tab specified by tabId. Automatically resets when the tab is closed."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getTitle",
|
||||
"type": "function",
|
||||
"description": "Gets the title of the sidebar action.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Specify the tab to get the title from. If no tab is specified, the non-tab-specific title is returned."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "setIcon",
|
||||
"type": "function",
|
||||
"description": "Sets the icon for the sidebar action. The icon can be specified either as the path to an image file or as the pixel data from a canvas element, or as dictionary of either one of those. Either the <strong>path</strong> or the <strong>imageData</strong> property must be specified.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"imageData": {
|
||||
"choices": [
|
||||
{ "$ref": "ImageDataType" },
|
||||
{
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[1-9]\\d*$": { "$ref": "ImageDataType" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"description": "Either an ImageData object or a dictionary {size -> ImageData} representing icon to be set. If the icon is specified as a dictionary, the actual image to be used is chosen depending on screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then image with size <code>scale</code> * 19 will be selected. Initially only scales 1 and 2 will be supported. At least one image must be specified. Note that 'details.imageData = foo' is equivalent to 'details.imageData = {'19': foo}'"
|
||||
},
|
||||
"path": {
|
||||
"choices": [
|
||||
{ "type": "string" },
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"}
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"description": "Either a relative image path or a dictionary {size -> relative image path} pointing to icon to be set. If the icon is specified as a dictionary, the actual image to be used is chosen depending on screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then image with size <code>scale</code> * 19 will be selected. Initially only scales 1 and 2 will be supported. At least one image must be specified. Note that 'details.path = foo' is equivalent to 'details.imageData = {'19': foo}'"
|
||||
},
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Sets the sidebar icon for the tab specified by tabId. Automatically resets when the tab is closed."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "setPanel",
|
||||
"type": "function",
|
||||
"description": "Sets the url to the html document to be opened in the sidebar when the user clicks on the sidebar action's icon.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"minimum": 0,
|
||||
"description": "Sets the sidebar url for the tab specified by tabId. Automatically resets when the tab is closed."
|
||||
},
|
||||
"panel": {
|
||||
"type": "string",
|
||||
"description": "The url to the html file to show in a sidebar. If set to the empty string (''), no sidebar is shown."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getPanel",
|
||||
"type": "function",
|
||||
"description": "Gets the url to the html document set as the panel for this sidebar action.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tabId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"description": "Specify the tab to get the sidebar from. If no tab is specified, the non-tab-specific sidebar is returned."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -52,6 +52,7 @@ support-files =
|
||||
[browser_ext_currentWindow.js]
|
||||
[browser_ext_devtools_inspectedWindow.js]
|
||||
[browser_ext_devtools_inspectedWindow_reload.js]
|
||||
[browser_ext_devtools_network.js]
|
||||
[browser_ext_devtools_page.js]
|
||||
[browser_ext_getViews.js]
|
||||
[browser_ext_incognito_views.js]
|
||||
@ -76,6 +77,8 @@ support-files =
|
||||
[browser_ext_sessions_getRecentlyClosed_private.js]
|
||||
[browser_ext_sessions_getRecentlyClosed_tabs.js]
|
||||
[browser_ext_sessions_restore.js]
|
||||
[browser_ext_sidebarAction.js]
|
||||
[browser_ext_sidebarAction_context.js]
|
||||
[browser_ext_simple.js]
|
||||
[browser_ext_tab_runtimeConnect.js]
|
||||
[browser_ext_tabs_audio.js]
|
||||
|
@ -0,0 +1,94 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "devtools",
|
||||
"resource://devtools/shared/Loader.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
|
||||
"resource://devtools/client/framework/gDevTools.jsm");
|
||||
|
||||
add_task(async function test_devtools_network_on_navigated() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
|
||||
|
||||
function background() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
let code;
|
||||
if (msg === "navigate") {
|
||||
code = "window.wrappedJSObject.location.href = 'http://example.com/';";
|
||||
browser.tabs.executeScript({code});
|
||||
} else if (msg === "reload") {
|
||||
code = "window.wrappedJSObject.location.reload(true);";
|
||||
browser.tabs.executeScript({code});
|
||||
}
|
||||
});
|
||||
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
||||
if (changeInfo.status === "complete" && tab.url === "http://example.com/") {
|
||||
browser.test.sendMessage("tabUpdated");
|
||||
}
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
function devtools_page() {
|
||||
let eventCount = 0;
|
||||
let listener = url => {
|
||||
eventCount++;
|
||||
browser.test.assertEq("http://example.com/", url, "onNavigated received the expected url.");
|
||||
if (eventCount === 2) {
|
||||
browser.devtools.network.onNavigated.removeListener(listener);
|
||||
}
|
||||
browser.test.sendMessage("onNavigatedFired", eventCount);
|
||||
};
|
||||
browser.devtools.network.onNavigated.addListener(listener);
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
background,
|
||||
manifest: {
|
||||
permissions: ["tabs", "http://mochi.test/", "http://example.com/"],
|
||||
devtools_page: "devtools_page.html",
|
||||
},
|
||||
files: {
|
||||
"devtools_page.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="devtools_page.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>`,
|
||||
"devtools_page.js": devtools_page,
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("ready");
|
||||
|
||||
let target = devtools.TargetFactory.forTab(tab);
|
||||
|
||||
await gDevTools.showToolbox(target, "webconsole");
|
||||
info("Developer toolbox opened.");
|
||||
|
||||
extension.sendMessage("navigate");
|
||||
await extension.awaitMessage("tabUpdated");
|
||||
let eventCount = await extension.awaitMessage("onNavigatedFired");
|
||||
is(eventCount, 1, "The expected number of events were fired.");
|
||||
|
||||
extension.sendMessage("reload");
|
||||
await extension.awaitMessage("tabUpdated");
|
||||
eventCount = await extension.awaitMessage("onNavigatedFired");
|
||||
is(eventCount, 2, "The expected number of events were fired.");
|
||||
|
||||
// do a reload after the listener has been removed, do not expect a message to be sent
|
||||
extension.sendMessage("reload");
|
||||
await extension.awaitMessage("tabUpdated");
|
||||
|
||||
await gDevTools.closeToolbox(target);
|
||||
|
||||
await target.destroy();
|
||||
|
||||
await extension.unload();
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
@ -0,0 +1,122 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
let extData = {
|
||||
manifest: {
|
||||
"sidebar_action": {
|
||||
"default_panel": "sidebar.html",
|
||||
},
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
|
||||
files: {
|
||||
"sidebar.html": `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"/>
|
||||
<script src="sidebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
A Test Sidebar
|
||||
</body></html>
|
||||
`,
|
||||
|
||||
"sidebar.js": function() {
|
||||
window.onload = () => {
|
||||
browser.test.sendMessage("sidebar");
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.test.onMessage.addListener(msg => {
|
||||
if (msg === "set-panel") {
|
||||
browser.sidebarAction.setPanel({panel: ""}).then(() => {
|
||||
browser.test.notifyFail("empty panel settable");
|
||||
}).catch(() => {
|
||||
browser.test.notifyPass("unable to set empty panel");
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* sidebar_initial_install() {
|
||||
ok(document.getElementById("sidebar-box").hidden, "sidebar box is not visible");
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension.awaitMessage("sidebar");
|
||||
ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible");
|
||||
// Test toolbar button is available
|
||||
ok(document.getElementById("sidebar-button"), "sidebar button is in UI");
|
||||
|
||||
yield extension.unload();
|
||||
// Test that the sidebar was closed on unload.
|
||||
ok(document.getElementById("sidebar-box").hidden, "sidebar box is not visible");
|
||||
|
||||
// Move toolbar button back to customization.
|
||||
CustomizableUI.removeWidgetFromArea("sidebar-button", CustomizableUI.AREA_NAVBAR);
|
||||
ok(!document.getElementById("sidebar-button"), "sidebar button is not in UI");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* sidebar_two_sidebar_addons() {
|
||||
let extension2 = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension2.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension2.awaitMessage("sidebar");
|
||||
ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible");
|
||||
// Test toolbar button is NOT available after first install
|
||||
ok(!document.getElementById("sidebar-button"), "sidebar button is not in UI");
|
||||
|
||||
// Test second sidebar install opens new sidebar
|
||||
let extension3 = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension3.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension3.awaitMessage("sidebar");
|
||||
ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible");
|
||||
yield extension3.unload();
|
||||
|
||||
// We just close the sidebar on uninstall of the current sidebar.
|
||||
ok(document.getElementById("sidebar-box").hidden, "sidebar box is not visible");
|
||||
|
||||
yield extension2.unload();
|
||||
});
|
||||
|
||||
add_task(function* sidebar_windows() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension.awaitMessage("sidebar");
|
||||
ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible in first window");
|
||||
|
||||
let secondSidebar = extension.awaitMessage("sidebar");
|
||||
|
||||
// SidebarUI relies on window.opener being set, which is normal behavior when
|
||||
// using menu or key commands to open a new browser window.
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow({opener: window});
|
||||
|
||||
yield secondSidebar;
|
||||
ok(!win.document.getElementById("sidebar-box").hidden, "sidebar box is visible in second window");
|
||||
|
||||
yield extension.unload();
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
add_task(function* sidebar_empty_panel() {
|
||||
let extension = ExtensionTestUtils.loadExtension(extData);
|
||||
yield extension.startup();
|
||||
// Test sidebar is opened on install
|
||||
yield extension.awaitMessage("sidebar");
|
||||
ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible in first window");
|
||||
extension.sendMessage("set-panel");
|
||||
yield extension.awaitFinish();
|
||||
yield extension.unload();
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
// This is set on initial sidebar install.
|
||||
Services.prefs.clearUserPref("extensions.sidebar-button.shown");
|
||||
});
|
@ -0,0 +1,381 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
// Ignore toolbarbutton stuff, other test covers it.
|
||||
set: [["extensions.sidebar-button.shown", true]],
|
||||
});
|
||||
|
||||
function* runTests(options) {
|
||||
async function background(getTests) {
|
||||
async function checkDetails(expecting, tabId) {
|
||||
let title = await browser.sidebarAction.getTitle({tabId});
|
||||
browser.test.assertEq(expecting.title, title,
|
||||
"expected value from getTitle");
|
||||
|
||||
let panel = await browser.sidebarAction.getPanel({tabId});
|
||||
browser.test.assertEq(expecting.panel, panel,
|
||||
"expected value from getPanel");
|
||||
}
|
||||
|
||||
let expectDefaults = expecting => {
|
||||
return checkDetails(expecting);
|
||||
};
|
||||
|
||||
let tabs = [];
|
||||
let tests = getTests(tabs, expectDefaults);
|
||||
|
||||
{
|
||||
let tabId = 0xdeadbeef;
|
||||
let calls = [
|
||||
() => browser.sidebarAction.setTitle({tabId, title: "foo"}),
|
||||
() => browser.sidebarAction.setIcon({tabId, path: "foo.png"}),
|
||||
() => browser.sidebarAction.setPanel({tabId, panel: "foo.html"}),
|
||||
];
|
||||
|
||||
for (let call of calls) {
|
||||
await browser.test.assertRejects(
|
||||
new Promise(resolve => resolve(call())),
|
||||
RegExp(`Invalid tab ID: ${tabId}`),
|
||||
"Expected invalid tab ID error");
|
||||
}
|
||||
}
|
||||
|
||||
// Runs the next test in the `tests` array, checks the results,
|
||||
// and passes control back to the outer test scope.
|
||||
function nextTest() {
|
||||
let test = tests.shift();
|
||||
|
||||
test(async expecting => {
|
||||
// Check that the API returns the expected values, and then
|
||||
// run the next test.
|
||||
let tabs = await browser.tabs.query({active: true, currentWindow: true});
|
||||
await checkDetails(expecting, tabs[0].id);
|
||||
|
||||
// Check that the actual icon has the expected values, then
|
||||
// run the next test.
|
||||
browser.test.sendMessage("nextTest", expecting, tests.length);
|
||||
});
|
||||
}
|
||||
|
||||
browser.test.onMessage.addListener((msg) => {
|
||||
if (msg != "runNextTest") {
|
||||
browser.test.fail("Expecting 'runNextTest' message");
|
||||
}
|
||||
|
||||
nextTest();
|
||||
});
|
||||
|
||||
browser.tabs.query({active: true, currentWindow: true}, resultTabs => {
|
||||
tabs[0] = resultTabs[0].id;
|
||||
});
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: options.manifest,
|
||||
useAddonManager: "temporary",
|
||||
|
||||
files: options.files || {},
|
||||
|
||||
background: `(${background})(${options.getTests})`,
|
||||
});
|
||||
|
||||
let sidebarActionId;
|
||||
function checkDetails(details) {
|
||||
if (!sidebarActionId) {
|
||||
sidebarActionId = `${makeWidgetId(extension.id)}-sidebar-action`;
|
||||
}
|
||||
|
||||
let command = document.getElementById(sidebarActionId);
|
||||
ok(command, "command exists");
|
||||
|
||||
let menuId = `menu_${sidebarActionId}`;
|
||||
let menu = document.getElementById(menuId);
|
||||
ok(menu, "menu exists");
|
||||
|
||||
let title = details.title || options.manifest.name;
|
||||
|
||||
is(getListStyleImage(menu), details.icon, "icon URL is correct");
|
||||
is(menu.getAttribute("label"), title, "image label is correct");
|
||||
}
|
||||
|
||||
let awaitFinish = new Promise(resolve => {
|
||||
extension.onMessage("nextTest", (expecting, testsRemaining) => {
|
||||
checkDetails(expecting);
|
||||
|
||||
if (testsRemaining) {
|
||||
extension.sendMessage("runNextTest");
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Wait for initial sidebar load to start tests.
|
||||
SidebarUI.browser.addEventListener("load", event => {
|
||||
extension.sendMessage("runNextTest");
|
||||
}, {capture: true, once: true});
|
||||
|
||||
yield extension.startup();
|
||||
yield awaitFinish;
|
||||
yield extension.unload();
|
||||
}
|
||||
|
||||
let sidebar = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"/></head>
|
||||
<body>
|
||||
A Test Sidebar
|
||||
</body></html>
|
||||
`;
|
||||
|
||||
add_task(function* testTabSwitchContext() {
|
||||
yield runTests({
|
||||
manifest: {
|
||||
"sidebar_action": {
|
||||
"default_icon": "default.png",
|
||||
"default_panel": "__MSG_panel__",
|
||||
"default_title": "Default __MSG_title__",
|
||||
},
|
||||
|
||||
"default_locale": "en",
|
||||
|
||||
"permissions": ["tabs"],
|
||||
},
|
||||
|
||||
"files": {
|
||||
"default.html": sidebar,
|
||||
"default-2.html": sidebar,
|
||||
"2.html": sidebar,
|
||||
|
||||
"_locales/en/messages.json": {
|
||||
"panel": {
|
||||
"message": "default.html",
|
||||
"description": "Panel",
|
||||
},
|
||||
|
||||
"title": {
|
||||
"message": "Title",
|
||||
"description": "Title",
|
||||
},
|
||||
},
|
||||
|
||||
"default.png": imageBuffer,
|
||||
"default-2.png": imageBuffer,
|
||||
"1.png": imageBuffer,
|
||||
"2.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs, expectDefaults) {
|
||||
let details = [
|
||||
{"icon": browser.runtime.getURL("default.png"),
|
||||
"panel": browser.runtime.getURL("default.html"),
|
||||
"title": "Default Title",
|
||||
},
|
||||
{"icon": browser.runtime.getURL("1.png"),
|
||||
"panel": browser.runtime.getURL("default.html"),
|
||||
"title": "Default Title",
|
||||
},
|
||||
{"icon": browser.runtime.getURL("2.png"),
|
||||
"panel": browser.runtime.getURL("2.html"),
|
||||
"title": "Title 2",
|
||||
},
|
||||
{"icon": browser.runtime.getURL("1.png"),
|
||||
"panel": browser.runtime.getURL("default-2.html"),
|
||||
"title": "Default Title 2",
|
||||
},
|
||||
{"icon": browser.runtime.getURL("1.png"),
|
||||
"panel": browser.runtime.getURL("default-2.html"),
|
||||
"title": "Default Title 2",
|
||||
},
|
||||
{"icon": browser.runtime.getURL("default-2.png"),
|
||||
"panel": browser.runtime.getURL("default-2.html"),
|
||||
"title": "Default Title 2",
|
||||
},
|
||||
{"icon": browser.runtime.getURL("1.png"),
|
||||
"panel": browser.runtime.getURL("2.html"),
|
||||
"title": "Default Title 2",
|
||||
},
|
||||
];
|
||||
|
||||
return [
|
||||
async expect => {
|
||||
browser.test.log("Initial state, expect default properties.");
|
||||
|
||||
await expectDefaults(details[0]);
|
||||
expect(details[0]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Change the icon in the current tab. Expect default properties excluding the icon.");
|
||||
await browser.sidebarAction.setIcon({tabId: tabs[0], path: "1.png"});
|
||||
|
||||
await expectDefaults(details[0]);
|
||||
expect(details[1]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Create a new tab. Expect default properties.");
|
||||
let tab = await browser.tabs.create({active: true, url: "about:blank?0"});
|
||||
tabs.push(tab.id);
|
||||
|
||||
await expectDefaults(details[0]);
|
||||
expect(details[0]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Change properties. Expect new properties.");
|
||||
let tabId = tabs[1];
|
||||
await Promise.all([
|
||||
browser.sidebarAction.setIcon({tabId, path: "2.png"}),
|
||||
browser.sidebarAction.setPanel({tabId, panel: "2.html"}),
|
||||
browser.sidebarAction.setTitle({tabId, title: "Title 2"}),
|
||||
]);
|
||||
await expectDefaults(details[0]);
|
||||
expect(details[2]);
|
||||
},
|
||||
expect => {
|
||||
browser.test.log("Navigate to a new page. Expect no changes.");
|
||||
|
||||
// TODO: This listener should not be necessary, but the |tabs.update|
|
||||
// callback currently fires too early in e10s windows.
|
||||
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
|
||||
if (tabId == tabs[1] && changed.url) {
|
||||
browser.tabs.onUpdated.removeListener(listener);
|
||||
expect(details[2]);
|
||||
}
|
||||
});
|
||||
|
||||
browser.tabs.update(tabs[1], {url: "about:blank?1"});
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Switch back to the first tab. Expect previously set properties.");
|
||||
await browser.tabs.update(tabs[0], {active: true});
|
||||
expect(details[1]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Change default values, expect those changes reflected.");
|
||||
await Promise.all([
|
||||
browser.sidebarAction.setIcon({path: "default-2.png"}),
|
||||
browser.sidebarAction.setPanel({panel: "default-2.html"}),
|
||||
browser.sidebarAction.setTitle({title: "Default Title 2"}),
|
||||
]);
|
||||
|
||||
await expectDefaults(details[3]);
|
||||
expect(details[3]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Switch back to tab 2. Expect former value, unaffected by changes to defaults in previous step.");
|
||||
await browser.tabs.update(tabs[1], {active: true});
|
||||
|
||||
await expectDefaults(details[3]);
|
||||
expect(details[2]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Delete tab, switch back to tab 1. Expect previous results again.");
|
||||
await browser.tabs.remove(tabs[1]);
|
||||
expect(details[4]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Create a new tab. Expect new default properties.");
|
||||
let tab = await browser.tabs.create({active: true, url: "about:blank?2"});
|
||||
tabs.push(tab.id);
|
||||
expect(details[5]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Delete tab.");
|
||||
await browser.tabs.remove(tabs[2]);
|
||||
expect(details[4]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Change tab panel.");
|
||||
let tabId = tabs[0];
|
||||
await browser.sidebarAction.setPanel({tabId, panel: "2.html"});
|
||||
expect(details[6]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Revert tab panel.");
|
||||
let tabId = tabs[0];
|
||||
await browser.sidebarAction.setPanel({tabId, panel: ""});
|
||||
expect(details[4]);
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* testDefaultTitle() {
|
||||
yield runTests({
|
||||
manifest: {
|
||||
"name": "Foo Extension",
|
||||
|
||||
"sidebar_action": {
|
||||
"default_icon": "icon.png",
|
||||
"default_panel": "sidebar.html",
|
||||
},
|
||||
|
||||
"permissions": ["tabs"],
|
||||
},
|
||||
|
||||
files: {
|
||||
"sidebar.html": sidebar,
|
||||
"icon.png": imageBuffer,
|
||||
},
|
||||
|
||||
getTests(tabs, expectDefaults) {
|
||||
let details = [
|
||||
{"title": "Foo Extension",
|
||||
"panel": browser.runtime.getURL("sidebar.html"),
|
||||
"icon": browser.runtime.getURL("icon.png")},
|
||||
{"title": "Foo Title",
|
||||
"panel": browser.runtime.getURL("sidebar.html"),
|
||||
"icon": browser.runtime.getURL("icon.png")},
|
||||
{"title": "Bar Title",
|
||||
"panel": browser.runtime.getURL("sidebar.html"),
|
||||
"icon": browser.runtime.getURL("icon.png")},
|
||||
{"title": "",
|
||||
"panel": browser.runtime.getURL("sidebar.html"),
|
||||
"icon": browser.runtime.getURL("icon.png")},
|
||||
];
|
||||
|
||||
return [
|
||||
async expect => {
|
||||
browser.test.log("Initial state. Expect extension title as default title.");
|
||||
|
||||
await expectDefaults(details[0]);
|
||||
expect(details[0]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Change the title. Expect new title.");
|
||||
browser.sidebarAction.setTitle({tabId: tabs[0], title: "Foo Title"});
|
||||
|
||||
await expectDefaults(details[0]);
|
||||
expect(details[1]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Change the default. Expect same properties.");
|
||||
browser.sidebarAction.setTitle({title: "Bar Title"});
|
||||
|
||||
await expectDefaults(details[2]);
|
||||
expect(details[1]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Clear the title. Expect new default title.");
|
||||
browser.sidebarAction.setTitle({tabId: tabs[0], title: ""});
|
||||
|
||||
await expectDefaults(details[2]);
|
||||
expect(details[2]);
|
||||
},
|
||||
async expect => {
|
||||
browser.test.log("Set default title to null string. Expect null string from API, extension title in UI.");
|
||||
browser.sidebarAction.setTitle({title: ""});
|
||||
|
||||
await expectDefaults(details[3]);
|
||||
expect(details[3]);
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
});
|
@ -514,7 +514,7 @@ PlacesTreeView.prototype = {
|
||||
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIXULChromeRegistry)
|
||||
.getSelectedLocale("global", true);
|
||||
const dtOptions = { year: "2-digit", month: "numeric", day: "numeric",
|
||||
const dtOptions = { year: "numeric", month: "numeric", day: "numeric",
|
||||
hour: "numeric", minute: "numeric" };
|
||||
this.__dateFormatter = new Intl.DateTimeFormat(locale, dtOptions);
|
||||
}
|
||||
|
@ -127,7 +127,7 @@
|
||||
case "date":
|
||||
let timeObj = new Date(node.time / 1000);
|
||||
// Default is short date format.
|
||||
let dtOptions = { year: '2-digit', month: 'numeric', day: 'numeric',
|
||||
let dtOptions = { year: 'numeric', month: 'numeric', day: 'numeric',
|
||||
hour: 'numeric', minute: 'numeric' };
|
||||
// For today's visits we don't show date portion.
|
||||
if (node.uri == "http://at.midnight.com/" ||
|
||||
|
@ -10,32 +10,9 @@
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let { utils: Cu } = Components;
|
||||
|
||||
let { Promise: { defer } } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
|
||||
// opens a sidebar
|
||||
function openSidebar(win) {
|
||||
let { promise, resolve } = defer();
|
||||
let doc = win.document;
|
||||
|
||||
let sidebarID = 'viewBookmarksSidebar';
|
||||
|
||||
let sidebar = doc.getElementById('sidebar');
|
||||
|
||||
let sidebarurl = doc.getElementById(sidebarID).getAttribute('sidebarurl');
|
||||
|
||||
sidebar.addEventListener('load', function onSidebarLoad() {
|
||||
if (sidebar.contentWindow.location.href != sidebarurl)
|
||||
return;
|
||||
sidebar.removeEventListener('load', onSidebarLoad, true);
|
||||
|
||||
resolve(win);
|
||||
}, true);
|
||||
|
||||
win.SidebarUI.show(sidebarID);
|
||||
|
||||
return promise;
|
||||
return win.SidebarUI.show("viewBookmarksSidebar").then(() => win);
|
||||
}
|
||||
|
||||
let windowCache = [];
|
||||
|
@ -16,17 +16,10 @@ function whenNewWindowLoaded(aOptions, aCallback) {
|
||||
return win;
|
||||
}
|
||||
|
||||
function openWindow(aParent, aOptions, a3) {
|
||||
let { Promise: { defer } } = Components.utils.import("resource://gre/modules/Promise.jsm", {});
|
||||
let { promise, resolve } = defer();
|
||||
|
||||
function openWindow(aParent, aOptions) {
|
||||
let win = aParent.OpenBrowserWindow(aOptions);
|
||||
|
||||
win.addEventListener("load", function() {
|
||||
resolve(win);
|
||||
}, {once: true});
|
||||
|
||||
return promise;
|
||||
return TestUtils.topicObserved("browser-delayed-startup-finished",
|
||||
subject => subject == win).then(() => win);
|
||||
}
|
||||
|
||||
function newDirectory() {
|
||||
|
@ -67,6 +67,8 @@
|
||||
|
||||
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
|
||||
|
||||
#define APP_REG_NAME_BASE L"Firefox-"
|
||||
|
||||
using mozilla::IsWin8OrLater;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
@ -91,152 +93,6 @@ OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Default Browser Registry Settings
|
||||
//
|
||||
// The setting of these values are made by an external binary since writing
|
||||
// these values may require elevation.
|
||||
//
|
||||
// To allow multiple installations to coexist, identifiers written to the
|
||||
// registry include a hash of the installation path. This is referred to as
|
||||
// <PathHash> in the tables below.
|
||||
//
|
||||
// - File Extension Mappings
|
||||
// -----------------------
|
||||
// The following file extensions:
|
||||
// .htm .html .shtml .xht .xhtml
|
||||
// are mapped like so:
|
||||
//
|
||||
// HKCU\SOFTWARE\Classes\.<ext>\ (default) REG_SZ FirefoxHTML-<PathHash>
|
||||
//
|
||||
// as aliases to the class:
|
||||
//
|
||||
// HKCU\SOFTWARE\Classes\FirefoxHTML-<PathHash>\
|
||||
// DefaultIcon (default) REG_SZ <apppath>,1
|
||||
// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
|
||||
// shell\open\ddeexec (default) REG_SZ <empty string>
|
||||
//
|
||||
// - Windows Vista and above Protocol Handler
|
||||
//
|
||||
// HKCU\SOFTWARE\Classes\FirefoxURL-<PathHash>\
|
||||
// (default) REG_SZ <appname> URL
|
||||
// EditFlags REG_DWORD 2
|
||||
// FriendlyTypeName REG_SZ <appname> URL
|
||||
// DefaultIcon (default) REG_SZ <apppath>,1
|
||||
// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
|
||||
// shell\open\ddeexec (default) REG_SZ <empty string>
|
||||
//
|
||||
// - Protocol Mappings
|
||||
// -----------------
|
||||
// The following protocols:
|
||||
// HTTP, HTTPS, FTP
|
||||
// are mapped like so:
|
||||
//
|
||||
// HKCU\SOFTWARE\Classes\<protocol>\
|
||||
// DefaultIcon (default) REG_SZ <apppath>,1
|
||||
// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
|
||||
// shell\open\ddeexec (default) REG_SZ <empty string>
|
||||
//
|
||||
// - Windows Start Menu (XP SP1 and newer)
|
||||
// -------------------------------------------------
|
||||
// The following keys are set to make Firefox appear in the Start Menu as the
|
||||
// browser:
|
||||
//
|
||||
// HKCU\SOFTWARE\Clients\StartMenuInternet\<appname>-<PathHash>\
|
||||
// (default) REG_SZ <appname>
|
||||
// DefaultIcon (default) REG_SZ <apppath>,0
|
||||
// InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts
|
||||
// InstallInfo IconsVisible REG_DWORD 1
|
||||
// InstallInfo ReinstallCommand REG_SZ <uninstpath> /SetAsDefaultAppGlobal
|
||||
// InstallInfo ShowIconsCommand REG_SZ <uninstpath> /ShowShortcuts
|
||||
// shell\open\command (default) REG_SZ <apppath>
|
||||
// shell\properties (default) REG_SZ <appname> &Options
|
||||
// shell\properties\command (default) REG_SZ <apppath> -preferences
|
||||
// shell\safemode (default) REG_SZ <appname> &Safe Mode
|
||||
// shell\safemode\command (default) REG_SZ <apppath> -safe-mode
|
||||
//
|
||||
// - RegisteredApplications
|
||||
// -------------------------------------------------
|
||||
// This entry creates the listing in Default Apps for Windows 8 and up and in
|
||||
// Set Program Access and Defaults (SPAD) on older versions.
|
||||
//
|
||||
// HKCU\Software\RegisteredApplications\
|
||||
// Firefox-<PathHash> REG_SZ "Software\Clients\StartMenuInternet\<appname>-<PathHash>\Capabilities"
|
||||
// HKCU\Software\Clients\StartMenuInternet\<appname>-<PathHash>\Capabilities\
|
||||
// ApplicationDescription REG_SZ <branding description>
|
||||
// ApplicationIcon REG_SZ <apppath>,0
|
||||
// ApplicationName REG_SZ <appname>
|
||||
// FileAssociations .htm REG_SZ FirefoxHTML-<PathHash>
|
||||
// FileAssociations .html REG_SZ FirefoxHTML-<PathHash>
|
||||
// FileAssociations .shtml REG_SZ FirefoxHTML-<PathHash>
|
||||
// FileAssociations .xht REG_SZ FirefoxHTML-<PathHash>
|
||||
// FileAssociations .xhtml REG_SZ FirefoxHTML-<PathHash>
|
||||
// StartMenu StartMenuInternet REG_SZ <appname>-<PathHash>
|
||||
// URLAssociations ftp REG_SZ FirefoxURL-<PathHash>
|
||||
// URLAssociations http REG_SZ FirefoxURL-<PathHash>
|
||||
// URLAssociations https REG_SZ FirefoxURL-<PathHash>
|
||||
|
||||
// The values checked are all default values so the value name is not needed.
|
||||
typedef struct {
|
||||
const char* keyName;
|
||||
const char* valueData;
|
||||
const char* oldValueData;
|
||||
} SETTING;
|
||||
|
||||
#define APP_REG_NAME_BASE L"Firefox-"
|
||||
#define VAL_FILE_ICON "%APPPATH%,1"
|
||||
#define VAL_OPEN "\"%APPPATH%\" -osint -url \"%1\""
|
||||
#define OLD_VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
|
||||
#define DI "\\DefaultIcon"
|
||||
#define SOC "\\shell\\open\\command"
|
||||
#define SOD "\\shell\\open\\ddeexec"
|
||||
// Used for updating the FTP protocol handler's shell open command under HKCU.
|
||||
#define FTP_SOC L"Software\\Classes\\ftp\\shell\\open\\command"
|
||||
|
||||
#define MAKE_KEY_NAME1(PREFIX, MID) \
|
||||
PREFIX MID
|
||||
|
||||
// The DefaultIcon registry key value should never be used when checking if
|
||||
// Firefox is the default browser for file handlers since other applications
|
||||
// (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
|
||||
// Handlers. see http://msdn2.microsoft.com/en-us/library/aa969357.aspx for
|
||||
// more info. The FTP protocol is not checked so advanced users can set the FTP
|
||||
// handler to another application and still have Firefox check if it is the
|
||||
// default HTTP and HTTPS handler.
|
||||
// *** Do not add additional checks here unless you skip them when aForAllTypes
|
||||
// is false below***.
|
||||
static SETTING gSettings[] = {
|
||||
// File Handler Class
|
||||
// ***keep this as the first entry because when aForAllTypes is not set below
|
||||
// it will skip over this check.***
|
||||
{ MAKE_KEY_NAME1("FirefoxHTML", SOC), VAL_OPEN, OLD_VAL_OPEN },
|
||||
|
||||
// Protocol Handler Class - for Vista and above
|
||||
{ MAKE_KEY_NAME1("FirefoxURL", SOC), VAL_OPEN, OLD_VAL_OPEN },
|
||||
|
||||
// Protocol Handlers
|
||||
{ MAKE_KEY_NAME1("HTTP", DI), VAL_FILE_ICON },
|
||||
{ MAKE_KEY_NAME1("HTTP", SOC), VAL_OPEN, OLD_VAL_OPEN },
|
||||
{ MAKE_KEY_NAME1("HTTPS", DI), VAL_FILE_ICON },
|
||||
{ MAKE_KEY_NAME1("HTTPS", SOC), VAL_OPEN, OLD_VAL_OPEN }
|
||||
};
|
||||
|
||||
// The settings to disable DDE are separate from the default browser settings
|
||||
// since they are only checked when Firefox is the default browser and if they
|
||||
// are incorrect they are fixed without notifying the user.
|
||||
static SETTING gDDESettings[] = {
|
||||
// File Handler Class
|
||||
{ MAKE_KEY_NAME1("Software\\Classes\\FirefoxHTML", SOD) },
|
||||
|
||||
// Protocol Handler Class - for Vista and above
|
||||
{ MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) },
|
||||
|
||||
// Protocol Handlers
|
||||
{ MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
|
||||
{ MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
|
||||
{ MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
|
||||
};
|
||||
|
||||
nsresult
|
||||
GetHelperPath(nsAutoString& aPath)
|
||||
{
|
||||
@ -373,29 +229,6 @@ IsAARDefault(const RefPtr<IApplicationAssociationRegistration>& pAAR,
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
static void
|
||||
IsDefaultBrowserWin8(bool aCheckAllTypes, bool* aIsDefaultBrowser)
|
||||
{
|
||||
RefPtr<IApplicationAssociationRegistration> pAAR;
|
||||
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
||||
nullptr,
|
||||
CLSCTX_INPROC,
|
||||
IID_IApplicationAssociationRegistration,
|
||||
getter_AddRefs(pAAR));
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool res = IsAARDefault(pAAR, L"http");
|
||||
if (*aIsDefaultBrowser) {
|
||||
*aIsDefaultBrowser = res;
|
||||
}
|
||||
res = IsAARDefault(pAAR, L".html");
|
||||
if (*aIsDefaultBrowser && aCheckAllTypes) {
|
||||
*aIsDefaultBrowser = res;
|
||||
}
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GetAppRegName(nsAutoString &aAppRegName)
|
||||
{
|
||||
@ -414,279 +247,45 @@ GetAppRegName(nsAutoString &aAppRegName)
|
||||
rv = exeFile->GetParent(getter_AddRefs(appDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString path;
|
||||
rv = appDir->GetPath(path);
|
||||
nsAutoString appDirStr;
|
||||
rv = appDir->GetPath(appDirStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint64_t hash = CityHash64(static_cast<const char *>(path.get()),
|
||||
path.Length() * sizeof(nsAutoString::char_type));
|
||||
|
||||
aAppRegName = APP_REG_NAME_BASE;
|
||||
aAppRegName.AppendInt((int)hash, 16);
|
||||
uint64_t hash = CityHash64(static_cast<const char *>(appDirStr.get()),
|
||||
appDirStr.Length() * sizeof(nsAutoString::char_type));
|
||||
aAppRegName.AppendInt((int)(hash >> 32), 16);
|
||||
aAppRegName.AppendInt((int)hash, 16);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Query's the AAR for the default status.
|
||||
* This only checks for FirefoxURL and if aCheckAllTypes is set, then
|
||||
* it also checks for FirefoxHTML. Note that those ProgIDs are shared
|
||||
* by all Firefox browsers.
|
||||
*/
|
||||
bool
|
||||
nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes,
|
||||
bool* aIsDefaultBrowser)
|
||||
{
|
||||
RefPtr<IApplicationAssociationRegistration> pAAR;
|
||||
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
||||
nullptr,
|
||||
CLSCTX_INPROC,
|
||||
IID_IApplicationAssociationRegistration,
|
||||
getter_AddRefs(pAAR));
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aCheckAllTypes) {
|
||||
BOOL res;
|
||||
nsAutoString appRegName;
|
||||
GetAppRegName(appRegName);
|
||||
hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
|
||||
appRegName.get(),
|
||||
&res);
|
||||
*aIsDefaultBrowser = res;
|
||||
} else if (!IsWin8OrLater()) {
|
||||
*aIsDefaultBrowser = IsAARDefault(pAAR, L"http");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
|
||||
bool aForAllTypes,
|
||||
bool* aIsDefaultBrowser)
|
||||
{
|
||||
// Assume we're the default unless one of the several checks below tell us
|
||||
// otherwise.
|
||||
*aIsDefaultBrowser = true;
|
||||
mozilla::Unused << aStartupCheck;
|
||||
|
||||
wchar_t exePath[MAX_BUF];
|
||||
if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
|
||||
return NS_ERROR_FAILURE;
|
||||
*aIsDefaultBrowser = false;
|
||||
|
||||
// Convert the path to a long path since GetModuleFileNameW returns the path
|
||||
// that was used to launch Firefox which is not necessarily a long path.
|
||||
if (!::GetLongPathNameW(exePath, exePath, MAX_BUF))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString appLongPath(exePath);
|
||||
|
||||
HKEY theKey;
|
||||
DWORD res;
|
||||
nsresult rv;
|
||||
wchar_t currValue[MAX_BUF];
|
||||
|
||||
SETTING* settings = gSettings;
|
||||
if (!aForAllTypes && IsWin8OrLater()) {
|
||||
// Skip over the file handler check
|
||||
settings++;
|
||||
RefPtr<IApplicationAssociationRegistration> pAAR;
|
||||
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
|
||||
nullptr,
|
||||
CLSCTX_INPROC,
|
||||
IID_IApplicationAssociationRegistration,
|
||||
getter_AddRefs(pAAR));
|
||||
if (FAILED(hr)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SETTING* end = gSettings + sizeof(gSettings) / sizeof(SETTING);
|
||||
|
||||
for (; settings < end; ++settings) {
|
||||
NS_ConvertUTF8toUTF16 keyName(settings->keyName);
|
||||
NS_ConvertUTF8toUTF16 valueData(settings->valueData);
|
||||
int32_t offset = valueData.Find("%APPPATH%");
|
||||
valueData.Replace(offset, 9, appLongPath);
|
||||
|
||||
rv = OpenKeyForReading(HKEY_CLASSES_ROOT, keyName, &theKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
*aIsDefaultBrowser = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
::ZeroMemory(currValue, sizeof(currValue));
|
||||
DWORD len = sizeof currValue;
|
||||
res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
|
||||
(LPBYTE)currValue, &len);
|
||||
// Close the key that was opened.
|
||||
::RegCloseKey(theKey);
|
||||
if (REG_FAILED(res) ||
|
||||
_wcsicmp(valueData.get(), currValue)) {
|
||||
// Key wasn't set or was set to something other than our registry entry.
|
||||
NS_ConvertUTF8toUTF16 oldValueData(settings->oldValueData);
|
||||
offset = oldValueData.Find("%APPPATH%");
|
||||
oldValueData.Replace(offset, 9, appLongPath);
|
||||
// The current registry value doesn't match the current or the old format.
|
||||
if (_wcsicmp(oldValueData.get(), currValue)) {
|
||||
*aIsDefaultBrowser = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
res = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName.get(),
|
||||
0, KEY_SET_VALUE, &theKey);
|
||||
if (REG_FAILED(res)) {
|
||||
// If updating the open command fails try to update it using the helper
|
||||
// application when setting Firefox as the default browser.
|
||||
*aIsDefaultBrowser = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
|
||||
(const BYTE *) valueData.get(),
|
||||
(valueData.Length() + 1) * sizeof(char16_t));
|
||||
// Close the key that was created.
|
||||
::RegCloseKey(theKey);
|
||||
if (REG_FAILED(res)) {
|
||||
// If updating the open command fails try to update it using the helper
|
||||
// application when setting Firefox as the default browser.
|
||||
*aIsDefaultBrowser = false;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only check if Firefox is the default browser on Vista and above if the
|
||||
// previous checks show that Firefox is the default browser.
|
||||
if (*aIsDefaultBrowser) {
|
||||
IsDefaultBrowserVista(aForAllTypes, aIsDefaultBrowser);
|
||||
if (IsWin8OrLater()) {
|
||||
IsDefaultBrowserWin8(aForAllTypes, aIsDefaultBrowser);
|
||||
}
|
||||
}
|
||||
|
||||
// To handle the case where DDE isn't disabled due for a user because there
|
||||
// account didn't perform a Firefox update this will check if Firefox is the
|
||||
// default browser and if dde is disabled for each handler
|
||||
// and if it isn't disable it. When Firefox is not the default browser the
|
||||
// helper application will disable dde for each handler.
|
||||
*aIsDefaultBrowser = IsAARDefault(pAAR, L"http");
|
||||
if (*aIsDefaultBrowser && aForAllTypes) {
|
||||
// Check ftp settings
|
||||
|
||||
end = gDDESettings + sizeof(gDDESettings) / sizeof(SETTING);
|
||||
|
||||
for (settings = gDDESettings; settings < end; ++settings) {
|
||||
NS_ConvertUTF8toUTF16 keyName(settings->keyName);
|
||||
|
||||
rv = OpenKeyForReading(HKEY_CURRENT_USER, keyName, &theKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
::RegCloseKey(theKey);
|
||||
// If disabling DDE fails try to disable it using the helper
|
||||
// application when setting Firefox as the default browser.
|
||||
*aIsDefaultBrowser = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
::ZeroMemory(currValue, sizeof(currValue));
|
||||
DWORD len = sizeof currValue;
|
||||
res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
|
||||
(LPBYTE)currValue, &len);
|
||||
// Close the key that was opened.
|
||||
::RegCloseKey(theKey);
|
||||
if (REG_FAILED(res) || char16_t('\0') != *currValue) {
|
||||
// Key wasn't set or was set to something other than our registry entry.
|
||||
// Delete the key along with all of its childrean and then recreate it.
|
||||
::SHDeleteKeyW(HKEY_CURRENT_USER, keyName.get());
|
||||
res = ::RegCreateKeyExW(HKEY_CURRENT_USER, keyName.get(), 0, nullptr,
|
||||
REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
|
||||
nullptr, &theKey, nullptr);
|
||||
if (REG_FAILED(res)) {
|
||||
// If disabling DDE fails try to disable it using the helper
|
||||
// application when setting Firefox as the default browser.
|
||||
*aIsDefaultBrowser = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
res = ::RegSetValueExW(theKey, L"", 0, REG_SZ, (const BYTE *) L"",
|
||||
sizeof(char16_t));
|
||||
// Close the key that was created.
|
||||
::RegCloseKey(theKey);
|
||||
if (REG_FAILED(res)) {
|
||||
// If disabling DDE fails try to disable it using the helper
|
||||
// application when setting Firefox as the default browser.
|
||||
*aIsDefaultBrowser = false;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the FTP protocol handler's shell open command if it is the old
|
||||
// format.
|
||||
res = ::RegOpenKeyExW(HKEY_CURRENT_USER, FTP_SOC, 0, KEY_ALL_ACCESS,
|
||||
&theKey);
|
||||
// Don't update the FTP protocol handler's shell open command when opening
|
||||
// its registry key fails under HKCU since it most likely doesn't exist.
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ConvertUTF8toUTF16 oldValueOpen(OLD_VAL_OPEN);
|
||||
int32_t offset = oldValueOpen.Find("%APPPATH%");
|
||||
oldValueOpen.Replace(offset, 9, appLongPath);
|
||||
|
||||
::ZeroMemory(currValue, sizeof(currValue));
|
||||
DWORD len = sizeof currValue;
|
||||
res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr, (LPBYTE)currValue,
|
||||
&len);
|
||||
|
||||
// Don't update the FTP protocol handler's shell open command when the
|
||||
// current registry value doesn't exist or matches the old format.
|
||||
if (REG_FAILED(res) ||
|
||||
_wcsicmp(oldValueOpen.get(), currValue)) {
|
||||
::RegCloseKey(theKey);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ConvertUTF8toUTF16 valueData(VAL_OPEN);
|
||||
valueData.Replace(offset, 9, appLongPath);
|
||||
res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
|
||||
(const BYTE *) valueData.get(),
|
||||
(valueData.Length() + 1) * sizeof(char16_t));
|
||||
// Close the key that was created.
|
||||
::RegCloseKey(theKey);
|
||||
// If updating the FTP protocol handlers shell open command fails try to
|
||||
// update it using the helper application when setting Firefox as the
|
||||
// default browser.
|
||||
if (REG_FAILED(res)) {
|
||||
*aIsDefaultBrowser = false;
|
||||
}
|
||||
*aIsDefaultBrowser = IsAARDefault(pAAR, L".html");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
|
||||
{
|
||||
// shell32.dll is in the knownDLLs list so will always be loaded from the
|
||||
// system32 directory.
|
||||
static const wchar_t kSehllLibraryName[] = L"shell32.dll";
|
||||
HMODULE shellDLL = ::LoadLibraryW(kSehllLibraryName);
|
||||
if (!shellDLL) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
decltype(SHOpenWithDialog)* SHOpenWithDialogFn =
|
||||
(decltype(SHOpenWithDialog)*) GetProcAddress(shellDLL, "SHOpenWithDialog");
|
||||
|
||||
if (!SHOpenWithDialogFn) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
HRESULT hr = SHOpenWithDialogFn(hwndParent, poainfo);
|
||||
if (SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))) {
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
FreeLibrary(shellDLL);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsWindowsShellService::LaunchControlPanelDefaultsSelectionUI()
|
||||
{
|
||||
@ -863,7 +462,12 @@ nsWindowsShellService::LaunchHTTPHandlerPane()
|
||||
info.oaifInFlags = OAIF_FORCE_REGISTRATION |
|
||||
OAIF_URL_PROTOCOL |
|
||||
OAIF_REGISTER_EXT;
|
||||
return DynSHOpenWithDialog(nullptr, &info);
|
||||
|
||||
HRESULT hr = SHOpenWithDialog(nullptr, &info);
|
||||
if (SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))) {
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -26,7 +26,6 @@ public:
|
||||
NS_DECL_NSIWINDOWSSHELLSERVICE
|
||||
|
||||
protected:
|
||||
bool IsDefaultBrowserVista(bool aCheckAllTypes, bool* aIsDefaultBrowser);
|
||||
nsresult LaunchControlPanelDefaultsSelectionUI();
|
||||
nsresult LaunchControlPanelDefaultPrograms();
|
||||
nsresult LaunchModernSettingsDialogDefaultApps();
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.1-dev (38014d1b6 2017-02-08) gecko build with -fPIC",
|
||||
"size": 75614428,
|
||||
"digest": "1bfd06db51c4aeaf43e43d8080069bba4b3d590a4863366ceb9c9a9915fbc528111fa067a13fc701ee00cbeda21a9f5de23d20d2479eab35fa2d7f729c660159",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -24,9 +24,9 @@
|
||||
"size": 12072532
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 132388656,
|
||||
"digest": "46c2c5d048b6d9e9bbb163277a1ae8a3c37727ad8aa8dd661c2b95e2b68e4e85b20ae4fa0eadf3a37a3c09801964fd7107151909ad07c3a7b2fbf805c7035d97",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 110076708,
|
||||
"digest": "2c865f12279b103e8861071e05480cd8aeb9c4e4cd63eea1b8ca50fb92880583bebd27a3af6a86b3f12b9ee89e70839140f061ab829fcceca5e85dc8bc428ec3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -8,9 +8,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 118864812,
|
||||
"digest": "649900813154b21c51c129050fde791e9974083936c9ef002dc18e1c6f8b9ad9ecfbdb5dd580e87743fc2bebed9b64ef9906461e60ec2a1e5277f3c213f417c9",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 122688750,
|
||||
"digest": "3216889f778b7df63e1d90f788322beb13f4120b36f43bc92108468443b7fdadc0249ef82dfe04ad6a8224d2b65b8d5bfdc803244809f4f65fd469d769039573",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -33,17 +33,18 @@
|
||||
"size": 1020700
|
||||
},
|
||||
{
|
||||
"size": 57060,
|
||||
"version": "https://github.com/andreas56/libdmg-hfsplus rev 81dd75fd1549b24bf8af9736ac25518b367e6b63",
|
||||
"size": 62032,
|
||||
"visibility": "public",
|
||||
"digest": "9649ca595f4cf088d118da26201f92cc94cda7af49c7c48112ee31cd13c83b2935b3e145de9dd78060cff2480b4c2e7ff5fb24235876956fed13c87852071998",
|
||||
"digest": "9073c41034784eb8823ec817aed42bbc65c8da63ad3fac572726fa48b36320ee302ca8f51b23576e7fdbeec6ab300610d0c58bbd9c52024577dfdb13d95aa2ec",
|
||||
"algorithm": "sha512",
|
||||
"unpack": true,
|
||||
"filename": "dmg.tar.xz"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 152573516,
|
||||
"digest": "eef2f10bf57005d11c34b9b49eb76d0f09d026295055039fea89952a3be51580abdab29366278ed4bfa393b33c5cee4d51d3af4221e9e7d7d833d0fc1347597c",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 140312816,
|
||||
"digest": "9b464eae8e8ae0020609b019ce10407eabb65580b2bf97fd1719dee15d6211fa61cb8bf7671efb415515256eaa0c5e48270f74d322e0b9105ee56b61a0de4935",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -8,9 +8,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 118864812,
|
||||
"digest": "649900813154b21c51c129050fde791e9974083936c9ef002dc18e1c6f8b9ad9ecfbdb5dd580e87743fc2bebed9b64ef9906461e60ec2a1e5277f3c213f417c9",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 122688750,
|
||||
"digest": "3216889f778b7df63e1d90f788322beb13f4120b36f43bc92108468443b7fdadc0249ef82dfe04ad6a8224d2b65b8d5bfdc803244809f4f65fd469d769039573",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -6,9 +6,9 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 63983591,
|
||||
"digest": "7bd57c81e57a984a83de75dce214e344cee870bf7e1955ae3831f5a3d638fd4d2d1dca6d434a3264f98bc3b3f00dedb55d0b6d28afd9015d231e8a8f3075dea0",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 67183225,
|
||||
"digest": "83e3f621587598ed46a3cde20c440f372a69db60d9bcb287bca6578d689a48a4caf2c0d3e490968856aaf5f4fad7314078936b7cc92a3344093541c3e6f2553f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -6,9 +6,9 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 63983591,
|
||||
"digest": "7bd57c81e57a984a83de75dce214e344cee870bf7e1955ae3831f5a3d638fd4d2d1dca6d434a3264f98bc3b3f00dedb55d0b6d28afd9015d231e8a8f3075dea0",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 67183225,
|
||||
"digest": "83e3f621587598ed46a3cde20c440f372a69db60d9bcb287bca6578d689a48a4caf2c0d3e490968856aaf5f4fad7314078936b7cc92a3344093541c3e6f2553f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -6,9 +6,9 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 63983591,
|
||||
"digest": "7bd57c81e57a984a83de75dce214e344cee870bf7e1955ae3831f5a3d638fd4d2d1dca6d434a3264f98bc3b3f00dedb55d0b6d28afd9015d231e8a8f3075dea0",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 67183225,
|
||||
"digest": "83e3f621587598ed46a3cde20c440f372a69db60d9bcb287bca6578d689a48a4caf2c0d3e490968856aaf5f4fad7314078936b7cc92a3344093541c3e6f2553f",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.bz2",
|
||||
"unpack": true
|
||||
|
@ -6,9 +6,9 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 69760089,
|
||||
"digest": "1ad9b88c90c70a11b76526a437f0f4df9590cd3dced50229a306b4b49fbf22b45871461cff9e33c8aabd00ef7734732f09dae131f1805587bac864e63f24f68f",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 72765977,
|
||||
"digest": "eb17864d7221b3bff46a33b483691c5bbd3d8ced66343ec4c789d84c87d931fafc4da499066b586966a4a5c10232d9b1fd424b6d00ad795dddbe8b12903442f9",
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "rustc.tar.bz2",
|
||||
|
@ -6,9 +6,9 @@
|
||||
"filename": "mozmake.exe"
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0 (e8a012324 2016-12-16) repack",
|
||||
"size": 69760089,
|
||||
"digest": "1ad9b88c90c70a11b76526a437f0f4df9590cd3dced50229a306b4b49fbf22b45871461cff9e33c8aabd00ef7734732f09dae131f1805587bac864e63f24f68f",
|
||||
"version": "rustc 1.15.0 (10893a9a3 2017-01-19) repack",
|
||||
"size": 72765977,
|
||||
"digest": "eb17864d7221b3bff46a33b483691c5bbd3d8ced66343ec4c789d84c87d931fafc4da499066b586966a4a5c10232d9b1fd424b6d00ad795dddbe8b12903442f9",
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "rustc.tar.bz2",
|
||||
|
@ -17,8 +17,8 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// Rules from the mozilla plugin
|
||||
"mozilla/balanced-listeners": "error",
|
||||
"mozilla/no-aArgs": "warn",
|
||||
"mozilla/no-cpows-in-tests": "warn",
|
||||
"mozilla/var-only-at-top-level": "warn",
|
||||
"mozilla/no-cpows-in-tests": "error",
|
||||
"mozilla/var-only-at-top-level": "error",
|
||||
|
||||
"valid-jsdoc": ["error", {
|
||||
"prefer": {
|
||||
@ -38,12 +38,6 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// Braces only needed for multi-line arrow function blocks
|
||||
// "arrow-body-style": ["error", "as-needed"],
|
||||
|
||||
// Require spacing around =>
|
||||
"arrow-spacing": "error",
|
||||
|
||||
// Always require spacing around a single line block
|
||||
"block-spacing": "warn",
|
||||
|
||||
// Forbid spaces inside the square brackets of array literals.
|
||||
"array-bracket-spacing": ["error", "never"],
|
||||
|
||||
@ -57,24 +51,12 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// start and end braces on the same line.
|
||||
"brace-style": ["error", "1tbs", {"allowSingleLine": true}],
|
||||
|
||||
// No space before always a space after a comma
|
||||
"comma-spacing": ["error", {"before": false, "after": true}],
|
||||
|
||||
// Commas at the end of the line not the start
|
||||
"comma-style": "error",
|
||||
|
||||
// Don't require spaces around computed properties
|
||||
"computed-property-spacing": ["warn", "never"],
|
||||
|
||||
// Functions are not required to consistently return something or nothing
|
||||
"consistent-return": "off",
|
||||
|
||||
// Require braces around blocks that start a new line
|
||||
"curly": ["error", "all"],
|
||||
|
||||
// Always require a trailing EOL
|
||||
"eol-last": "error",
|
||||
|
||||
// Require function* name()
|
||||
"generator-star-spacing": ["error", {"before": false, "after": true}],
|
||||
|
||||
@ -84,27 +66,12 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// Space after colon not before in property declarations
|
||||
"key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "minimum"}],
|
||||
|
||||
// Require spaces before and after finally, catch, etc.
|
||||
"keyword-spacing": "error",
|
||||
|
||||
// Unix linebreaks
|
||||
"linebreak-style": ["error", "unix"],
|
||||
|
||||
// Always require parenthesis for new calls
|
||||
"new-parens": "error",
|
||||
|
||||
// Use [] instead of Array()
|
||||
"no-array-constructor": "error",
|
||||
|
||||
// No duplicate arguments in function declarations
|
||||
"no-dupe-args": "error",
|
||||
|
||||
// No duplicate keys in object declarations
|
||||
"no-dupe-keys": "error",
|
||||
|
||||
// No duplicate cases in switch statements
|
||||
"no-duplicate-case": "error",
|
||||
|
||||
// If an if block ends with a return no need for an else block
|
||||
// "no-else-return": "error",
|
||||
|
||||
@ -115,74 +82,9 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// which is a valid use case.
|
||||
"no-empty": "error",
|
||||
|
||||
// No empty character classes in regex
|
||||
"no-empty-character-class": "error",
|
||||
|
||||
// Disallow empty destructuring
|
||||
"no-empty-pattern": "error",
|
||||
|
||||
// No assiging to exception variable
|
||||
"no-ex-assign": "error",
|
||||
|
||||
// No using !! where casting to boolean is already happening
|
||||
"no-extra-boolean-cast": "warn",
|
||||
|
||||
// No double semicolon
|
||||
"no-extra-semi": "error",
|
||||
|
||||
// No overwriting defined functions
|
||||
"no-func-assign": "error",
|
||||
|
||||
// No invalid regular expresions
|
||||
"no-invalid-regexp": "error",
|
||||
|
||||
// No odd whitespace characters
|
||||
"no-irregular-whitespace": "error",
|
||||
|
||||
// No single if block inside an else block
|
||||
"no-lonely-if": "warn",
|
||||
|
||||
// No mixing spaces and tabs in indent
|
||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||
|
||||
// Disallow use of multiple spaces (sometimes used to align const values,
|
||||
// array or object items, etc.). It's hard to maintain and doesn't add that
|
||||
// much benefit.
|
||||
"no-multi-spaces": "warn",
|
||||
|
||||
// No reassigning native JS objects
|
||||
"no-native-reassign": "error",
|
||||
|
||||
// Nested ternary statements are confusing
|
||||
"no-nested-ternary": "error",
|
||||
|
||||
// Use {} instead of new Object()
|
||||
"no-new-object": "error",
|
||||
|
||||
// No Math() or JSON()
|
||||
"no-obj-calls": "error",
|
||||
|
||||
// No octal literals
|
||||
"no-octal": "error",
|
||||
|
||||
// No redeclaring variables
|
||||
"no-redeclare": "error",
|
||||
|
||||
// No unnecessary comparisons
|
||||
"no-self-compare": "error",
|
||||
|
||||
// No spaces between function name and parentheses
|
||||
"no-spaced-func": "warn",
|
||||
|
||||
// No trailing whitespace
|
||||
"no-trailing-spaces": "error",
|
||||
|
||||
// Error on newline where a semicolon is needed
|
||||
"no-unexpected-multiline": "error",
|
||||
|
||||
// No unreachable statements
|
||||
"no-unreachable": "error",
|
||||
|
||||
// No expressions where a statement is expected
|
||||
"no-unused-expressions": "error",
|
||||
|
||||
@ -192,30 +94,12 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// No using variables before defined
|
||||
"no-use-before-define": "error",
|
||||
|
||||
// No using with
|
||||
"no-with": "error",
|
||||
|
||||
// Always require semicolon at end of statement
|
||||
"semi": ["error", "always"],
|
||||
|
||||
// Require space before blocks
|
||||
"space-before-blocks": "error",
|
||||
|
||||
// Never use spaces before function parentheses
|
||||
"space-before-function-paren": ["error", {"anonymous": "never", "named": "never"}],
|
||||
|
||||
// Require spaces around operators, except for a|"off".
|
||||
"space-infix-ops": ["error", {"int32Hint": true}],
|
||||
|
||||
// ++ and -- should not need spacing
|
||||
"space-unary-ops": ["warn", {"nonwords": false}],
|
||||
|
||||
// No comparisons to NaN
|
||||
"use-isnan": "error",
|
||||
|
||||
// Only check typeof against valid results
|
||||
"valid-typeof": "error",
|
||||
|
||||
// Disallow using variables outside the blocks they are defined (especially
|
||||
// since only let and const are used, see "no-var").
|
||||
"block-scoped-var": "error",
|
||||
@ -231,228 +115,70 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// with auto-binding fat arrow functions).
|
||||
// "consistent-this": ["error", "self"],
|
||||
|
||||
// Don't require a default case in switch statements. Avoid being forced to
|
||||
// add a bogus default when you know all possible cases are handled.
|
||||
"default-case": "off",
|
||||
|
||||
// Enforce dots on the next line with property name.
|
||||
"dot-location": ["error", "property"],
|
||||
|
||||
// Encourage the use of dot notation whenever possible.
|
||||
"dot-notation": "error",
|
||||
|
||||
// Allow using == instead of ===, in the interest of landing something since
|
||||
// the devtools codebase is split on convention here.
|
||||
"eqeqeq": "off",
|
||||
|
||||
// Don't require function expressions to have a name.
|
||||
// This makes the code more verbose and hard to read. Our engine already
|
||||
// does a fantastic job assigning a name to the function, which includes
|
||||
// the enclosing function name, and worst case you have a line number that
|
||||
// you can just look up.
|
||||
"func-names": "off",
|
||||
|
||||
// Allow use of function declarations and expressions.
|
||||
"func-style": "off",
|
||||
|
||||
// Don't enforce the maximum depth that blocks can be nested. The complexity
|
||||
// rule is a better rule to check this.
|
||||
"max-depth": "off",
|
||||
|
||||
// Maximum length of a line.
|
||||
// Disabled because we exceed this in too many places.
|
||||
"max-len": ["off", 80],
|
||||
// This should be 100 but too many lines were longer than that so set a
|
||||
// conservative upper bound for now.
|
||||
"max-len": ["error", 140],
|
||||
|
||||
// Maximum depth callbacks can be nested.
|
||||
"max-nested-callbacks": ["error", 4],
|
||||
|
||||
// Don't limit the number of parameters that can be used in a function.
|
||||
"max-params": "off",
|
||||
|
||||
// Don't limit the maximum number of statement allowed in a function. We
|
||||
// already have the complexity rule that's a better measurement.
|
||||
"max-statements": "off",
|
||||
|
||||
// Don't require a capital letter for constructors, only check if all new
|
||||
// operators are followed by a capital letter. Don't warn when capitalized
|
||||
// functions are used without the new operator.
|
||||
"new-cap": ["off", {"capIsNew": false}],
|
||||
|
||||
// Allow use of bitwise operators.
|
||||
"no-bitwise": "off",
|
||||
|
||||
// Disallow use of arguments.caller or arguments.callee.
|
||||
"no-caller": "error",
|
||||
|
||||
// Disallow the catch clause parameter name being the same as a variable in
|
||||
// the outer scope, to avoid confusion.
|
||||
"no-catch-shadow": "off",
|
||||
|
||||
// Disallow assignment in conditional expressions.
|
||||
"no-cond-assign": "error",
|
||||
|
||||
// Disallow using the console API.
|
||||
"no-console": "error",
|
||||
|
||||
// Allow using constant expressions in conditions like while (true)
|
||||
"no-constant-condition": "off",
|
||||
|
||||
// Allow use of the continue statement.
|
||||
"no-continue": "off",
|
||||
|
||||
// Disallow control characters in regular expressions.
|
||||
"no-control-regex": "error",
|
||||
|
||||
// Disallow use of debugger.
|
||||
"no-debugger": "error",
|
||||
|
||||
// Disallow deletion of variables (deleting properties is fine).
|
||||
"no-delete-var": "error",
|
||||
|
||||
// Allow division operators explicitly at beginning of regular expression.
|
||||
"no-div-regex": "off",
|
||||
|
||||
// Disallow use of eval(). We have other APIs to evaluate code in content.
|
||||
"no-eval": "error",
|
||||
|
||||
// Disallow adding to native types
|
||||
"no-extend-native": "error",
|
||||
|
||||
// Disallow unnecessary function binding.
|
||||
"no-extra-bind": "error",
|
||||
|
||||
// Allow unnecessary parentheses, as they may make the code more readable.
|
||||
"no-extra-parens": "off",
|
||||
|
||||
// Disallow fallthrough of case statements, except if there is a comment.
|
||||
"no-fallthrough": "error",
|
||||
|
||||
// Allow the use of leading or trailing decimal points in numeric literals.
|
||||
"no-floating-decimal": "off",
|
||||
|
||||
// Allow comments inline after code.
|
||||
"no-inline-comments": "off",
|
||||
|
||||
// Disallow use of labels for anything other then loops and switches.
|
||||
"no-labels": ["error", {"allowLoop": true}],
|
||||
|
||||
// Disallow use of multiline strings (use template strings instead).
|
||||
"no-multi-str": "warn",
|
||||
|
||||
// Disallow multiple empty lines.
|
||||
"no-multiple-empty-lines": ["warn", {"max": 2}],
|
||||
|
||||
// Allow reassignment of function parameters.
|
||||
"no-param-reassign": "off",
|
||||
|
||||
// Allow string concatenation with __dirname and __filename (not a node env).
|
||||
"no-path-concat": "off",
|
||||
|
||||
// Allow use of unary operators, ++ and --.
|
||||
"no-plusplus": "off",
|
||||
|
||||
// Allow using process.env (not a node environment).
|
||||
"no-process-env": "off",
|
||||
|
||||
// Allow using process.exit (not a node environment).
|
||||
"no-process-exit": "off",
|
||||
|
||||
// Disallow usage of __proto__ property.
|
||||
"no-proto": "error",
|
||||
|
||||
// Disallow multiple spaces in a regular expression literal.
|
||||
"no-regex-spaces": "error",
|
||||
|
||||
// Allow reserved words being used as object literal keys.
|
||||
"no-reserved-keys": "off",
|
||||
|
||||
// Don't restrict usage of specified node modules (not a node environment).
|
||||
"no-restricted-modules": "off",
|
||||
|
||||
// Disallow use of assignment in return statement. It is preferable for a
|
||||
// single line of code to have only one easily predictable effect.
|
||||
"no-return-assign": "error",
|
||||
|
||||
// Don't warn about declaration of variables already declared in the outer scope.
|
||||
"no-shadow": "off",
|
||||
|
||||
// Disallow shadowing of names such as arguments.
|
||||
"no-shadow-restricted-names": "error",
|
||||
|
||||
// Allow use of synchronous methods (not a node environment).
|
||||
"no-sync": "off",
|
||||
|
||||
// Allow the use of ternary operators.
|
||||
"no-ternary": "off",
|
||||
|
||||
// Disallow throwing literals (eg. throw "error" instead of
|
||||
// throw new Error("error")).
|
||||
"no-throw-literal": "error",
|
||||
|
||||
// Disallow use of undeclared variables unless mentioned in a /* global */
|
||||
// block. Note that globals from head.js are automatically imported in tests
|
||||
// by the import-headjs-globals rule form the mozilla eslint plugin.
|
||||
"no-undef": "error",
|
||||
|
||||
// Allow dangling underscores in identifiers (for privates).
|
||||
"no-underscore-dangle": "off",
|
||||
|
||||
// Allow use of undefined variable.
|
||||
"no-undefined": "off",
|
||||
|
||||
// Disallow the use of Boolean literals in conditional expressions.
|
||||
"no-unneeded-ternary": "error",
|
||||
|
||||
// We use var-only-at-top-level instead of no-var as we allow top level
|
||||
// vars.
|
||||
"no-var": "off",
|
||||
|
||||
// Allow using TODO/FIXME comments.
|
||||
"no-warning-comments": "off",
|
||||
|
||||
// Don't require method and property shorthand syntax for object literals.
|
||||
// We use this in the code a lot, but not consistently, and this seems more
|
||||
// like something to check at code review time.
|
||||
"object-shorthand": "off",
|
||||
|
||||
// Allow more than one variable declaration per function.
|
||||
"one-var": "off",
|
||||
|
||||
// Disallow padding within blocks.
|
||||
"padded-blocks": ["warn", "never"],
|
||||
|
||||
// Don't require quotes around object literal property names.
|
||||
"quote-props": "off",
|
||||
|
||||
// Double quotes should be used.
|
||||
"quotes": ["warn", "double", {"avoidEscape": true, "allowTemplateLiterals": true}],
|
||||
|
||||
// Require use of the second argument for parseInt().
|
||||
"radix": "error",
|
||||
|
||||
// Enforce spacing after semicolons.
|
||||
"semi-spacing": ["error", {"before": false, "after": true}],
|
||||
|
||||
// Don't require to sort variables within the same declaration block.
|
||||
// Anyway, one-var is disabled.
|
||||
"sort-vars": "off",
|
||||
|
||||
// Require a space immediately following the // in a line comment.
|
||||
"spaced-comment": ["error", "always"],
|
||||
|
||||
// Require "use strict" to be defined globally in the script.
|
||||
"strict": ["error", "global"],
|
||||
|
||||
// Allow vars to be declared anywhere in the scope.
|
||||
"vars-on-top": "off",
|
||||
|
||||
// Don't require immediate function invocation to be wrapped in parentheses.
|
||||
"wrap-iife": "off",
|
||||
|
||||
// Don't require regex literals to be wrapped in parentheses (which
|
||||
// supposedly prevent them from being mistaken for division operators).
|
||||
"wrap-regex": "off",
|
||||
|
||||
// Disallow Yoda conditions (where literal value comes first).
|
||||
"yoda": "error",
|
||||
|
||||
@ -462,9 +188,6 @@ module.exports = { // eslint-disable-line no-undef
|
||||
// Disallow function or variable declarations in nested blocks
|
||||
"no-inner-declarations": "error",
|
||||
|
||||
// Disallow usage of __iterator__ property
|
||||
"no-iterator": "error",
|
||||
|
||||
// Disallow labels that share a name with a variable
|
||||
"no-label-var": "error",
|
||||
|
||||
|
@ -46,7 +46,7 @@ let FormAutofillParent = {
|
||||
/**
|
||||
* Initializes ProfileStorage and registers the message handler.
|
||||
*/
|
||||
init: function() {
|
||||
init() {
|
||||
let storePath =
|
||||
OS.Path.join(OS.Constants.Path.profileDir, PROFILE_JSON_FILE_NAME);
|
||||
|
||||
@ -66,7 +66,7 @@ let FormAutofillParent = {
|
||||
* @param {object} message.data The data of the message.
|
||||
* @param {nsIFrameMessageManager} message.target Caller's message manager.
|
||||
*/
|
||||
receiveMessage: function({name, data, target}) {
|
||||
receiveMessage({name, data, target}) {
|
||||
switch (name) {
|
||||
case "FormAutofill:PopulateFieldValues":
|
||||
this._populateFieldValues(data, target);
|
||||
@ -84,7 +84,7 @@ let FormAutofillParent = {
|
||||
*
|
||||
* @returns {ProfileStorage}
|
||||
*/
|
||||
getProfileStore: function() {
|
||||
getProfileStore() {
|
||||
return this._profileStore;
|
||||
},
|
||||
|
||||
@ -93,7 +93,7 @@ let FormAutofillParent = {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_uninit: function() {
|
||||
_uninit() {
|
||||
if (this._profileStore) {
|
||||
this._profileStore._saveImmediately();
|
||||
this._profileStore = null;
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
],
|
||||
}
|
7
browser/extensions/formautofill/test/unit/.eslintrc.js
Normal file
7
browser/extensions/formautofill/test/unit/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = { // eslint-disable-line no-undef
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js",
|
||||
],
|
||||
};
|
@ -39,7 +39,7 @@ let gFileCounter = Math.floor(Math.random() * 1000000);
|
||||
|
||||
function loadFormAutofillContent() {
|
||||
let facGlobal = {
|
||||
addEventListener: function() {},
|
||||
addEventListener() {},
|
||||
};
|
||||
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader);
|
||||
|
@ -2,8 +2,6 @@
|
||||
* Test for populating field values in Form Autofill Parent.
|
||||
*/
|
||||
|
||||
/* global FormAutofillParent */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://formautofill/FormAutofillParent.jsm");
|
||||
@ -64,7 +62,7 @@ add_task(function* test_populateFieldValues() {
|
||||
fields: TEST_FIELDS,
|
||||
},
|
||||
target: {
|
||||
sendAsyncMessage: function(name, data) {
|
||||
sendAsyncMessage(name, data) {
|
||||
do_check_eq(name, "FormAutofill:fillForm");
|
||||
|
||||
let fields = data.fields;
|
||||
|
@ -16,7 +16,7 @@ let matchingProfiles = [{
|
||||
|
||||
let testCases = [{
|
||||
options: {},
|
||||
matchingProfiles: matchingProfiles,
|
||||
matchingProfiles,
|
||||
searchString: "",
|
||||
fieldName: "",
|
||||
expected: {
|
||||
|
@ -2,8 +2,6 @@
|
||||
* Tests ProfileStorage object.
|
||||
*/
|
||||
|
||||
/* global ProfileStorage */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
@ -457,7 +457,13 @@ class Viewport {
|
||||
type: 'viewport',
|
||||
xOffset: this._runtimePosition.x,
|
||||
yOffset: this._runtimePosition.y,
|
||||
zoom: this._zoom
|
||||
zoom: this._zoom,
|
||||
// FIXME Since Chromium improves pinch-zoom for PDF. PostMessage of type
|
||||
// viewport takes an addition parameter pinchPhase. We workaround
|
||||
// here by adding a pinchPhase of value 0 to make sure that viewing
|
||||
// pdf works normally. More details about pinch-zoom please refer
|
||||
// to chromium revision: 6e1abbfb2450eedddb1ab128be1b31cc93104e41
|
||||
pinchPhase: 0
|
||||
});
|
||||
|
||||
let newPage = this._getMostVisiblePage();
|
||||
|
@ -17,15 +17,12 @@ if test -z $TMPDIR; then
|
||||
TMPDIR=/tmp/
|
||||
fi
|
||||
|
||||
# Install clang first
|
||||
yum install -y clang
|
||||
|
||||
# Set an md5 check file to validate input
|
||||
echo "${md5sum} *${TMPDIR}/${filename}" > $TMPDIR/hfsplus.MD5
|
||||
|
||||
# Most-upstream is https://opensource.apple.com/source/diskdev_cmds/
|
||||
|
||||
# Download the source of the specified version of binutils
|
||||
# Download the source of the specified version of hfsplus
|
||||
wget -c -P $TMPDIR http://pkgs.fedoraproject.org/repo/pkgs/hfsplus-tools/${filename}/${md5sum}/${filename} || exit 1
|
||||
md5sum -c $TMPDIR/hfsplus.MD5 || exit 1
|
||||
mkdir hfsplus-source
|
||||
|
@ -730,7 +730,7 @@ BasePrincipal::CloneStrippingUserContextIdAndFirstPartyDomain()
|
||||
}
|
||||
|
||||
bool
|
||||
BasePrincipal::AddonAllowsLoad(nsIURI* aURI)
|
||||
BasePrincipal::AddonAllowsLoad(nsIURI* aURI, bool aExplicit /* = false */)
|
||||
{
|
||||
if (mOriginAttributes.mAddonId.IsEmpty()) {
|
||||
return false;
|
||||
@ -740,7 +740,7 @@ BasePrincipal::AddonAllowsLoad(nsIURI* aURI)
|
||||
NS_ENSURE_TRUE(aps, false);
|
||||
|
||||
bool allowed = false;
|
||||
nsresult rv = aps->AddonMayLoadURI(mOriginAttributes.mAddonId, aURI, &allowed);
|
||||
nsresult rv = aps->AddonMayLoadURI(mOriginAttributes.mAddonId, aURI, aExplicit, &allowed);
|
||||
return NS_SUCCEEDED(rv) && allowed;
|
||||
}
|
||||
|
||||
|
@ -264,6 +264,11 @@ public:
|
||||
|
||||
already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain();
|
||||
|
||||
// Helper to check whether this principal is associated with an addon that
|
||||
// allows unprivileged code to load aURI. aExplicit == true will prevent
|
||||
// use of all_urls permission, requiring the domain in its permissions.
|
||||
bool AddonAllowsLoad(nsIURI* aURI, bool aExplicit = false);
|
||||
|
||||
protected:
|
||||
virtual ~BasePrincipal();
|
||||
|
||||
@ -278,10 +283,6 @@ protected:
|
||||
virtual bool MayLoadInternal(nsIURI* aURI) = 0;
|
||||
friend class ::nsExpandedPrincipal;
|
||||
|
||||
// Helper to check whether this principal is associated with an addon that
|
||||
// allows unprivileged code to load aURI.
|
||||
bool AddonAllowsLoad(nsIURI* aURI);
|
||||
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mPreloadCSP;
|
||||
OriginAttributes mOriginAttributes;
|
||||
|
@ -47,9 +47,10 @@ interface nsIAddonPolicyService : nsISupports
|
||||
|
||||
/**
|
||||
* Returns true if unprivileged code associated with the given addon may load
|
||||
* data from |aURI|.
|
||||
* data from |aURI|. If |aExplicit| is true, the <all_urls> permission and
|
||||
* permissive host globs are ignored when checking for a match.
|
||||
*/
|
||||
boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI);
|
||||
boolean addonMayLoadURI(in AString aAddonId, in nsIURI aURI, [optional] in boolean aExplicit);
|
||||
|
||||
/**
|
||||
* Returns true if a given extension:// URI is web-accessible.
|
||||
|
@ -299,9 +299,9 @@ AnimationTimeBlock.prototype = {
|
||||
text += "\n";
|
||||
}
|
||||
|
||||
// Adding the easing.
|
||||
if (state.easing) {
|
||||
text += L10N.getStr("player.animationEasingLabel") + " ";
|
||||
// Adding the easing if it is not "linear".
|
||||
if (state.easing && state.easing !== "linear") {
|
||||
text += L10N.getStr("player.animationOverallEasingLabel") + " ";
|
||||
text += state.easing;
|
||||
text += "\n";
|
||||
}
|
||||
|
@ -37,8 +37,11 @@ add_task(function* () {
|
||||
} else {
|
||||
ok(!title.match(/Repeats: /), "The tooltip doesn't show the iterations");
|
||||
}
|
||||
if (state.easing) {
|
||||
ok(title.match(/Easing: /), "The tooltip shows the easing");
|
||||
if (state.easing && state.easing !== "linear") {
|
||||
ok(title.match(/Overall easing: /), "The tooltip shows the easing");
|
||||
} else {
|
||||
ok(!title.match(/Overall easing: /),
|
||||
"The tooltip doesn't show the easing if it is 'linear'");
|
||||
}
|
||||
if (state.fill) {
|
||||
ok(title.match(/Fill: /), "The tooltip shows the fill");
|
||||
|
@ -70,11 +70,12 @@ player.infiniteIterationCountText=∞
|
||||
# %2$S will be replaced by the actual time of iteration start
|
||||
player.animationIterationStartLabel=Iteration start: %1$S (%2$Ss)
|
||||
|
||||
# LOCALIZATION NOTE (player.animationEasingLabel):
|
||||
# LOCALIZATION NOTE (player.animationOverallEasingLabel):
|
||||
# This string is displayed in a tooltip that appears when hovering over
|
||||
# animations in the timeline. It is the label displayed before the animation
|
||||
# easing value.
|
||||
player.animationEasingLabel=Easing:
|
||||
# animations in the timeline. It is the label displayed before the easing
|
||||
# that applies to a whole iteration of an animation as opposed to the
|
||||
# easing that applies between animation keyframes.
|
||||
player.animationOverallEasingLabel=Overall easing:
|
||||
|
||||
# LOCALIZATION NOTE (player.animationFillLabel):
|
||||
# This string is displayed in a tooltip that appears when hovering over
|
||||
|
@ -2,15 +2,19 @@
|
||||
* 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 {
|
||||
ADD_REQUEST,
|
||||
UPDATE_REQUEST,
|
||||
CLEAR_REQUESTS,
|
||||
CLONE_SELECTED_REQUEST,
|
||||
REMOVE_SELECTED_CUSTOM_REQUEST,
|
||||
CLEAR_REQUESTS,
|
||||
SEND_CUSTOM_REQUEST,
|
||||
UPDATE_REQUEST,
|
||||
} = require("../constants");
|
||||
const { getSelectedRequest } = require("../selectors/index");
|
||||
|
||||
function addRequest(id, data, batch) {
|
||||
return {
|
||||
@ -40,6 +44,43 @@ function cloneSelectedRequest() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a new HTTP request using the data in the custom request form.
|
||||
*/
|
||||
function sendCustomRequest() {
|
||||
if (!NetMonitorController.supportsCustomRequest) {
|
||||
return cloneSelectedRequest();
|
||||
}
|
||||
|
||||
return (dispatch, getState) => {
|
||||
const selected = getSelectedRequest(getState());
|
||||
|
||||
if (!selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a new HTTP request using the data in the custom request form
|
||||
let data = {
|
||||
url: selected.url,
|
||||
method: selected.method,
|
||||
httpVersion: selected.httpVersion,
|
||||
};
|
||||
if (selected.requestHeaders) {
|
||||
data.headers = selected.requestHeaders.headers;
|
||||
}
|
||||
if (selected.requestPostData) {
|
||||
data.body = selected.requestPostData.postData.text;
|
||||
}
|
||||
|
||||
NetMonitorController.webConsoleClient.sendHTTPRequest(data, (response) => {
|
||||
return dispatch({
|
||||
type: SEND_CUSTOM_REQUEST,
|
||||
id: response.eventActor.actor,
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a request from the list. Supports removing only cloned requests with a
|
||||
* "isCustom" attribute. Other requests never need to be removed.
|
||||
@ -58,8 +99,9 @@ function clearRequests() {
|
||||
|
||||
module.exports = {
|
||||
addRequest,
|
||||
updateRequest,
|
||||
clearRequests,
|
||||
cloneSelectedRequest,
|
||||
removeSelectedCustomRequest,
|
||||
clearRequests,
|
||||
sendCustomRequest,
|
||||
updateRequest,
|
||||
};
|
||||
|
@ -5,19 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const { getDisplayedRequests } = require("../selectors/index");
|
||||
const { SELECT_REQUEST, PRESELECT_REQUEST } = require("../constants");
|
||||
|
||||
/**
|
||||
* When a new request with a given id is added in future, select it immediately.
|
||||
* Used by the "Edit and Resend" feature, where we know in advance the ID of the
|
||||
* request, at a time when it wasn't sent yet.
|
||||
*/
|
||||
function preselectRequest(id) {
|
||||
return {
|
||||
type: PRESELECT_REQUEST,
|
||||
id
|
||||
};
|
||||
}
|
||||
const { SELECT_REQUEST } = require("../constants");
|
||||
|
||||
/**
|
||||
* Select request with a given id.
|
||||
@ -61,7 +49,6 @@ function selectDelta(delta) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
preselectRequest,
|
||||
selectRequest,
|
||||
selectDelta,
|
||||
};
|
||||
|
@ -5,20 +5,20 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
OPEN_SIDEBAR,
|
||||
OPEN_NETWORK_DETAILS,
|
||||
OPEN_STATISTICS,
|
||||
SELECT_DETAILS_PANEL_TAB,
|
||||
WATERFALL_RESIZE,
|
||||
} = require("../constants");
|
||||
|
||||
/**
|
||||
* Change sidebar open state.
|
||||
* Change network details panel.
|
||||
*
|
||||
* @param {boolean} open - open state
|
||||
* @param {boolean} open - expected network details panel open state
|
||||
*/
|
||||
function openSidebar(open) {
|
||||
function openNetworkDetails(open) {
|
||||
return {
|
||||
type: OPEN_SIDEBAR,
|
||||
type: OPEN_NETWORK_DETAILS,
|
||||
open,
|
||||
};
|
||||
}
|
||||
@ -26,7 +26,7 @@ function openSidebar(open) {
|
||||
/**
|
||||
* Change performance statistics view open state.
|
||||
*
|
||||
* @param {boolean} visible - expected sidebar open state
|
||||
* @param {boolean} visible - expected performance statistics open state
|
||||
*/
|
||||
function openStatistics(open) {
|
||||
return {
|
||||
@ -46,7 +46,7 @@ function resizeWaterfall(width) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the selected tab for details panel.
|
||||
* Change the selected tab for network details panel.
|
||||
*
|
||||
* @param {string} id - tab id to be selected
|
||||
*/
|
||||
@ -58,10 +58,11 @@ function selectDetailsPanelTab(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle sidebar open state.
|
||||
* Toggle network details panel.
|
||||
*/
|
||||
function toggleSidebar() {
|
||||
return (dispatch, getState) => dispatch(openSidebar(!getState().ui.sidebarOpen));
|
||||
function toggleNetworkDetails() {
|
||||
return (dispatch, getState) =>
|
||||
dispatch(openNetworkDetails(!getState().ui.networkDetailsOpen));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,10 +73,10 @@ function toggleStatistics() {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
openSidebar,
|
||||
openNetworkDetails,
|
||||
openStatistics,
|
||||
resizeWaterfall,
|
||||
selectDetailsPanelTab,
|
||||
toggleSidebar,
|
||||
toggleNetworkDetails,
|
||||
toggleStatistics,
|
||||
};
|
||||
|
@ -1,15 +1,22 @@
|
||||
/* 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/. */
|
||||
/* globals NetMonitorView */
|
||||
|
||||
/* globals NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { createClass, PropTypes, DOM } = require("devtools/client/shared/vendor/react");
|
||||
const { L10N } = require("../l10n");
|
||||
const { div, span, button } = DOM;
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const Actions = require("../actions/index");
|
||||
const { ACTIVITY_TYPE } = require("../constants");
|
||||
const { L10N } = require("../l10n");
|
||||
|
||||
const { button, div, span } = DOM;
|
||||
|
||||
/**
|
||||
* UI displayed when the request list is empty. Contains instructions on reloading
|
||||
@ -61,6 +68,7 @@ module.exports = connect(
|
||||
undefined,
|
||||
dispatch => ({
|
||||
onPerfClick: e => dispatch(Actions.openStatistics(true)),
|
||||
onReloadClick: e => NetMonitorView.reloadPage(),
|
||||
onReloadClick: e =>
|
||||
NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
|
||||
})
|
||||
)(RequestListEmptyNotice);
|
||||
|
@ -23,7 +23,7 @@ function propertiesEqual(props, item1, item2) {
|
||||
* Used by shouldComponentUpdate: compare two items, and compare only properties
|
||||
* relevant for rendering the RequestListItem. Other properties (like request and
|
||||
* response headers, cookies, bodies) are ignored. These are very useful for the
|
||||
* sidebar details, but not here.
|
||||
* network details, but not here.
|
||||
*/
|
||||
const UPDATED_REQ_ITEM_PROPS = [
|
||||
"mimeType",
|
||||
|
@ -15,7 +15,7 @@ const Actions = require("../actions/index");
|
||||
const { L10N } = require("../l10n");
|
||||
const {
|
||||
getDisplayedRequestsSummary,
|
||||
isSidebarToggleButtonDisabled,
|
||||
isNetworkDetailsToggleButtonDisabled,
|
||||
} = require("../selectors/index");
|
||||
const {
|
||||
getSizeWithDecimals,
|
||||
@ -43,14 +43,17 @@ function Toolbar({
|
||||
openStatistics,
|
||||
requestFilterTypes,
|
||||
setRequestFilterText,
|
||||
sidebarToggleDisabled,
|
||||
sidebarOpen,
|
||||
networkDetailsToggleDisabled,
|
||||
networkDetailsOpen,
|
||||
summary,
|
||||
toggleNetworkDetails,
|
||||
toggleRequestFilterType,
|
||||
toggleSidebar,
|
||||
}) {
|
||||
let toggleButtonClassName = ["devtools-button"];
|
||||
if (!sidebarOpen) {
|
||||
let toggleButtonClassName = [
|
||||
"network-details-panel-toggle",
|
||||
"devtools-button",
|
||||
];
|
||||
if (!networkDetailsOpen) {
|
||||
toggleButtonClassName.push("pane-collapsed");
|
||||
}
|
||||
|
||||
@ -109,12 +112,11 @@ function Toolbar({
|
||||
onChange: setRequestFilterText,
|
||||
}),
|
||||
button({
|
||||
id: "details-pane-toggle",
|
||||
className: toggleButtonClassName.join(" "),
|
||||
title: sidebarOpen ? COLLPASE_DETAILS_PANE : EXPAND_DETAILS_PANE,
|
||||
disabled: sidebarToggleDisabled,
|
||||
title: networkDetailsOpen ? COLLPASE_DETAILS_PANE : EXPAND_DETAILS_PANE,
|
||||
disabled: networkDetailsToggleDisabled,
|
||||
tabIndex: "0",
|
||||
onMouseDown: toggleSidebar,
|
||||
onMouseDown: toggleNetworkDetails,
|
||||
}),
|
||||
)
|
||||
)
|
||||
@ -128,17 +130,17 @@ Toolbar.propTypes = {
|
||||
openStatistics: PropTypes.func.isRequired,
|
||||
requestFilterTypes: PropTypes.object.isRequired,
|
||||
setRequestFilterText: PropTypes.func.isRequired,
|
||||
sidebarToggleDisabled: PropTypes.bool.isRequired,
|
||||
sidebarOpen: PropTypes.bool.isRequired,
|
||||
networkDetailsToggleDisabled: PropTypes.bool.isRequired,
|
||||
networkDetailsOpen: PropTypes.bool.isRequired,
|
||||
summary: PropTypes.object.isRequired,
|
||||
toggleNetworkDetails: PropTypes.func.isRequired,
|
||||
toggleRequestFilterType: PropTypes.func.isRequired,
|
||||
toggleSidebar: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
sidebarToggleDisabled: isSidebarToggleButtonDisabled(state),
|
||||
sidebarOpen: state.ui.sidebarOpen,
|
||||
networkDetailsToggleDisabled: isNetworkDetailsToggleButtonDisabled(state),
|
||||
networkDetailsOpen: state.ui.networkDetailsOpen,
|
||||
requestFilterTypes: state.filters.requestFilterTypes,
|
||||
summary: getDisplayedRequestsSummary(state),
|
||||
}),
|
||||
@ -152,6 +154,6 @@ module.exports = connect(
|
||||
}
|
||||
dispatch(Actions.toggleRequestFilterType(evt.target.dataset.key));
|
||||
},
|
||||
toggleSidebar: () => dispatch(Actions.toggleSidebar()),
|
||||
toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),
|
||||
})
|
||||
)(Toolbar);
|
||||
|
@ -19,12 +19,12 @@ const actionTypes = {
|
||||
CLEAR_TIMING_MARKERS: "CLEAR_TIMING_MARKERS",
|
||||
CLONE_SELECTED_REQUEST: "CLONE_SELECTED_REQUEST",
|
||||
ENABLE_REQUEST_FILTER_TYPE_ONLY: "ENABLE_REQUEST_FILTER_TYPE_ONLY",
|
||||
OPEN_SIDEBAR: "OPEN_SIDEBAR",
|
||||
OPEN_NETWORK_DETAILS: "OPEN_NETWORK_DETAILS",
|
||||
OPEN_STATISTICS: "OPEN_STATISTICS",
|
||||
PRESELECT_REQUEST: "PRESELECT_REQUEST",
|
||||
REMOVE_SELECTED_CUSTOM_REQUEST: "REMOVE_SELECTED_CUSTOM_REQUEST",
|
||||
SELECT_REQUEST: "SELECT_REQUEST",
|
||||
SELECT_DETAILS_PANEL_TAB: "SELECT_DETAILS_PANEL_TAB",
|
||||
SEND_CUSTOM_REQUEST: "SEND_CUSTOM_REQUEST",
|
||||
SET_REQUEST_FILTER_TEXT: "SET_REQUEST_FILTER_TEXT",
|
||||
SORT_BY: "SORT_BY",
|
||||
TOGGLE_REQUEST_FILTER_TYPE: "TOGGLE_REQUEST_FILTER_TYPE",
|
||||
|
@ -1,222 +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/. */
|
||||
|
||||
/* globals window, dumpn, gNetwork, $, EVENTS, NetMonitorView */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { writeHeaderText,
|
||||
getKeyWithEvent,
|
||||
getUrlQuery,
|
||||
parseQueryString } = require("./request-utils");
|
||||
const Actions = require("./actions/index");
|
||||
|
||||
/**
|
||||
* Functions handling the custom request view.
|
||||
*/
|
||||
function CustomRequestView() {
|
||||
dumpn("CustomRequestView was instantiated");
|
||||
}
|
||||
|
||||
CustomRequestView.prototype = {
|
||||
/**
|
||||
* Initialization function, called when the network monitor is started.
|
||||
*/
|
||||
initialize: function () {
|
||||
dumpn("Initializing the CustomRequestView");
|
||||
|
||||
this.updateCustomRequestEvent = getKeyWithEvent(this.onUpdate.bind(this));
|
||||
$("#custom-pane").addEventListener("input",
|
||||
this.updateCustomRequestEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Destruction function, called when the network monitor is closed.
|
||||
*/
|
||||
destroy: function () {
|
||||
dumpn("Destroying the CustomRequestView");
|
||||
|
||||
$("#custom-pane").removeEventListener("input",
|
||||
this.updateCustomRequestEvent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Populates this view with the specified data.
|
||||
*
|
||||
* @param object data
|
||||
* The data source (this should be the attachment of a request item).
|
||||
* @return object
|
||||
* Returns a promise that resolves upon population the view.
|
||||
*/
|
||||
populate: Task.async(function* (data) {
|
||||
$("#custom-url-value").value = data.url;
|
||||
$("#custom-method-value").value = data.method;
|
||||
this.updateCustomQuery(data.url);
|
||||
|
||||
if (data.requestHeaders) {
|
||||
let headers = data.requestHeaders.headers;
|
||||
$("#custom-headers-value").value = writeHeaderText(headers);
|
||||
}
|
||||
if (data.requestPostData) {
|
||||
let postData = data.requestPostData.postData.text;
|
||||
$("#custom-postdata-value").value = yield gNetwork.getString(postData);
|
||||
}
|
||||
|
||||
window.emit(EVENTS.CUSTOMREQUESTVIEW_POPULATED);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Handle user input in the custom request form.
|
||||
*
|
||||
* @param object field
|
||||
* the field that the user updated.
|
||||
*/
|
||||
onUpdate: function (field) {
|
||||
let selectedItem = NetMonitorView.RequestsMenu.selectedItem;
|
||||
let store = NetMonitorView.RequestsMenu.store;
|
||||
let value;
|
||||
|
||||
switch (field) {
|
||||
case "method":
|
||||
value = $("#custom-method-value").value.trim();
|
||||
store.dispatch(Actions.updateRequest(selectedItem.id, { method: value }));
|
||||
break;
|
||||
case "url":
|
||||
value = $("#custom-url-value").value;
|
||||
this.updateCustomQuery(value);
|
||||
store.dispatch(Actions.updateRequest(selectedItem.id, { url: value }));
|
||||
break;
|
||||
case "query":
|
||||
let query = $("#custom-query-value").value;
|
||||
this.updateCustomUrl(query);
|
||||
value = $("#custom-url-value").value;
|
||||
store.dispatch(Actions.updateRequest(selectedItem.id, { url: value }));
|
||||
break;
|
||||
case "body":
|
||||
value = $("#custom-postdata-value").value;
|
||||
store.dispatch(Actions.updateRequest(selectedItem.id, {
|
||||
requestPostData: {
|
||||
postData: { text: value }
|
||||
}
|
||||
}));
|
||||
break;
|
||||
case "headers":
|
||||
let headersText = $("#custom-headers-value").value;
|
||||
value = parseHeadersText(headersText);
|
||||
store.dispatch(Actions.updateRequest(selectedItem.id, {
|
||||
requestHeaders: { headers: value }
|
||||
}));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the query string field based on the url.
|
||||
*
|
||||
* @param object url
|
||||
* The URL to extract query string from.
|
||||
*/
|
||||
updateCustomQuery: function (url) {
|
||||
const paramsArray = parseQueryString(getUrlQuery(url));
|
||||
|
||||
if (!paramsArray) {
|
||||
$("#custom-query").hidden = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$("#custom-query").hidden = false;
|
||||
$("#custom-query-value").value = writeQueryText(paramsArray);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the url based on the query string field.
|
||||
*
|
||||
* @param object queryText
|
||||
* The contents of the query string field.
|
||||
*/
|
||||
updateCustomUrl: function (queryText) {
|
||||
let params = parseQueryText(queryText);
|
||||
let queryString = writeQueryString(params);
|
||||
|
||||
let url = $("#custom-url-value").value;
|
||||
let oldQuery = getUrlQuery(url);
|
||||
let path = url.replace(oldQuery, queryString);
|
||||
|
||||
$("#custom-url-value").value = path;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse text representation of multiple HTTP headers.
|
||||
*
|
||||
* @param string text
|
||||
* Text of headers
|
||||
* @return array
|
||||
* Array of headers info {name, value}
|
||||
*/
|
||||
function parseHeadersText(text) {
|
||||
return parseRequestText(text, "\\S+?", ":");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse readable text list of a query string.
|
||||
*
|
||||
* @param string text
|
||||
* Text of query string representation
|
||||
* @return array
|
||||
* Array of query params {name, value}
|
||||
*/
|
||||
function parseQueryText(text) {
|
||||
return parseRequestText(text, ".+?", "=");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a text representation of a name[divider]value list with
|
||||
* the given name regex and divider character.
|
||||
*
|
||||
* @param string text
|
||||
* Text of list
|
||||
* @return array
|
||||
* Array of headers info {name, value}
|
||||
*/
|
||||
function parseRequestText(text, namereg, divider) {
|
||||
let regex = new RegExp("(" + namereg + ")\\" + divider + "\\s*(.+)");
|
||||
let pairs = [];
|
||||
|
||||
for (let line of text.split("\n")) {
|
||||
let matches;
|
||||
if (matches = regex.exec(line)) { // eslint-disable-line
|
||||
let [, name, value] = matches;
|
||||
pairs.push({name: name, value: value});
|
||||
}
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out a list of query params into a chunk of text
|
||||
*
|
||||
* @param array params
|
||||
* Array of query params {name, value}
|
||||
* @return string
|
||||
* List of query params in text format
|
||||
*/
|
||||
function writeQueryText(params) {
|
||||
return params.map(({name, value}) => name + "=" + value).join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out a list of query params into a query string
|
||||
*
|
||||
* @param array params
|
||||
* Array of query params {name, value}
|
||||
* @return string
|
||||
* Query string that can be appended to a url.
|
||||
*/
|
||||
function writeQueryString(params) {
|
||||
return params.map(({name, value}) => name + "=" + value).join("&");
|
||||
}
|
||||
|
||||
exports.CustomRequestView = CustomRequestView;
|
@ -59,12 +59,6 @@ const EVENTS = {
|
||||
RESPONSE_IMAGE_THUMBNAIL_DISPLAYED:
|
||||
"NetMonitor:ResponseImageThumbnailAvailable",
|
||||
|
||||
// Fired when Sidebar has finished being populated.
|
||||
SIDEBAR_POPULATED: "NetMonitor:SidebarPopulated",
|
||||
|
||||
// Fired when CustomRequestView has finished being populated.
|
||||
CUSTOMREQUESTVIEW_POPULATED: "NetMonitor:CustomRequestViewPopulated",
|
||||
|
||||
// Fired when charts have been displayed in the PerformanceStatisticsView.
|
||||
PLACEHOLDER_CHARTS_DISPLAYED: "NetMonitor:PlaceholderChartsDisplayed",
|
||||
PRIMED_CACHE_CHART_DISPLAYED: "NetMonitor:PrimedChartsDisplayed",
|
||||
|
@ -15,7 +15,6 @@ DIRS += [
|
||||
|
||||
DevToolsModules(
|
||||
'constants.js',
|
||||
'custom-request-view.js',
|
||||
'events.js',
|
||||
'filter-predicates.js',
|
||||
'l10n.js',
|
||||
@ -26,7 +25,6 @@ DevToolsModules(
|
||||
'request-list-context-menu.js',
|
||||
'request-utils.js',
|
||||
'requests-menu-view.js',
|
||||
'sidebar-view.js',
|
||||
'sort-predicates.js',
|
||||
'store.js',
|
||||
'waterfall-background.js',
|
||||
|
@ -2,24 +2,19 @@
|
||||
* 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 $, gStore, NetMonitorController, dumpn */
|
||||
/* eslint-disable mozilla/reject-some-requires */
|
||||
/* globals $, gStore, NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { ViewHelpers } = require("devtools/client/shared/widgets/view-helpers");
|
||||
const { RequestsMenuView } = require("./requests-menu-view");
|
||||
const { CustomRequestView } = require("./custom-request-view");
|
||||
const { SidebarView } = require("./sidebar-view");
|
||||
const { ACTIVITY_TYPE } = require("./constants");
|
||||
const { Prefs } = require("./prefs");
|
||||
const { createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const Actions = require("./actions/index");
|
||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
|
||||
|
||||
// Components
|
||||
const DetailsPanel = createFactory(require("./shared/components/details-panel"));
|
||||
const NetworkDetailsPanel = createFactory(require("./shared/components/network-details-panel"));
|
||||
const StatisticsPanel = createFactory(require("./components/statistics-panel"));
|
||||
const Toolbar = createFactory(require("./components/toolbar"));
|
||||
|
||||
@ -31,16 +26,16 @@ var NetMonitorView = {
|
||||
* Initializes the network monitor view.
|
||||
*/
|
||||
initialize: function () {
|
||||
this._initializePanes();
|
||||
this._body = $("#body");
|
||||
|
||||
this.detailsPanel = $("#react-details-panel-hook");
|
||||
this.networkDetailsPanel = $("#react-network-details-panel-hook");
|
||||
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
DetailsPanel({ toolbox: NetMonitorController._toolbox }),
|
||||
), this.detailsPanel);
|
||||
NetworkDetailsPanel({ toolbox: NetMonitorController._toolbox }),
|
||||
), this.networkDetailsPanel);
|
||||
|
||||
this.statisticsPanel = $("#statistics-panel");
|
||||
this.statisticsPanel = $("#react-statistics-panel-hook");
|
||||
|
||||
ReactDOM.render(Provider(
|
||||
{ store: gStore },
|
||||
@ -55,7 +50,6 @@ var NetMonitorView = {
|
||||
), this.toolbar);
|
||||
|
||||
this.RequestsMenu.initialize(gStore);
|
||||
this.CustomRequest.initialize();
|
||||
|
||||
// Store watcher here is for observing the statisticsOpen state change.
|
||||
// It should be removed once we migrate to react and apply react/redex binding.
|
||||
@ -70,111 +64,21 @@ var NetMonitorView = {
|
||||
* Destroys the network monitor view.
|
||||
*/
|
||||
destroy: function () {
|
||||
this._isDestroyed = true;
|
||||
this.RequestsMenu.destroy();
|
||||
this.CustomRequest.destroy();
|
||||
ReactDOM.unmountComponentAtNode(this.detailsPanel);
|
||||
ReactDOM.unmountComponentAtNode(this.networkDetailsPanel);
|
||||
ReactDOM.unmountComponentAtNode(this.statisticsPanel);
|
||||
ReactDOM.unmountComponentAtNode(this.toolbar);
|
||||
this.unsubscribeStore();
|
||||
|
||||
this._destroyPanes();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the UI for all the displayed panes.
|
||||
*/
|
||||
_initializePanes: function () {
|
||||
dumpn("Initializing the NetMonitorView panes");
|
||||
|
||||
this._body = $("#body");
|
||||
this._detailsPane = $("#details-pane");
|
||||
|
||||
this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth);
|
||||
this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight);
|
||||
this.toggleDetailsPane({ visible: false });
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys the UI for all the displayed panes.
|
||||
*/
|
||||
_destroyPanes: Task.async(function* () {
|
||||
dumpn("Destroying the NetMonitorView panes");
|
||||
|
||||
Prefs.networkDetailsWidth = this._detailsPane.getAttribute("width");
|
||||
Prefs.networkDetailsHeight = this._detailsPane.getAttribute("height");
|
||||
|
||||
this._detailsPane = null;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Gets the visibility state of the network details pane.
|
||||
* @return boolean
|
||||
*/
|
||||
get detailsPaneHidden() {
|
||||
return this._detailsPane.classList.contains("pane-collapsed");
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the network details pane hidden or visible.
|
||||
*
|
||||
* @param object flags
|
||||
* An object containing some of the following properties:
|
||||
* - visible: true if the pane should be shown, false to hide
|
||||
* - animated: true to display an animation on toggle
|
||||
* - delayed: true to wait a few cycles before toggle
|
||||
* - callback: a function to invoke when the toggle finishes
|
||||
* @param number tabIndex [optional]
|
||||
* The index of the intended selected tab in the details pane.
|
||||
*/
|
||||
toggleDetailsPane: function (flags, tabIndex) {
|
||||
ViewHelpers.togglePane(flags, this._detailsPane);
|
||||
|
||||
if (flags.visible) {
|
||||
this._body.classList.remove("pane-collapsed");
|
||||
gStore.dispatch(Actions.openSidebar(true));
|
||||
} else {
|
||||
this._body.classList.add("pane-collapsed");
|
||||
gStore.dispatch(Actions.openSidebar(false));
|
||||
}
|
||||
|
||||
if (tabIndex !== undefined) {
|
||||
$("#event-details-pane").selectedIndex = tabIndex;
|
||||
}
|
||||
},
|
||||
|
||||
get currentFrontendMode() {
|
||||
// The getter may be called from a timeout after the panel is destroyed.
|
||||
if (!this._body.selectedPanel) {
|
||||
return null;
|
||||
}
|
||||
return this._body.selectedPanel.id;
|
||||
},
|
||||
|
||||
toggleFrontendMode: function () {
|
||||
if (gStore.getState().ui.statisticsOpen) {
|
||||
this.showNetworkStatisticsView();
|
||||
this._body.selectedPanel = $("#react-statistics-panel-hook");
|
||||
NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
|
||||
} else {
|
||||
this.showNetworkInspectorView();
|
||||
this._body.selectedPanel = $("#inspector-panel");
|
||||
}
|
||||
},
|
||||
|
||||
showNetworkInspectorView: function () {
|
||||
this._body.selectedPanel = $("#inspector-panel");
|
||||
},
|
||||
|
||||
showNetworkStatisticsView: function () {
|
||||
this._body.selectedPanel = $("#statistics-panel");
|
||||
NetMonitorController.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
|
||||
},
|
||||
|
||||
reloadPage: function () {
|
||||
NetMonitorController.triggerActivity(
|
||||
ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT);
|
||||
},
|
||||
|
||||
_body: null,
|
||||
_detailsPane: null,
|
||||
};
|
||||
|
||||
// A smart store watcher to notify store changes as necessary
|
||||
@ -193,8 +97,6 @@ function storeWatcher(initialValue, reduceValue, onChange) {
|
||||
/**
|
||||
* Preliminary setup for the NetMonitorView object.
|
||||
*/
|
||||
NetMonitorView.Sidebar = new SidebarView();
|
||||
NetMonitorView.RequestsMenu = new RequestsMenuView();
|
||||
NetMonitorView.CustomRequest = new CustomRequestView();
|
||||
|
||||
exports.NetMonitorView = NetMonitorView;
|
||||
|
@ -33,76 +33,18 @@
|
||||
<splitter id="network-inspector-view-splitter"
|
||||
class="devtools-side-splitter"/>
|
||||
|
||||
<deck id="details-pane"
|
||||
hidden="true">
|
||||
<vbox id="custom-pane"
|
||||
class="tabpanel-content">
|
||||
<hbox align="baseline">
|
||||
<label data-localization="content=netmonitor.custom.newRequest"
|
||||
class="plain tabpanel-summary-label
|
||||
custom-header"/>
|
||||
<hbox flex="1" pack="end"
|
||||
class="devtools-toolbarbutton-group">
|
||||
<button id="custom-request-send-button"
|
||||
class="devtools-toolbarbutton"
|
||||
data-localization="label=netmonitor.custom.send"/>
|
||||
<button id="custom-request-close-button"
|
||||
class="devtools-toolbarbutton"
|
||||
data-localization="label=netmonitor.custom.cancel"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<hbox id="custom-method-and-url"
|
||||
class="tabpanel-summary-container"
|
||||
align="center">
|
||||
<textbox id="custom-method-value"
|
||||
data-key="method"/>
|
||||
<textbox id="custom-url-value"
|
||||
flex="1"
|
||||
data-key="url"/>
|
||||
</hbox>
|
||||
<vbox id="custom-query"
|
||||
class="tabpanel-summary-container custom-section">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
data-localization="content=netmonitor.custom.query"/>
|
||||
<textbox id="custom-query-value"
|
||||
class="tabpanel-summary-input"
|
||||
multiline="true"
|
||||
rows="4"
|
||||
wrap="off"
|
||||
data-key="query"/>
|
||||
</vbox>
|
||||
<vbox id="custom-headers"
|
||||
class="tabpanel-summary-container custom-section">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
data-localization="content=netmonitor.custom.headers"/>
|
||||
<textbox id="custom-headers-value"
|
||||
class="tabpanel-summary-input"
|
||||
multiline="true"
|
||||
rows="8"
|
||||
wrap="off"
|
||||
data-key="headers"/>
|
||||
</vbox>
|
||||
<vbox id="custom-postdata"
|
||||
class="tabpanel-summary-container custom-section">
|
||||
<label class="plain tabpanel-summary-label"
|
||||
data-localization="content=netmonitor.custom.postData"/>
|
||||
<textbox id="custom-postdata-value"
|
||||
class="tabpanel-summary-input"
|
||||
multiline="true"
|
||||
rows="6"
|
||||
wrap="off"
|
||||
data-key="body"/>
|
||||
</vbox>
|
||||
</vbox>
|
||||
<box id="splitter-adjustable-box"
|
||||
hidden="true">
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="react-details-panel-hook"/>
|
||||
</deck>
|
||||
id="react-network-details-panel-hook">
|
||||
</html:div>
|
||||
</box>
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
|
||||
<html:div xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="statistics-panel">
|
||||
id="react-statistics-panel-hook">
|
||||
</html:div>
|
||||
</deck>
|
||||
|
||||
|
@ -8,13 +8,13 @@ const I = require("devtools/client/shared/vendor/immutable");
|
||||
const { getUrlDetails } = require("../request-utils");
|
||||
const {
|
||||
ADD_REQUEST,
|
||||
UPDATE_REQUEST,
|
||||
CLEAR_REQUESTS,
|
||||
SELECT_REQUEST,
|
||||
PRESELECT_REQUEST,
|
||||
CLONE_SELECTED_REQUEST,
|
||||
OPEN_NETWORK_DETAILS,
|
||||
REMOVE_SELECTED_CUSTOM_REQUEST,
|
||||
OPEN_SIDEBAR,
|
||||
SELECT_REQUEST,
|
||||
SEND_CUSTOM_REQUEST,
|
||||
UPDATE_REQUEST,
|
||||
} = require("../constants");
|
||||
|
||||
const Request = I.Record({
|
||||
@ -43,6 +43,9 @@ const Request = I.Record({
|
||||
totalTime: undefined,
|
||||
eventTimings: undefined,
|
||||
headersSize: undefined,
|
||||
// Text value is used for storing custom request query
|
||||
// which only appears when user edit the custom requst form
|
||||
customQueryValue: undefined,
|
||||
requestHeaders: undefined,
|
||||
requestHeadersFromUploadStream: undefined,
|
||||
requestCookies: undefined,
|
||||
@ -81,6 +84,7 @@ const UPDATE_PROPS = [
|
||||
"totalTime",
|
||||
"eventTimings",
|
||||
"headersSize",
|
||||
"customQueryValue",
|
||||
"requestHeaders",
|
||||
"requestHeadersFromUploadStream",
|
||||
"requestCookies",
|
||||
@ -92,6 +96,29 @@ const UPDATE_PROPS = [
|
||||
"formDataSections",
|
||||
];
|
||||
|
||||
/**
|
||||
* Remove the currently selected custom request.
|
||||
*/
|
||||
function closeCustomRequest(state) {
|
||||
let { requests, selectedId } = state;
|
||||
|
||||
if (!selectedId) {
|
||||
return state;
|
||||
}
|
||||
|
||||
let removedRequest = requests.get(selectedId);
|
||||
|
||||
// Only custom requests can be removed
|
||||
if (!removedRequest || !removedRequest.isCustom) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return state.withMutations(st => {
|
||||
st.requests = st.requests.delete(selectedId);
|
||||
st.selectedId = null;
|
||||
});
|
||||
}
|
||||
|
||||
function requestsReducer(state = new Requests(), action) {
|
||||
switch (action.type) {
|
||||
case ADD_REQUEST: {
|
||||
@ -119,7 +146,6 @@ function requestsReducer(state = new Requests(), action) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
case UPDATE_REQUEST: {
|
||||
let { requests, lastEndedMillis } = state;
|
||||
|
||||
@ -166,9 +192,6 @@ function requestsReducer(state = new Requests(), action) {
|
||||
case SELECT_REQUEST: {
|
||||
return state.set("selectedId", action.id);
|
||||
}
|
||||
case PRESELECT_REQUEST: {
|
||||
return state.set("preselectedId", action.id);
|
||||
}
|
||||
case CLONE_SELECTED_REQUEST: {
|
||||
let { requests, selectedId } = state;
|
||||
|
||||
@ -197,24 +220,15 @@ function requestsReducer(state = new Requests(), action) {
|
||||
});
|
||||
}
|
||||
case REMOVE_SELECTED_CUSTOM_REQUEST: {
|
||||
let { requests, selectedId } = state;
|
||||
|
||||
if (!selectedId) {
|
||||
return state;
|
||||
}
|
||||
|
||||
// Only custom requests can be removed
|
||||
let removedRequest = requests.get(selectedId);
|
||||
if (!removedRequest || !removedRequest.isCustom) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return state.withMutations(st => {
|
||||
st.requests = requests.delete(selectedId);
|
||||
st.selectedId = null;
|
||||
});
|
||||
return closeCustomRequest(state);
|
||||
}
|
||||
case OPEN_SIDEBAR: {
|
||||
case SEND_CUSTOM_REQUEST: {
|
||||
// When a new request with a given id is added in future, select it immediately.
|
||||
// where we know in advance the ID of the request, at a time when it
|
||||
// wasn't sent yet.
|
||||
return closeCustomRequest(state.set("preselectedId", action.id));
|
||||
}
|
||||
case OPEN_NETWORK_DETAILS: {
|
||||
if (!action.open) {
|
||||
return state.set("selectedId", null);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
const I = require("devtools/client/shared/vendor/immutable");
|
||||
const {
|
||||
OPEN_SIDEBAR,
|
||||
OPEN_NETWORK_DETAILS,
|
||||
OPEN_STATISTICS,
|
||||
SELECT_DETAILS_PANEL_TAB,
|
||||
WATERFALL_RESIZE,
|
||||
@ -14,7 +14,7 @@ const {
|
||||
|
||||
const UI = I.Record({
|
||||
detailsPanelSelectedTab: "headers",
|
||||
sidebarOpen: false,
|
||||
networkDetailsOpen: false,
|
||||
statisticsOpen: false,
|
||||
waterfallWidth: null,
|
||||
});
|
||||
@ -26,8 +26,8 @@ function resizeWaterfall(state, action) {
|
||||
return state.set("waterfallWidth", action.width - REQUESTS_WATERFALL_SAFE_BOUNDS);
|
||||
}
|
||||
|
||||
function openSidebar(state, action) {
|
||||
return state.set("sidebarOpen", action.open);
|
||||
function openNetworkDetails(state, action) {
|
||||
return state.set("networkDetailsOpen", action.open);
|
||||
}
|
||||
|
||||
function openStatistics(state, action) {
|
||||
@ -40,8 +40,8 @@ function setDetailsPanelTab(state, action) {
|
||||
|
||||
function ui(state = new UI(), action) {
|
||||
switch (action.type) {
|
||||
case OPEN_SIDEBAR:
|
||||
return openSidebar(state, action);
|
||||
case OPEN_NETWORK_DETAILS:
|
||||
return openNetworkDetails(state, action);
|
||||
case OPEN_STATISTICS:
|
||||
return openStatistics(state, action);
|
||||
case SELECT_DETAILS_PANEL_TAB:
|
||||
|
@ -6,35 +6,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
||||
const { Task } = require("devtools/shared/task");
|
||||
|
||||
/**
|
||||
* Helper method to get a wrapped function which can be bound to as
|
||||
* an event listener directly and is executed only when data-key is
|
||||
* present in event.target.
|
||||
*
|
||||
* @param {function} callback - function to execute execute when data-key
|
||||
* is present in event.target.
|
||||
* @param {bool} onlySpaceOrReturn - flag to indicate if callback should only
|
||||
* be called when the space or return button
|
||||
* is pressed
|
||||
* @return {function} wrapped function with the target data-key as the first argument
|
||||
* and the event as the second argument.
|
||||
*/
|
||||
function getKeyWithEvent(callback, onlySpaceOrReturn) {
|
||||
return function (event) {
|
||||
let key = event.target.getAttribute("data-key");
|
||||
let filterKeyboardEvent = !onlySpaceOrReturn ||
|
||||
event.keyCode === KeyCodes.DOM_VK_SPACE ||
|
||||
event.keyCode === KeyCodes.DOM_VK_RETURN;
|
||||
|
||||
if (key && filterKeyboardEvent) {
|
||||
callback(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||
* POST request.
|
||||
@ -254,7 +227,6 @@ function parseQueryString(query) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getKeyWithEvent,
|
||||
getFormDataSections,
|
||||
fetchHeaders,
|
||||
formDataURI,
|
||||
|
@ -2,7 +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/. */
|
||||
|
||||
/* globals window, dumpn, $, gNetwork, NetMonitorController, NetMonitorView */
|
||||
/* globals window, dumpn, $, gNetwork, NetMonitorController */
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -81,10 +81,10 @@ RequestsMenuView.prototype = {
|
||||
(newSelected, oldSelected) => this.onSelectionUpdate(newSelected, oldSelected)
|
||||
));
|
||||
|
||||
// Watch the sidebar status and resize the waterfall column on change
|
||||
// Watch the network details panel toggle and resize the waterfall column on change
|
||||
this.store.subscribe(storeWatcher(
|
||||
false,
|
||||
() => this.store.getState().ui.sidebarOpen,
|
||||
() => this.store.getState().ui.networkDetailsOpen,
|
||||
() => this.onResize()
|
||||
));
|
||||
|
||||
@ -139,9 +139,6 @@ RequestsMenuView.prototype = {
|
||||
},
|
||||
));
|
||||
|
||||
this.sendCustomRequestEvent = this.sendCustomRequest.bind(this);
|
||||
this.closeCustomRequestEvent = this.closeCustomRequest.bind(this);
|
||||
|
||||
this._summary = $("#requests-menu-network-summary-button");
|
||||
this._summary.setAttribute("label", L10N.getStr("networkMenu.empty"));
|
||||
|
||||
@ -157,17 +154,6 @@ RequestsMenuView.prototype = {
|
||||
{ store: this.store },
|
||||
RequestList()
|
||||
), this.mountPoint);
|
||||
|
||||
window.once("connected", this._onConnect.bind(this));
|
||||
},
|
||||
|
||||
_onConnect() {
|
||||
if (NetMonitorController.supportsCustomRequest) {
|
||||
$("#custom-request-send-button")
|
||||
.addEventListener("click", this.sendCustomRequestEvent);
|
||||
$("#custom-request-close-button")
|
||||
.addEventListener("click", this.closeCustomRequestEvent);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -178,13 +164,6 @@ RequestsMenuView.prototype = {
|
||||
|
||||
Prefs.filters = getActiveFilters(this.store.getState());
|
||||
|
||||
// this.flushRequestsTask.disarm();
|
||||
|
||||
$("#custom-request-send-button")
|
||||
.removeEventListener("click", this.sendCustomRequestEvent);
|
||||
$("#custom-request-close-button")
|
||||
.removeEventListener("click", this.closeCustomRequestEvent);
|
||||
|
||||
this._splitter.removeEventListener("mouseup", this.onResize);
|
||||
window.removeEventListener("resize", this.onResize);
|
||||
|
||||
@ -202,7 +181,7 @@ RequestsMenuView.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all network requests and closes the sidebar if open.
|
||||
* Removes all network requests and closes the network details panel if open.
|
||||
*/
|
||||
clear() {
|
||||
this.store.dispatch(Actions.clearRequests());
|
||||
@ -401,16 +380,15 @@ RequestsMenuView.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the sidebar status when something about the selection changes
|
||||
* Updates the network details panel state when something about the selection changes
|
||||
*/
|
||||
onSelectionUpdate(newSelected, oldSelected) {
|
||||
if (newSelected) {
|
||||
// Another item just got selected
|
||||
NetMonitorView.Sidebar.populate(newSelected);
|
||||
NetMonitorView.Sidebar.toggle(true);
|
||||
this.store.dispatch(Actions.openNetworkDetails(true));
|
||||
} else {
|
||||
// Selection just got empty
|
||||
NetMonitorView.Sidebar.toggle(false);
|
||||
this.store.dispatch(Actions.openNetworkDetails(false));
|
||||
}
|
||||
},
|
||||
|
||||
@ -426,48 +404,7 @@ RequestsMenuView.prototype = {
|
||||
this.store.dispatch(Actions.resizeWaterfall(width));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new custom request form populated with the data from
|
||||
* the currently selected request.
|
||||
*/
|
||||
cloneSelectedRequest() {
|
||||
this.store.dispatch(Actions.cloneSelectedRequest());
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a new HTTP request using the data in the custom request form.
|
||||
*/
|
||||
sendCustomRequest: function () {
|
||||
let selected = getSelectedRequest(this.store.getState());
|
||||
|
||||
let data = {
|
||||
url: selected.url,
|
||||
method: selected.method,
|
||||
httpVersion: selected.httpVersion,
|
||||
};
|
||||
if (selected.requestHeaders) {
|
||||
data.headers = selected.requestHeaders.headers;
|
||||
}
|
||||
if (selected.requestPostData) {
|
||||
data.body = selected.requestPostData.postData.text;
|
||||
}
|
||||
|
||||
NetMonitorController.webConsoleClient.sendHTTPRequest(data, response => {
|
||||
let id = response.eventActor.actor;
|
||||
this.store.dispatch(Actions.preselectRequest(id));
|
||||
});
|
||||
|
||||
this.closeCustomRequest();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the currently selected custom request.
|
||||
*/
|
||||
closeCustomRequest() {
|
||||
this.store.dispatch(Actions.removeSelectedCustomRequest());
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
exports.RequestsMenuView = RequestsMenuView;
|
||||
|
@ -94,7 +94,7 @@ const getDisplayedRequestsSummary = createSelector(
|
||||
|
||||
const getSelectedRequest = createSelector(
|
||||
state => state.requests,
|
||||
({ selectedId, requests }) => selectedId ? requests.get(selectedId) : null
|
||||
({ selectedId, requests }) => selectedId ? requests.get(selectedId) : undefined
|
||||
);
|
||||
|
||||
function getRequestById(state, id) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
const { getDisplayedRequests } = require("./requests");
|
||||
|
||||
function isSidebarToggleButtonDisabled(state) {
|
||||
function isNetworkDetailsToggleButtonDisabled(state) {
|
||||
return getDisplayedRequests(state).isEmpty();
|
||||
}
|
||||
|
||||
@ -31,6 +31,6 @@ function getWaterfallScale(state) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isSidebarToggleButtonDisabled,
|
||||
isNetworkDetailsToggleButtonDisabled,
|
||||
getWaterfallScale,
|
||||
};
|
||||
|
@ -0,0 +1,257 @@
|
||||
/* 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 {
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { L10N } = require("../../l10n");
|
||||
const Actions = require("../../actions/index");
|
||||
const { getSelectedRequest } = require("../../selectors/index");
|
||||
const {
|
||||
getUrlQuery,
|
||||
parseQueryString,
|
||||
writeHeaderText,
|
||||
} = require("../../request-utils");
|
||||
|
||||
const {
|
||||
button,
|
||||
div,
|
||||
input,
|
||||
textarea,
|
||||
} = DOM;
|
||||
|
||||
const CUSTOM_CANCEL = L10N.getStr("netmonitor.custom.cancel");
|
||||
const CUSTOM_HEADERS = L10N.getStr("netmonitor.custom.headers");
|
||||
const CUSTOM_NEW_REQUEST = L10N.getStr("netmonitor.custom.newRequest");
|
||||
const CUSTOM_POSTDATA = L10N.getStr("netmonitor.custom.postData");
|
||||
const CUSTOM_QUERY = L10N.getStr("netmonitor.custom.query");
|
||||
const CUSTOM_SEND = L10N.getStr("netmonitor.custom.send");
|
||||
|
||||
function CustomRequestPanel({
|
||||
removeSelectedCustomRequest,
|
||||
request = {},
|
||||
sendCustomRequest,
|
||||
updateRequest,
|
||||
}) {
|
||||
let {
|
||||
method,
|
||||
customQueryValue,
|
||||
requestHeaders,
|
||||
requestPostData,
|
||||
url,
|
||||
} = request;
|
||||
|
||||
let headers = "";
|
||||
if (requestHeaders) {
|
||||
headers = requestHeaders.customHeadersValue ?
|
||||
requestHeaders.customHeadersValue : writeHeaderText(requestHeaders.headers);
|
||||
}
|
||||
let queryArray = url ? parseQueryString(getUrlQuery(url)) : [];
|
||||
let params = customQueryValue;
|
||||
if (!params) {
|
||||
params = queryArray ?
|
||||
queryArray.map(({ name, value }) => name + "=" + value).join("\n") : "";
|
||||
}
|
||||
let postData = requestPostData && requestPostData.postData.text ?
|
||||
requestPostData.postData.text : "";
|
||||
|
||||
return (
|
||||
div({ className: "custom-request-panel" },
|
||||
div({ className: "tabpanel-summary-container custom-request" },
|
||||
div({ className: "custom-request-label custom-header" },
|
||||
CUSTOM_NEW_REQUEST
|
||||
),
|
||||
button({
|
||||
className: "devtools-button",
|
||||
id: "custom-request-send-button",
|
||||
onClick: sendCustomRequest,
|
||||
},
|
||||
CUSTOM_SEND
|
||||
),
|
||||
button({
|
||||
className: "devtools-button",
|
||||
id: "custom-request-close-button",
|
||||
onClick: removeSelectedCustomRequest,
|
||||
},
|
||||
CUSTOM_CANCEL
|
||||
),
|
||||
),
|
||||
div({
|
||||
className: "tabpanel-summary-container custom-method-and-url",
|
||||
id: "custom-method-and-url",
|
||||
},
|
||||
input({
|
||||
className: "custom-method-value",
|
||||
id: "custom-method-value",
|
||||
onChange: (evt) => updateCustomRequestFields(evt, request, updateRequest),
|
||||
value: method || "GET",
|
||||
}),
|
||||
input({
|
||||
className: "custom-url-value",
|
||||
id: "custom-url-value",
|
||||
onChange: (evt) => updateCustomRequestFields(evt, request, updateRequest),
|
||||
value: url || "http://",
|
||||
}),
|
||||
),
|
||||
// Hide query field when there is no params
|
||||
params ? div({
|
||||
className: "tabpanel-summary-container custom-section",
|
||||
id: "custom-query",
|
||||
},
|
||||
div({ className: "custom-request-label" }, CUSTOM_QUERY),
|
||||
textarea({
|
||||
className: "tabpanel-summary-input",
|
||||
id: "custom-query-value",
|
||||
onChange: (evt) => updateCustomRequestFields(evt, request, updateRequest),
|
||||
rows: 4,
|
||||
value: params,
|
||||
wrap: "off",
|
||||
})
|
||||
) : null,
|
||||
div({
|
||||
id: "custom-headers",
|
||||
className: "tabpanel-summary-container custom-section",
|
||||
},
|
||||
div({ className: "custom-request-label" }, CUSTOM_HEADERS),
|
||||
textarea({
|
||||
className: "tabpanel-summary-input",
|
||||
id: "custom-headers-value",
|
||||
onChange: (evt) => updateCustomRequestFields(evt, request, updateRequest),
|
||||
rows: 8,
|
||||
value: headers,
|
||||
wrap: "off",
|
||||
})
|
||||
),
|
||||
div({
|
||||
id: "custom-postdata",
|
||||
className: "tabpanel-summary-container custom-section",
|
||||
},
|
||||
div({ className: "custom-request-label" }, CUSTOM_POSTDATA),
|
||||
textarea({
|
||||
className: "tabpanel-summary-input",
|
||||
id: "custom-postdata-value",
|
||||
onChange: (evt) => updateCustomRequestFields(evt, request, updateRequest),
|
||||
rows: 6,
|
||||
value: postData,
|
||||
wrap: "off",
|
||||
})
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
CustomRequestPanel.displayName = "CustomRequestPanel";
|
||||
|
||||
CustomRequestPanel.propTypes = {
|
||||
removeSelectedCustomRequest: PropTypes.func.isRequired,
|
||||
request: PropTypes.object,
|
||||
sendCustomRequest: PropTypes.func.isRequired,
|
||||
updateRequest: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a text representation of a name[divider]value list with
|
||||
* the given name regex and divider character.
|
||||
*
|
||||
* @param {string} text - Text of list
|
||||
* @return {array} array of headers info {name, value}
|
||||
*/
|
||||
function parseRequestText(text, namereg, divider) {
|
||||
let regex = new RegExp(`(${namereg})\\${divider}\\s*(.+)`);
|
||||
let pairs = [];
|
||||
|
||||
for (let line of text.split("\n")) {
|
||||
let matches = regex.exec(line);
|
||||
if (matches) {
|
||||
let [, name, value] = matches;
|
||||
pairs.push({ name, value });
|
||||
}
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Custom Request Fields
|
||||
*
|
||||
* @param {Object} evt click event
|
||||
* @param {Object} request current request
|
||||
* @param {updateRequest} updateRequest action
|
||||
*/
|
||||
function updateCustomRequestFields(evt, request, updateRequest) {
|
||||
const val = evt.target.value;
|
||||
let data;
|
||||
switch (evt.target.id) {
|
||||
case "custom-headers-value":
|
||||
let customHeadersValue = val || "";
|
||||
// Parse text representation of multiple HTTP headers
|
||||
let headersArray = parseRequestText(customHeadersValue, "\\S+?", ":");
|
||||
// Remove temp customHeadersValue while query string is parsable
|
||||
if (customHeadersValue === "" ||
|
||||
headersArray.length === customHeadersValue.split("\n").length) {
|
||||
customHeadersValue = null;
|
||||
}
|
||||
data = {
|
||||
requestHeaders: {
|
||||
customHeadersValue,
|
||||
headers: headersArray,
|
||||
},
|
||||
};
|
||||
break;
|
||||
case "custom-method-value":
|
||||
data = { method: val.trim() };
|
||||
break;
|
||||
case "custom-postdata-value":
|
||||
data = {
|
||||
requestPostData: {
|
||||
postData: { text: val },
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "custom-query-value":
|
||||
let customQueryValue = val || "";
|
||||
// Parse readable text list of a query string
|
||||
let queryArray = customQueryValue ?
|
||||
parseRequestText(customQueryValue, ".+?", "=") : [];
|
||||
// Write out a list of query params into a query string
|
||||
let queryString = queryArray.map(
|
||||
({ name, value }) => name + "=" + value).join("&");
|
||||
let url = queryString ? [request.url.split("?")[0], queryString].join("?") :
|
||||
request.url.split("?")[0];
|
||||
// Remove temp customQueryValue while query string is parsable
|
||||
if (customQueryValue === "" ||
|
||||
queryArray.length === customQueryValue.split("\n").length) {
|
||||
customQueryValue = null;
|
||||
}
|
||||
data = {
|
||||
customQueryValue,
|
||||
url,
|
||||
};
|
||||
break;
|
||||
case "custom-url-value":
|
||||
data = {
|
||||
customQueryValue: null,
|
||||
url: val
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (data) {
|
||||
// All updateRequest batch mode should be disabled to make UI editing in sync
|
||||
updateRequest(request.id, data, false);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({ request: getSelectedRequest(state) }),
|
||||
(dispatch) => ({
|
||||
removeSelectedCustomRequest: () => dispatch(Actions.removeSelectedCustomRequest()),
|
||||
sendCustomRequest: () => dispatch(Actions.sendCustomRequest()),
|
||||
updateRequest: (id, data, batch) => dispatch(Actions.updateRequest(id, data, batch)),
|
||||
})
|
||||
)(CustomRequestPanel);
|
@ -4,14 +4,16 @@
|
||||
|
||||
DevToolsModules(
|
||||
'cookies-panel.js',
|
||||
'details-panel.js',
|
||||
'custom-request-panel.js',
|
||||
'editor.js',
|
||||
'headers-mdn.js',
|
||||
'headers-panel.js',
|
||||
'network-details-panel.js',
|
||||
'params-panel.js',
|
||||
'preview-panel.js',
|
||||
'properties-view.js',
|
||||
'response-panel.js',
|
||||
'security-panel.js',
|
||||
'tabbox-panel.js',
|
||||
'timings-panel.js',
|
||||
)
|
||||
|
@ -0,0 +1,102 @@
|
||||
/* 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/. */
|
||||
|
||||
/* globals document */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
createFactory,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
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,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = connect(
|
||||
(state) => ({
|
||||
activeTabId: state.ui.detailsPanelSelectedTab,
|
||||
open: state.ui.networkDetailsOpen,
|
||||
request: getSelectedRequest(state),
|
||||
}),
|
||||
(dispatch) => ({
|
||||
cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
|
||||
selectTab: (tabId) => dispatch(Actions.selectDetailsPanelTab(tabId)),
|
||||
}),
|
||||
)(NetworkDetailsPanel);
|
@ -34,10 +34,10 @@ const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
|
||||
const PREVIEW_TITLE = L10N.getStr("netmonitor.tab.preview");
|
||||
|
||||
/*
|
||||
* Details panel component
|
||||
* Tabbox panel component
|
||||
* Display the network request details
|
||||
*/
|
||||
function DetailsPanel({
|
||||
function TabboxPanel({
|
||||
activeTabId,
|
||||
cloneSelectedRequest,
|
||||
request,
|
||||
@ -104,13 +104,13 @@ function DetailsPanel({
|
||||
);
|
||||
}
|
||||
|
||||
DetailsPanel.displayName = "DetailsPanel";
|
||||
TabboxPanel.displayName = "TabboxPanel";
|
||||
|
||||
DetailsPanel.propTypes = {
|
||||
TabboxPanel.propTypes = {
|
||||
activeTabId: PropTypes.string,
|
||||
cloneSelectedRequest: PropTypes.func.isRequired,
|
||||
request: PropTypes.object,
|
||||
setTabIndex: PropTypes.func.isRequired,
|
||||
selectedTab: PropTypes.number.isRequired,
|
||||
selectTab: PropTypes.func.isRequired,
|
||||
toolbox: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
@ -123,4 +123,4 @@ module.exports = connect(
|
||||
cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
|
||||
selectTab: (tabId) => dispatch(Actions.selectDetailsPanelTab(tabId)),
|
||||
}),
|
||||
)(DetailsPanel);
|
||||
)(TabboxPanel);
|
@ -1,52 +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/. */
|
||||
|
||||
/* globals window, dumpn, $, NetMonitorView */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Task } = require("devtools/shared/task");
|
||||
const { EVENTS } = require("./events");
|
||||
|
||||
/**
|
||||
* Functions handling the sidebar details view.
|
||||
*/
|
||||
function SidebarView() {
|
||||
dumpn("SidebarView was instantiated");
|
||||
}
|
||||
|
||||
SidebarView.prototype = {
|
||||
/**
|
||||
* Sets this view hidden or visible. It's visible by default.
|
||||
*
|
||||
* @param boolean visibleFlag
|
||||
* Specifies the intended visibility.
|
||||
*/
|
||||
toggle: function (visibleFlag) {
|
||||
NetMonitorView.toggleDetailsPane({ visible: visibleFlag });
|
||||
},
|
||||
|
||||
/**
|
||||
* Populates this view with the specified data.
|
||||
*
|
||||
* @param object data
|
||||
* The data source (this should be the attachment of a request item).
|
||||
* @return object
|
||||
* Returns a promise that resolves upon population of the subview.
|
||||
*/
|
||||
populate: Task.async(function* (data) {
|
||||
let isCustom = data.isCustom;
|
||||
|
||||
if (isCustom) {
|
||||
yield NetMonitorView.CustomRequest.populate(data);
|
||||
}
|
||||
|
||||
$("#details-pane").selectedIndex = isCustom ? 0 : 1;
|
||||
|
||||
window.emit(EVENTS.SIDEBAR_POPULATED);
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
exports.SidebarView = SidebarView;
|
@ -128,12 +128,14 @@ 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]
|
||||
[browser_net_req-resp-bodies.js]
|
||||
[browser_net_resend_cors.js]
|
||||
[browser_net_resend_headers.js]
|
||||
[browser_net_resend.js]
|
||||
[browser_net_security-details.js]
|
||||
[browser_net_security-error.js]
|
||||
[browser_net_security-icon-click.js]
|
||||
|
@ -14,7 +14,7 @@ add_task(function* () {
|
||||
// It seems that this test may be slow on Ubuntu builds running on ec2.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let { NetMonitorView, gStore, windowRequire } = monitor.panelWin;
|
||||
let { document, NetMonitorView, gStore, windowRequire } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
@ -22,13 +22,13 @@ add_task(function* () {
|
||||
let Actions = windowRequire("devtools/client/netmonitor/actions/index");
|
||||
|
||||
let count = 0;
|
||||
function check(selectedIndex, paneVisibility) {
|
||||
function check(selectedIndex, panelVisibility) {
|
||||
info("Performing check " + (count++) + ".");
|
||||
|
||||
is(RequestsMenu.selectedIndex, selectedIndex,
|
||||
"The selected item in the requests menu was incorrect.");
|
||||
is(NetMonitorView.detailsPaneHidden, !paneVisibility,
|
||||
"The network requests details pane visibility state was incorrect.");
|
||||
is(!!document.querySelector(".network-details-panel"), panelVisibility,
|
||||
"The network details panel should render correctly.");
|
||||
}
|
||||
|
||||
let wait = waitForNetworkEvents(monitor, 2);
|
||||
|
@ -14,19 +14,19 @@ add_task(function* () {
|
||||
// It seems that this test may be slow on Ubuntu builds running on ec2.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let { window, $, NetMonitorView } = monitor.panelWin;
|
||||
let { window, document, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
let count = 0;
|
||||
function check(selectedIndex, paneVisibility) {
|
||||
function check(selectedIndex, panelVisibility) {
|
||||
info("Performing check " + (count++) + ".");
|
||||
|
||||
is(RequestsMenu.selectedIndex, selectedIndex,
|
||||
"The selected item in the requests menu was incorrect.");
|
||||
is(NetMonitorView.detailsPaneHidden, !paneVisibility,
|
||||
"The network requests details pane visibility state was incorrect.");
|
||||
is(!!document.querySelector(".network-details-panel"), panelVisibility,
|
||||
"The network details panel should render correctly.");
|
||||
}
|
||||
|
||||
let wait = waitForNetworkEvents(monitor, 2);
|
||||
@ -35,7 +35,7 @@ add_task(function* () {
|
||||
});
|
||||
yield wait;
|
||||
|
||||
$(".requests-menu-contents").focus();
|
||||
document.querySelector(".requests-menu-contents").focus();
|
||||
|
||||
check(-1, false);
|
||||
|
||||
@ -122,7 +122,8 @@ add_task(function* () {
|
||||
EventUtils.sendKey("DOWN", window);
|
||||
check(19, true);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $(".request-list-item"));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelector(".request-list-item"));
|
||||
check(0, true);
|
||||
|
||||
yield teardown(monitor);
|
||||
|
@ -40,7 +40,7 @@ add_task(function* () {
|
||||
|
||||
wait = waitForDOM(document, "#response-panel .editor-mount iframe");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
document.querySelector("#response-tab").click();
|
||||
let [editorFrame] = yield wait;
|
||||
|
||||
|
@ -11,16 +11,15 @@ add_task(function* () {
|
||||
let { tab, monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { $, NetMonitorView } = monitor.panelWin;
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
let detailsPane = $("#details-pane");
|
||||
let detailsPaneToggleButton = $("#details-pane-toggle");
|
||||
let clearButton = $("#requests-menu-clear-button");
|
||||
let detailsPanelToggleButton = document.querySelector(".network-details-panel-toggle");
|
||||
let clearButton = document.querySelector("#requests-menu-clear-button");
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
|
||||
// Make sure we start in a sane state
|
||||
assertNoRequestState(RequestsMenu, detailsPaneToggleButton);
|
||||
assertNoRequestState(RequestsMenu, detailsPanelToggleButton);
|
||||
|
||||
// Load one request and assert it shows up in the list
|
||||
let networkEvent = monitor.panelWin.once(monitor.panelWin.EVENTS.NETWORK_EVENT);
|
||||
@ -40,17 +39,18 @@ add_task(function* () {
|
||||
|
||||
assertSingleRequestState();
|
||||
|
||||
// Make sure we can now open the details pane
|
||||
NetMonitorView.toggleDetailsPane({ visible: true, animated: false });
|
||||
ok(!detailsPane.classList.contains("pane-collapsed") &&
|
||||
!detailsPaneToggleButton.classList.contains("pane-collapsed"),
|
||||
// Make sure we can now open the network details panel
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, detailsPanelToggleButton);
|
||||
|
||||
ok(document.querySelector(".network-details-panel") &&
|
||||
!detailsPanelToggleButton.classList.contains("pane-collapsed"),
|
||||
"The details pane should be visible after clicking the toggle button.");
|
||||
|
||||
// Click clear and make sure the details pane closes
|
||||
EventUtils.sendMouseEvent({ type: "click" }, clearButton);
|
||||
assertNoRequestState();
|
||||
ok(detailsPane.classList.contains("pane-collapsed") &&
|
||||
detailsPaneToggleButton.classList.contains("pane-collapsed"),
|
||||
ok(!document.querySelector(".network-details-panel") &&
|
||||
detailsPanelToggleButton.classList.contains("pane-collapsed"),
|
||||
"The details pane should not be visible clicking 'clear'.");
|
||||
|
||||
return teardown(monitor);
|
||||
@ -61,7 +61,7 @@ add_task(function* () {
|
||||
function assertSingleRequestState() {
|
||||
is(RequestsMenu.itemCount, 1,
|
||||
"The request menu should have one item at this point.");
|
||||
is(detailsPaneToggleButton.hasAttribute("disabled"), false,
|
||||
is(detailsPanelToggleButton.hasAttribute("disabled"), false,
|
||||
"The pane toggle button should be enabled after a request is made.");
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ add_task(function* () {
|
||||
function assertNoRequestState() {
|
||||
is(RequestsMenu.itemCount, 0,
|
||||
"The request menu should be empty at this point.");
|
||||
is(detailsPaneToggleButton.hasAttribute("disabled"), true,
|
||||
is(detailsPanelToggleButton.hasAttribute("disabled"), true,
|
||||
"The pane toggle button should be disabled when the request menu is cleared.");
|
||||
}
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ add_task(function* () {
|
||||
|
||||
wait = waitForDOM(document, "#params-panel .tree-section", 2);
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
document.querySelector("#params-tab").click();
|
||||
yield wait;
|
||||
testParamsTab1("a", '""', '{ "foo": "bar" }', '""');
|
||||
@ -61,9 +61,7 @@ add_task(function* () {
|
||||
yield waitForDOM(editorFrames[0].contentDocument, ".CodeMirror-code");
|
||||
testParamsTab2("a", '"b"', "?foo=bar", "text");
|
||||
|
||||
wait = waitForDOM(document, "#params-panel .empty-notice");
|
||||
RequestsMenu.selectedIndex = 6;
|
||||
yield wait;
|
||||
testParamsTab3();
|
||||
|
||||
yield teardown(monitor);
|
||||
|
@ -30,7 +30,7 @@ add_task(function* () {
|
||||
|
||||
wait = waitForDOM(document, "#response-panel .editor-mount iframe");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
document.querySelector("#response-tab").click();
|
||||
let [editor] = yield wait;
|
||||
yield once(editor, "DOMContentLoaded");
|
||||
|
@ -29,7 +29,7 @@ add_task(function* () {
|
||||
|
||||
wait = waitForDOM(document, "#response-panel .editor-mount iframe");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
document.querySelector("#response-tab").click();
|
||||
let [editor] = yield wait;
|
||||
yield once(editor, "DOMContentLoaded");
|
||||
|
@ -140,7 +140,7 @@ add_task(function* () {
|
||||
|
||||
info("Starting test... ");
|
||||
|
||||
let { $, NetMonitorView } = monitor.panelWin;
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
@ -150,85 +150,108 @@ add_task(function* () {
|
||||
yield performRequestsInContent(REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS);
|
||||
yield wait;
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
|
||||
isnot(RequestsMenu.selectedItem, null,
|
||||
"There should be a selected item in the requests menu.");
|
||||
is(RequestsMenu.selectedIndex, 0,
|
||||
"The first item should be selected in the requests menu.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should not be hidden after toggle button was pressed.");
|
||||
is(!!document.querySelector(".network-details-panel"), true,
|
||||
"The network details panel should render correctly.");
|
||||
|
||||
// First test with single filters...
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-html-button"));
|
||||
testFilterButtons(monitor, "html");
|
||||
testContents([1, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
// Reset filters
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-css-button"));
|
||||
testFilterButtons(monitor, "css");
|
||||
testContents([0, 1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-js-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-js-button"));
|
||||
testFilterButtons(monitor, "js");
|
||||
testContents([0, 0, 1, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-xhr-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-xhr-button"));
|
||||
testFilterButtons(monitor, "xhr");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-fonts-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-fonts-button"));
|
||||
testFilterButtons(monitor, "fonts");
|
||||
testContents([0, 0, 0, 1, 0, 0, 0, 0, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-images-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-images-button"));
|
||||
testFilterButtons(monitor, "images");
|
||||
testContents([0, 0, 0, 0, 1, 0, 0, 0, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-media-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-media-button"));
|
||||
testFilterButtons(monitor, "media");
|
||||
testContents([0, 0, 0, 0, 0, 1, 1, 0, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-flash-button"));
|
||||
testFilterButtons(monitor, "flash");
|
||||
testContents([0, 0, 0, 0, 0, 0, 0, 1, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-ws-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-ws-button"));
|
||||
testFilterButtons(monitor, "ws");
|
||||
testContents([0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
|
||||
// Text in filter box that matches nothing should hide all.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
setFreetextFilter("foobar");
|
||||
testContents([0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
// Text in filter box that matches should filter out everything else.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
setFreetextFilter("sample");
|
||||
testContents([1, 1, 1, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
// Text in filter box that matches should filter out everything else.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
setFreetextFilter("SAMPLE");
|
||||
testContents([1, 1, 1, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
// Test negative filtering (only show unmatched items)
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
setFreetextFilter("-sample");
|
||||
testContents([0, 0, 0, 1, 1, 1, 1, 1, 1]);
|
||||
|
||||
@ -236,8 +259,10 @@ add_task(function* () {
|
||||
|
||||
// Enable filtering for html and css; should show request of both type.
|
||||
setFreetextFilter("");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-css-button"));
|
||||
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
testContents([1, 1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
@ -246,28 +271,36 @@ add_task(function* () {
|
||||
setFreetextFilter("sample");
|
||||
testContents([1, 1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-flash-button"));
|
||||
setFreetextFilter("");
|
||||
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0]);
|
||||
testContents([1, 1, 0, 0, 0, 0, 0, 1, 0]);
|
||||
|
||||
// Disable some filters. Only one left active.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-flash-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-css-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-flash-button"));
|
||||
testFilterButtons(monitor, "html");
|
||||
testContents([1, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
// Disable last active filter. Should toggle to all.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-html-button"));
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
|
||||
// Enable few filters and click on all. Only "all" should be checked.
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-css-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-ws-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-css-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-ws-button"));
|
||||
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 1]);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
|
||||
@ -278,8 +311,8 @@ add_task(function* () {
|
||||
"There should still be a selected item after filtering.");
|
||||
is(RequestsMenu.selectedIndex, 0,
|
||||
"The first item should be still selected after filtering.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should still be visible after filtering.");
|
||||
is(!!document.querySelector(".network-details-panel"), true,
|
||||
"The network details panel should render correctly.");
|
||||
|
||||
const items = RequestsMenu.items;
|
||||
const visibleItems = RequestsMenu.visibleItems;
|
||||
|
@ -136,7 +136,7 @@ add_task(function* () {
|
||||
// It seems that this test may be slow on Ubuntu builds running on ec2.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let { $, NetMonitorView } = monitor.panelWin;
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
@ -146,20 +146,22 @@ add_task(function* () {
|
||||
yield performRequestsInContent(REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS);
|
||||
yield wait;
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
|
||||
isnot(RequestsMenu.selectedItem, null,
|
||||
"There should be a selected item in the requests menu.");
|
||||
is(RequestsMenu.selectedIndex, 0,
|
||||
"The first item should be selected in the requests menu.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should not be hidden after toggle button was pressed.");
|
||||
is(!!document.querySelector(".network-details-panel"), true,
|
||||
"The network details panel should be visible after toggle button was pressed.");
|
||||
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
|
||||
info("Testing html filtering.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-html-button"));
|
||||
testFilterButtons(monitor, "html");
|
||||
testContents([1, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
@ -183,7 +185,8 @@ add_task(function* () {
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
info("Resetting filters.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-all-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-all-button"));
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
@ -195,8 +198,8 @@ add_task(function* () {
|
||||
"There should still be a selected item after filtering.");
|
||||
is(RequestsMenu.selectedIndex, 0,
|
||||
"The first item should be still selected after filtering.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should still be visible after filtering.");
|
||||
is(!!document.querySelector(".network-details-panel"), true,
|
||||
"The network details panel should still be visible after filtering.");
|
||||
|
||||
const items = RequestsMenu.items;
|
||||
const visibleItems = RequestsMenu.visibleItems;
|
||||
|
@ -27,7 +27,7 @@ add_task(function* () {
|
||||
// It seems that this test may be slow on Ubuntu builds running on ec2.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
let { $, NetMonitorView } = monitor.panelWin;
|
||||
let { document, NetMonitorView } = monitor.panelWin;
|
||||
let { RequestsMenu } = NetMonitorView;
|
||||
|
||||
RequestsMenu.lazyUpdate = false;
|
||||
@ -44,25 +44,28 @@ add_task(function* () {
|
||||
yield performRequestsInContent(requests);
|
||||
yield wait;
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
|
||||
isnot(RequestsMenu.selectedItem, null,
|
||||
"There should be a selected item in the requests menu.");
|
||||
is(RequestsMenu.selectedIndex, 0,
|
||||
"The first item should be selected in the requests menu.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should not be hidden after toggle button was pressed.");
|
||||
is(!!document.querySelector(".network-details-panel"), true,
|
||||
"The network details panel should be visible after toggle button was pressed.");
|
||||
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([0, 1, 2, 3, 4, 5, 6], 7, 0);
|
||||
|
||||
info("Sorting by size, ascending.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-size-button"));
|
||||
testFilterButtons(monitor, "all");
|
||||
testContents([6, 4, 5, 0, 1, 2, 3], 7, 6);
|
||||
|
||||
info("Testing html filtering.");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-filter-html-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-filter-html-button"));
|
||||
testFilterButtons(monitor, "html");
|
||||
testContents([6, 4, 5, 0, 1, 2, 3], 1, 6);
|
||||
|
||||
@ -89,8 +92,10 @@ add_task(function* () {
|
||||
yield teardown(monitor);
|
||||
|
||||
function resetSorting() {
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-waterfall-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" }, $("#requests-menu-size-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-waterfall-button"));
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#requests-menu-size-button"));
|
||||
}
|
||||
|
||||
function testContents(order, visible, selection) {
|
||||
@ -98,8 +103,8 @@ add_task(function* () {
|
||||
"There should still be a selected item after filtering.");
|
||||
is(RequestsMenu.selectedIndex, selection,
|
||||
"The first item should be still selected after filtering.");
|
||||
is(NetMonitorView.detailsPaneHidden, false,
|
||||
"The details pane should still be visible after filtering.");
|
||||
is(!!document.querySelector(".network-details-panel"), true,
|
||||
"The network details panel should still be visible after filtering.");
|
||||
|
||||
is(RequestsMenu.items.length, order.length,
|
||||
"There should be a specific amount of items in the requests menu.");
|
||||
|
@ -23,7 +23,7 @@ add_task(function* () {
|
||||
yield wait;
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
|
||||
ok(document.querySelector("#headers-tab[aria-selected=true]"),
|
||||
"The headers tab in the details panel should be selected.");
|
||||
@ -32,11 +32,8 @@ add_task(function* () {
|
||||
ok(!document.querySelector("#preview-panel"),
|
||||
"The preview panel is hidden for non html responses.");
|
||||
|
||||
wait = waitForDOM(document, ".tabs");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[4]);
|
||||
yield wait;
|
||||
|
||||
document.querySelector("#preview-tab").click();
|
||||
|
||||
ok(document.querySelector("#preview-tab[aria-selected=true]"),
|
||||
@ -45,7 +42,9 @@ add_task(function* () {
|
||||
"The preview panel should be visible now.");
|
||||
|
||||
let iframe = document.querySelector("#preview-panel iframe");
|
||||
console.log(123)
|
||||
yield once(iframe, "DOMContentLoaded");
|
||||
console.log(123)
|
||||
|
||||
ok(iframe,
|
||||
"There should be a response preview iframe available.");
|
||||
|
@ -25,7 +25,7 @@ add_task(function* () {
|
||||
|
||||
wait = waitForDOM(document, "#response-panel");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
document.querySelector("#response-tab").click();
|
||||
yield wait;
|
||||
|
||||
|
@ -41,7 +41,7 @@ add_task(function* () {
|
||||
|
||||
wait = waitForDOM(document, "#response-panel");
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.getElementById("details-pane-toggle"));
|
||||
document.querySelector(".network-details-panel-toggle"));
|
||||
document.querySelector("#response-tab").click();
|
||||
yield wait;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user