Merge fx-team to m-c a=merge
@ -3,6 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var TrackingProtection = {
|
||||
// If the user ignores the doorhanger, we stop showing it after some time.
|
||||
MAX_INTROS: 0,
|
||||
PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
|
||||
PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
|
||||
@ -106,11 +107,13 @@ var TrackingProtection = {
|
||||
this.content.setAttribute("state", "blocked-tracking-content");
|
||||
|
||||
// Open the tracking protection introduction panel, if applicable.
|
||||
let introCount = gPrefService.getIntPref("privacy.trackingprotection.introCount");
|
||||
if (introCount < TrackingProtection.MAX_INTROS) {
|
||||
gPrefService.setIntPref("privacy.trackingprotection.introCount", ++introCount);
|
||||
gPrefService.savePrefFile(null);
|
||||
this.showIntroPanel();
|
||||
if (this.enabledGlobally) {
|
||||
let introCount = gPrefService.getIntPref("privacy.trackingprotection.introCount");
|
||||
if (introCount < TrackingProtection.MAX_INTROS) {
|
||||
gPrefService.setIntPref("privacy.trackingprotection.introCount", ++introCount);
|
||||
gPrefService.savePrefFile(null);
|
||||
this.showIntroPanel();
|
||||
}
|
||||
}
|
||||
|
||||
this.shieldHistogramAdd(2);
|
||||
@ -183,6 +186,16 @@ var TrackingProtection = {
|
||||
BrowserReload();
|
||||
},
|
||||
|
||||
dontShowIntroPanelAgain() {
|
||||
// This function may be called in private windows, but it does not change
|
||||
// any preference unless Tracking Protection is enabled globally.
|
||||
if (this.enabledGlobally) {
|
||||
gPrefService.setIntPref("privacy.trackingprotection.introCount",
|
||||
this.MAX_INTROS);
|
||||
gPrefService.savePrefFile(null);
|
||||
}
|
||||
},
|
||||
|
||||
showIntroPanel: Task.async(function*() {
|
||||
let brandBundle = document.getElementById("bundle_brand");
|
||||
let brandShortName = brandBundle.getString("brandShortName");
|
||||
@ -190,12 +203,10 @@ var TrackingProtection = {
|
||||
let openStep2 = () => {
|
||||
// When the user proceeds in the tour, adjust the counter to indicate that
|
||||
// the user doesn't need to see the intro anymore.
|
||||
gPrefService.setIntPref("privacy.trackingprotection.introCount",
|
||||
this.MAX_INTROS);
|
||||
gPrefService.savePrefFile(null);
|
||||
this.dontShowIntroPanelAgain();
|
||||
|
||||
let nextURL = Services.urlFormatter.formatURLPref("privacy.trackingprotection.introURL") +
|
||||
"#step2";
|
||||
"?step=2&newtab=true";
|
||||
switchToTabHavingURI(nextURL, true, {
|
||||
// Ignore the fragment in case the intro is shown on the tour page
|
||||
// (e.g. if the user manually visited the tour or clicked the link from
|
||||
@ -220,8 +231,9 @@ var TrackingProtection = {
|
||||
UITour.initForBrowser(gBrowser.selectedBrowser, window);
|
||||
UITour.showInfo(window, panelTarget,
|
||||
gNavigatorBundle.getString("trackingProtection.intro.title"),
|
||||
gNavigatorBundle.getFormattedString("trackingProtection.intro.description",
|
||||
gNavigatorBundle.getFormattedString("trackingProtection.intro.description2",
|
||||
[brandShortName]),
|
||||
undefined, buttons);
|
||||
undefined, buttons,
|
||||
{ closeButtonCallback: () => this.dontShowIntroPanelAgain() });
|
||||
}),
|
||||
};
|
||||
|
@ -7882,6 +7882,11 @@ var AboutPrivateBrowsingListener = {
|
||||
const PREF = "privacy.trackingprotection.pbmode.enabled";
|
||||
Services.prefs.setBoolPref(PREF, !Services.prefs.getBoolPref(PREF));
|
||||
});
|
||||
window.messageManager.addMessageListener(
|
||||
"AboutPrivateBrowsing:DontShowIntroPanelAgain",
|
||||
msg => {
|
||||
TrackingProtection.dontShowIntroPanelAgain();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -229,6 +229,8 @@ var AboutPrivateBrowsingListener = {
|
||||
false, true);
|
||||
chromeGlobal.addEventListener("AboutPrivateBrowsingToggleTrackingProtection", this,
|
||||
false, true);
|
||||
chromeGlobal.addEventListener("AboutPrivateBrowsingDontShowIntroPanelAgain", this,
|
||||
false, true);
|
||||
},
|
||||
|
||||
get isAboutPrivateBrowsing() {
|
||||
@ -246,6 +248,9 @@ var AboutPrivateBrowsingListener = {
|
||||
case "AboutPrivateBrowsingToggleTrackingProtection":
|
||||
sendAsyncMessage("AboutPrivateBrowsing:ToggleTrackingProtection");
|
||||
break;
|
||||
case "AboutPrivateBrowsingDontShowIntroPanelAgain":
|
||||
sendAsyncMessage("AboutPrivateBrowsing:DontShowIntroPanelAgain");
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -57,6 +57,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
.addEventListener("click", toggleTrackingProtection);
|
||||
document.getElementById("disableTrackingProtection")
|
||||
.addEventListener("click", toggleTrackingProtection);
|
||||
document.getElementById("startTour")
|
||||
.addEventListener("click", dontShowIntroPanelAgain);
|
||||
|
||||
let formatURLPref = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
|
||||
.getService(Ci.nsIURLFormatter).formatURLPref;
|
||||
@ -81,3 +83,10 @@ function toggleTrackingProtection() {
|
||||
new CustomEvent("AboutPrivateBrowsingToggleTrackingProtection",
|
||||
{bubbles:true}));
|
||||
}
|
||||
|
||||
function dontShowIntroPanelAgain() {
|
||||
// Ask chrome to disable the doorhanger
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("AboutPrivateBrowsingDontShowIntroPanelAgain",
|
||||
{bubbles:true}));
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ add_task(function* test_trackingPages() {
|
||||
is(Services.prefs.getIntPref(PREF_INTRO_COUNT), TrackingProtection.MAX_INTROS, "Check intro count increased");
|
||||
|
||||
let step2URL = Services.urlFormatter.formatURLPref("privacy.trackingprotection.introURL") +
|
||||
"#step2";
|
||||
"?step=2&newtab=true";
|
||||
let buttons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
info("Click the step text and nothing should happen");
|
||||
|
@ -332,8 +332,10 @@ identity.identified.state_and_country=%S, %S
|
||||
identity.unknown.tooltip=This website does not supply identity information.
|
||||
|
||||
trackingProtection.intro.title=How Tracking Protection works
|
||||
# LOCALIZATION NOTE (trackingProtection.intro.description): %S is brandShortName
|
||||
trackingProtection.intro.description=When the shield is visible, that means Firefox is actively blocking content that tracks you.
|
||||
# LOCALIZATION NOTE (trackingProtection.intro.description2):
|
||||
# %S is brandShortName. This string should match the one from Step 1 of the tour
|
||||
# when it starts from the button shown when a new private window is opened.
|
||||
trackingProtection.intro.description2=When you see the shield, %S is blocking some parts of the page that could track your browsing activity.
|
||||
# LOCALIZATION NOTE (trackingProtection.intro.step1of3): Indicates that the intro panel is step one of three in a tour.
|
||||
trackingProtection.intro.step1of3=1 of 3
|
||||
trackingProtection.intro.nextButton.label=Next
|
||||
|
@ -64,12 +64,6 @@
|
||||
z-index: 2; /* navbar is at 1 */
|
||||
}
|
||||
|
||||
@media (-moz-mac-yosemite-theme) {
|
||||
#navigator-toolbox::after {
|
||||
background-image: linear-gradient(to top, hsla(0,0%,0%,.1), hsla(0,0%,0%,.1) 1px, hsla(0,0%,100%,0) 1px, hsla(0,0%,100%,0) 2px, transparent 3px);
|
||||
}
|
||||
}
|
||||
|
||||
#navigator-toolbox toolbarbutton:-moz-lwtheme {
|
||||
color: inherit;
|
||||
text-shadow: inherit;
|
||||
@ -156,10 +150,6 @@ toolbarseparator {
|
||||
#navigator-toolbox > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#navigator-toolbox > toolbar:-moz-window-inactive:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) {
|
||||
background-color: hsl(0,0%,95%);
|
||||
}
|
||||
}
|
||||
|
||||
#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar):not(#addon-bar) {
|
||||
@ -202,10 +192,6 @@ toolbarseparator {
|
||||
#nav-bar {
|
||||
background: linear-gradient(hsl(0,0%,93%), hsl(0,0%,83%));
|
||||
}
|
||||
|
||||
#nav-bar:-moz-window-inactive {
|
||||
background: linear-gradient(hsl(0,0%,97%), hsl(0,0%,95%));
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw the bottom border of the tabs toolbar when it's not using
|
||||
@ -232,10 +218,6 @@ toolbarseparator {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#main-window[tabsintitlebar] #TabsToolbar:not([collapsed="true"]) + #nav-bar:-moz-window-inactive:not(:-moz-lwtheme) {
|
||||
border-top-color: hsla(0,0%,0%,.05);
|
||||
}
|
||||
}
|
||||
|
||||
#nav-bar-customization-target {
|
||||
@ -2490,54 +2472,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-mac-yosemite-theme) {
|
||||
.tab-background-middle[visuallyselected=true]:-moz-window-inactive {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-active-middle-inactive.png),
|
||||
@fgTabTextureYosemiteInactive@,
|
||||
none;
|
||||
}
|
||||
|
||||
.tab-background-start[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-stroke-start-inactive.png);
|
||||
}
|
||||
|
||||
.tab-background-end[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-stroke-end-inactive.png);
|
||||
}
|
||||
|
||||
.tab-background-start[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
|
||||
.tab-background-end[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-selected-start-inactive.svg);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.tab-background-end[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
|
||||
.tab-background-start[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-selected-end-inactive.svg);
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.tab-background-middle[visuallyselected=true]:-moz-window-inactive {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-active-middle-inactive@2x.png),
|
||||
@fgTabTextureYosemiteInactive@,
|
||||
none;
|
||||
}
|
||||
|
||||
.tab-background-start[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-end[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-stroke-start-inactive@2x.png);
|
||||
}
|
||||
|
||||
.tab-background-end[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(ltr)::after,
|
||||
.tab-background-start[visuallyselected=true]:-moz-window-inactive:-moz-locale-dir(rtl)::after {
|
||||
background-image: url(chrome://browser/skin/yosemite/tab-stroke-end-inactive@2x.png);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([visuallyselected="true"]) {
|
||||
opacity: .9;
|
||||
}
|
||||
|
@ -238,14 +238,6 @@ browser.jar:
|
||||
skin/classic/browser/yosemite/reload-stop-go@2x.png (reload-stop-go-yosemite@2x.png)
|
||||
skin/classic/browser/yosemite/sync-horizontalbar.png (sync-horizontalbar-yosemite.png)
|
||||
skin/classic/browser/yosemite/sync-horizontalbar@2x.png (sync-horizontalbar-yosemite@2x.png)
|
||||
skin/classic/browser/yosemite/tab-selected-end-inactive.svg (tabbrowser/tab-selected-end-yosemite-inactive.svg)
|
||||
skin/classic/browser/yosemite/tab-selected-start-inactive.svg (tabbrowser/tab-selected-start-yosemite-inactive.svg)
|
||||
skin/classic/browser/yosemite/tab-active-middle-inactive.png (tabbrowser/tab-active-middle-yosemite-inactive.png)
|
||||
skin/classic/browser/yosemite/tab-active-middle-inactive@2x.png (tabbrowser/tab-active-middle-yosemite-inactive@2x.png)
|
||||
skin/classic/browser/yosemite/tab-stroke-end-inactive.png (tabbrowser/tab-stroke-end-yosemite-inactive.png)
|
||||
skin/classic/browser/yosemite/tab-stroke-end-inactive@2x.png (tabbrowser/tab-stroke-end-yosemite-inactive@2x.png)
|
||||
skin/classic/browser/yosemite/tab-stroke-start-inactive.png (tabbrowser/tab-stroke-start-yosemite-inactive.png)
|
||||
skin/classic/browser/yosemite/tab-stroke-start-inactive@2x.png (tabbrowser/tab-stroke-start-yosemite-inactive@2x.png)
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
|
||||
#endif
|
||||
@ -274,5 +266,5 @@ browser.jar:
|
||||
% override chrome://browser/skin/preferences/checkbox@2x.png chrome://browser/skin/yosemite/preferences/checkbox@2x.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/reload-stop-go.png chrome://browser/skin/yosemite/reload-stop-go.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/reload-stop-go@2x.png chrome://browser/skin/yosemite/reload-stop-go@2x.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/sync-horizontalbar.png chrome://browser/skin/yosemite/sync-horizontalbar.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/sync-horizontalbar@2x.png chrome://browser/skin/yosemite/sync-horizontalbar@2x.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/sync-horizontalbar.png chrome://browser/skin/yosemite/sync-horizontalbar.png os=Darwin osversion>=10.10
|
||||
% override chrome://browser/skin/sync-horizontalbar@2x.png chrome://browser/skin/yosemite/sync-horizontalbar@2x.png os=Darwin osversion>=10.10
|
||||
|
@ -4,7 +4,6 @@
|
||||
%filter substitution
|
||||
|
||||
%define fgTabTexture linear-gradient(transparent 2px, hsla(0,0%,100%,.6) 2px, hsla(0,0%,100%,.6) 3px, hsl(0,0%,99%) 3px, hsl(0,0%,93%))
|
||||
%define fgTabTextureYosemiteInactive linear-gradient(transparent 2px, hsl(0,0%,99%) 2px, hsl(0,0%,97%))
|
||||
%define toolbarColorLWT rgba(253,253,253,0.45)
|
||||
%define fgTabTextureLWT linear-gradient(transparent 2px, rgba(254,254,254,.72) 2px, @toolbarColorLWT@)
|
||||
%define fgTabBackgroundColor transparent
|
||||
|
Before Width: | Height: | Size: 78 B |
Before Width: | Height: | Size: 89 B |
@ -1,28 +0,0 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30px" height="31px" preserveAspectRatio="none">
|
||||
<defs>
|
||||
<style>
|
||||
#tab-background-fill {
|
||||
background-color: transparent;
|
||||
background-image: linear-gradient(transparent, transparent 2px, hsl(0,0%,99%) 2px, hsl(0,0%,97%));
|
||||
background-repeat: no-repeat;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<clipPath id="tab-curve-clip-path-end" clipPathUnits="objectBoundingBox">
|
||||
<path d="m 0,0.0625 -0.05,0 0,0.938 1,0 0,-0.028 C 0.67917542,0.95840561 0.56569036,0.81970962 0.51599998,0.5625 0.48279998,0.3905 0.465,0.0659 0,0.0625 z"/>
|
||||
</clipPath>
|
||||
|
||||
<clipPath id="tab-hover-clip-path" clipPathUnits="objectBoundingBox">
|
||||
<path d="M 0,0.2 0,1 1,1, 1,0.2 z"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<foreignObject width="30" height="31" clip-path="url(#tab-curve-clip-path-end)">
|
||||
<div id="tab-background-fill" xmlns="http://www.w3.org/1999/xhtml"></div>
|
||||
</foreignObject>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,28 +0,0 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30px" height="31px" preserveAspectRatio="none">
|
||||
<defs>
|
||||
<style>
|
||||
#tab-background-fill {
|
||||
background-color: transparent;
|
||||
background-image: linear-gradient(transparent, transparent 2px, hsl(0,0%,99%) 2px, hsl(0,0%,97%));
|
||||
background-repeat: no-repeat;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<clipPath id="tab-curve-clip-path-start" clipPathUnits="objectBoundingBox">
|
||||
<path d="m 1,0.0625 0.05,0 0,0.938 -1,0 0,-0.028 C 0.32082458,0.95840561 0.4353096,0.81970962 0.48499998,0.5625 0.51819998,0.3905 0.535,0.0659 1,0.0625 z"/>
|
||||
</clipPath>
|
||||
|
||||
<clipPath id="tab-hover-clip-path" clipPathUnits="objectBoundingBox">
|
||||
<path d="M 0,0.2 0,1 1,1, 1,0.2 z"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<foreignObject width="30" height="31" clip-path="url(#tab-curve-clip-path-start)">
|
||||
<div id="tab-background-fill" xmlns="http://www.w3.org/1999/xhtml"></div>
|
||||
</foreignObject>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 339 B |
Before Width: | Height: | Size: 718 B |
Before Width: | Height: | Size: 339 B |
Before Width: | Height: | Size: 716 B |
@ -49,11 +49,24 @@ add_task(function *() {
|
||||
|
||||
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
|
||||
|
||||
// XXX: race, the WorkerDebugger is ready whereas ServiceWorkerInfo
|
||||
// doesn't has the worker registered yet on its side
|
||||
// Ensure that the registration resolved before trying to connect to the sw
|
||||
let frameScript = function () {
|
||||
// Retrieve the `sw` promise created in the html page
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function (registration) {
|
||||
sendAsyncMessage("sw-registered");
|
||||
});
|
||||
};
|
||||
let mm = swTab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
yield new Promise(done => {
|
||||
require("sdk/timers").setTimeout(done, 250);
|
||||
mm.addMessageListener("sw-registered", function listener() {
|
||||
mm.removeMessageListener("sw-registered", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
ok(true, "Service worker registration resolved");
|
||||
|
||||
// Retrieve the DEBUG button for the worker
|
||||
let names = [...document.querySelectorAll("#service-workers .target-name")];
|
||||
@ -93,7 +106,7 @@ add_task(function *() {
|
||||
|
||||
// Finally, unregister the service worker itself
|
||||
// Use message manager to work with e10s
|
||||
let frameScript = function () {
|
||||
frameScript = function () {
|
||||
// Retrieve the `sw` promise created in the html page
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function (registration) {
|
||||
@ -105,7 +118,7 @@ add_task(function *() {
|
||||
});
|
||||
});
|
||||
};
|
||||
let mm = swTab.linkedBrowser.messageManager;
|
||||
mm = swTab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
yield new Promise(done => {
|
||||
|
@ -108,8 +108,9 @@ OptionsPanel.prototype = {
|
||||
this.setupToolsList();
|
||||
this.setupToolbarButtonsList();
|
||||
this.setupThemeList();
|
||||
this.populatePreferences();
|
||||
this.updateDefaultTheme();
|
||||
}).then(() => {
|
||||
return this.populatePreferences();
|
||||
}).then(() => {
|
||||
this.isReady = true;
|
||||
this.emit("ready");
|
||||
@ -315,7 +316,7 @@ OptionsPanel.prototype = {
|
||||
}
|
||||
|
||||
if (this.target.activeTab) {
|
||||
this.target.client.attachTab(this.target.activeTab._actor, (response) => {
|
||||
return this.target.client.attachTab(this.target.activeTab._actor).then(([response,client]) => {
|
||||
this._origJavascriptEnabled = !response.javascriptEnabled;
|
||||
this.disableJSNode.checked = this._origJavascriptEnabled;
|
||||
this.disableJSNode.addEventListener("click", this._disableJSClicked, false);
|
||||
|
@ -50,5 +50,5 @@ function* testColorPickerAppearsOnColorSwatchClick(view, swatch) {
|
||||
ok(!inplaceEditor(swatch.parentNode),
|
||||
"The inplace editor wasn't shown as a result of the color swatch click");
|
||||
|
||||
yield hideTooltipAndWaitForRuleviewChanged(cPicker, view);
|
||||
yield hideTooltipAndWaitForRuleViewChanged(cPicker, view);
|
||||
}
|
||||
|
@ -72,5 +72,5 @@ function* testPickingNewColor(view) {
|
||||
"rgb(0, 0, 0) 100%)",
|
||||
"The gradient has been updated correctly");
|
||||
|
||||
yield hideTooltipAndWaitForRuleviewChanged(cPicker, view);
|
||||
yield hideTooltipAndWaitForRuleViewChanged(cPicker, view);
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ function* testComplexMultipleColorChanges(inspector, ruleView) {
|
||||
}
|
||||
|
||||
info("Closing the color picker");
|
||||
yield hideTooltipAndWaitForRuleviewChanged(picker.tooltip, ruleView);
|
||||
yield hideTooltipAndWaitForRuleViewChanged(picker.tooltip, ruleView);
|
||||
}
|
||||
|
||||
function* testOverriddenMultipleColorChanges(inspector, ruleView) {
|
||||
|
@ -66,5 +66,5 @@ function* testAppears(view, swatch) {
|
||||
ok(true, "The cubic-bezier tooltip was shown on click of the cibuc swatch");
|
||||
ok(!inplaceEditor(swatch.parentNode),
|
||||
"The inplace editor wasn't shown as a result of the cibuc swatch click");
|
||||
yield hideTooltipAndWaitForRuleviewChanged(bezier, view);
|
||||
yield hideTooltipAndWaitForRuleViewChanged(bezier, view);
|
||||
}
|
||||
|
@ -29,5 +29,5 @@ add_task(function*() {
|
||||
"The inplace editor wasn't shown as a result of the filter swatch click");
|
||||
|
||||
yield filterTooltip.widget;
|
||||
yield hideTooltipAndWaitForRuleviewChanged(filterTooltip, view);
|
||||
yield hideTooltipAndWaitForRuleViewChanged(filterTooltip, view);
|
||||
});
|
||||
|
@ -13,16 +13,18 @@ add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("div", inspector);
|
||||
yield testCreateNewMultiDuplicates(inspector, view);
|
||||
});
|
||||
|
||||
function* testCreateNewMultiDuplicates(inspector, view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
// Note that we wait for a markup mutation here because this new rule will end
|
||||
// up creating a style attribute on the node shown in the markup-view.
|
||||
// (we also wait for the rule-view to refresh).
|
||||
let onMutation = inspector.once("markupmutation");
|
||||
let onRuleViewChanged = view.once("ruleview-changed");
|
||||
yield createNewRuleViewProperty(ruleEditor,
|
||||
"color:red;color:orange;color:yellow;color:green;color:blue;color:indigo;" +
|
||||
"color:violet;");
|
||||
yield onMutation;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
is(ruleEditor.rule.textProps.length, 7,
|
||||
"Should have created new text properties.");
|
||||
@ -63,4 +65,4 @@ function* testCreateNewMultiDuplicates(inspector, view) {
|
||||
"Should have correct property name");
|
||||
is(ruleEditor.rule.textProps[6].value, "violet",
|
||||
"Should have correct property value");
|
||||
}
|
||||
});
|
||||
|
@ -13,15 +13,17 @@ add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("div", inspector);
|
||||
yield testCreateNewMultiPriority(inspector, view);
|
||||
});
|
||||
|
||||
function* testCreateNewMultiPriority(inspector, view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
// Note that we wait for a markup mutation here because this new rule will end
|
||||
// up creating a style attribute on the node shown in the markup-view.
|
||||
// (we also wait for the rule-view to refresh).
|
||||
let onMutation = inspector.once("markupmutation");
|
||||
let onRuleViewChanged = view.once("ruleview-changed");
|
||||
yield createNewRuleViewProperty(ruleEditor,
|
||||
"color:red;width:100px;height: 100px;");
|
||||
yield onMutation;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
is(ruleEditor.rule.textProps.length, 3,
|
||||
"Should have created new text properties.");
|
||||
@ -42,4 +44,4 @@ function* testCreateNewMultiPriority(inspector, view) {
|
||||
"Should have correct property name");
|
||||
is(ruleEditor.rule.textProps[2].value, "100px",
|
||||
"Should have correct property value");
|
||||
}
|
||||
});
|
||||
|
@ -13,14 +13,16 @@ add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("div", inspector);
|
||||
yield testCreateNewMultiPartialUnfinished(inspector, view);
|
||||
});
|
||||
|
||||
function* testCreateNewMultiPartialUnfinished(inspector, view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
// Note that we wait for a markup mutation here because this new rule will end
|
||||
// up creating a style attribute on the node shown in the markup-view.
|
||||
// (we also wait for the rule-view to refresh).
|
||||
let onMutation = inspector.once("markupmutation");
|
||||
let onRuleViewChanged = view.once("ruleview-changed");
|
||||
yield createNewRuleViewProperty(ruleEditor, "width: 100px; heig");
|
||||
yield onMutation;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
is(ruleEditor.rule.textProps.length, 2,
|
||||
"Should have created a new text property.");
|
||||
@ -29,10 +31,12 @@ function* testCreateNewMultiPartialUnfinished(inspector, view) {
|
||||
|
||||
// Value is focused, lets add multiple rules here and make sure they get added
|
||||
onMutation = inspector.once("markupmutation");
|
||||
onRuleViewChanged = view.once("ruleview-changed");
|
||||
let valueEditor = ruleEditor.propertyList.children[1].querySelector("input");
|
||||
valueEditor.value = "10px;background:orangered;color: black;";
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow);
|
||||
yield onMutation;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
is(ruleEditor.rule.textProps.length, 4,
|
||||
"Should have added the changed value.");
|
||||
@ -58,4 +62,4 @@ function* testCreateNewMultiPartialUnfinished(inspector, view) {
|
||||
"Should have correct property name");
|
||||
is(ruleEditor.rule.textProps[3].value, "black",
|
||||
"Should have correct property value");
|
||||
}
|
||||
});
|
||||
|
@ -13,16 +13,18 @@ add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("div", inspector);
|
||||
yield testCreateNewMulti(inspector, view);
|
||||
});
|
||||
|
||||
function* testCreateNewMulti(inspector, view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
// Note that we wait for a markup mutation here because this new rule will end
|
||||
// up creating a style attribute on the node shown in the markup-view.
|
||||
// (we also wait for the rule-view to refresh).
|
||||
let onMutation = inspector.once("markupmutation");
|
||||
let onRuleViewChanged = view.once("ruleview-changed");
|
||||
yield createNewRuleViewProperty(ruleEditor,
|
||||
"color:blue;background : orange ; text-align:center; " +
|
||||
"border-color: green;");
|
||||
yield onMutation;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
is(ruleEditor.rule.textProps.length, 4,
|
||||
"Should have created a new text property.");
|
||||
@ -48,4 +50,4 @@ function* testCreateNewMulti(inspector, view) {
|
||||
"Should have correct property name");
|
||||
is(ruleEditor.rule.textProps[3].value, "green",
|
||||
"Should have correct property value");
|
||||
}
|
||||
});
|
||||
|
@ -23,16 +23,15 @@ add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#testid", inspector);
|
||||
yield testModifyPropertyNameFilter(inspector, view);
|
||||
});
|
||||
|
||||
function* testModifyPropertyNameFilter(inspector, view) {
|
||||
info("Enter the test value in the search filter");
|
||||
yield setSearchFilter(view, SEARCH);
|
||||
|
||||
info("Focus the width property name");
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let rule = ruleEditor.rule;
|
||||
let propEditor = rule.textProps[0].editor;
|
||||
let editor = yield focusEditableField(view, propEditor.nameSpan);
|
||||
yield focusEditableField(view, propEditor.nameSpan);
|
||||
|
||||
info("Check that the correct rules are visible");
|
||||
is(view.element.children.length, 2, "Should have 2 rules.");
|
||||
@ -43,13 +42,21 @@ function* testModifyPropertyNameFilter(inspector, view) {
|
||||
.contains("ruleview-highlight"),
|
||||
"height text property is correctly highlighted.");
|
||||
|
||||
let onBlur = once(editor.input, "blur");
|
||||
let onModification = rule._applyingModifications;
|
||||
info("Change the width property to margin-left");
|
||||
EventUtils.sendString("margin-left", view.styleWindow);
|
||||
|
||||
info("Submit the change");
|
||||
let onRuleViewChanged = view.once("ruleview-changed");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
yield onBlur;
|
||||
yield onModification;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
ok(propEditor.container.classList.contains("ruleview-highlight"),
|
||||
"margin-left text property is correctly highlighted.");
|
||||
}
|
||||
|
||||
// After pressing return on the property name, the value has been focused
|
||||
// automatically. Blur it now and wait for the rule-view to refresh to avoid
|
||||
// pending requests.
|
||||
onRuleViewChanged = view.once("ruleview-changed");
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||
yield onRuleViewChanged;
|
||||
});
|
||||
|
@ -23,12 +23,11 @@ add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#testid", inspector);
|
||||
yield testModifyPropertyValueFilter(inspector, view);
|
||||
});
|
||||
|
||||
function* testModifyPropertyValueFilter(inspector, view) {
|
||||
info("Enter the test value in the search filter");
|
||||
yield setSearchFilter(view, SEARCH);
|
||||
|
||||
info("Focus the height property value");
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let rule = ruleEditor.rule;
|
||||
let propEditor = rule.textProps[1].editor;
|
||||
@ -43,13 +42,12 @@ function* testModifyPropertyValueFilter(inspector, view) {
|
||||
ok(!propEditor.container.classList.contains("ruleview-highlight"),
|
||||
"height text property is not highlighted.");
|
||||
|
||||
let onBlur = once(editor.input, "blur");
|
||||
let onModification = rule._applyingModifications;
|
||||
info("Change the height property value to 100%");
|
||||
let onRuleViewChanged = view.once("ruleview-changed");
|
||||
EventUtils.sendString("100%", view.styleWindow);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
yield onBlur;
|
||||
yield onModification;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
ok(propEditor.container.classList.contains("ruleview-highlight"),
|
||||
"height text property is correctly highlighted.");
|
||||
}
|
||||
});
|
||||
|
@ -23,12 +23,11 @@ add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {inspector, view} = yield openRuleView();
|
||||
yield selectNode("#testid", inspector);
|
||||
yield testNewPropertyFilter(inspector, view);
|
||||
});
|
||||
|
||||
function* testNewPropertyFilter(inspector, view) {
|
||||
info("Enter the test value in the search filter");
|
||||
yield setSearchFilter(view, SEARCH);
|
||||
|
||||
info("Start entering a new property in the rule");
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let rule = ruleEditor.rule;
|
||||
let editor = yield focusEditableField(view, ruleEditor.closeBrace);
|
||||
@ -46,27 +45,28 @@ function* testNewPropertyFilter(inspector, view) {
|
||||
info("Test creating a new property");
|
||||
|
||||
info("Entering margin-left in the property name editor");
|
||||
// Changing the value doesn't cause a rule-view refresh, no need to wait for
|
||||
// ruleview-changed here.
|
||||
editor.input.value = "margin-left";
|
||||
|
||||
info("Pressing return to commit and focus the new value field");
|
||||
let onValueFocus = once(ruleEditor.element, "focus", true);
|
||||
let onModifications = ruleEditor.rule._applyingModifications;
|
||||
let onRuleViewChanged = view.once("ruleview-changed");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow);
|
||||
yield onValueFocus;
|
||||
yield onModifications;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
// Getting the new value editor after focus
|
||||
editor = inplaceEditor(view.styleDocument.activeElement);
|
||||
let propEditor = ruleEditor.rule.textProps[2].editor;
|
||||
|
||||
info("Entering a value and bluring the field to expect a rule change");
|
||||
onRuleViewChanged = view.once("ruleview-changed");
|
||||
editor.input.value = "100%";
|
||||
let onBlur = once(editor.input, "blur");
|
||||
onModifications = ruleEditor.rule._applyingModifications;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
onRuleViewChanged = view.once("ruleview-changed");
|
||||
editor.input.blur();
|
||||
yield onBlur;
|
||||
yield onModifications;
|
||||
yield onRuleViewChanged;
|
||||
|
||||
ok(propEditor.container.classList.contains("ruleview-highlight"),
|
||||
"margin-left text property is correctly highlighted.");
|
||||
}
|
||||
});
|
||||
|
@ -289,7 +289,7 @@ function assertHoverTooltipOn(tooltip, element) {
|
||||
* @param {Tooltip} tooltip
|
||||
* @param {CSSRuleView} view
|
||||
*/
|
||||
function* hideTooltipAndWaitForRuleviewChanged(tooltip, view) {
|
||||
function* hideTooltipAndWaitForRuleViewChanged(tooltip, view) {
|
||||
let onModified = view.once("ruleview-changed");
|
||||
tooltip.hide();
|
||||
yield onModified;
|
||||
|
@ -279,8 +279,8 @@ devtools.jar:
|
||||
skin/images/dock-bottom-minimize@2x.png (themes/images/dock-bottom-minimize@2x.png)
|
||||
skin/images/dock-bottom-maximize@2x.png (themes/images/dock-bottom-maximize@2x.png)
|
||||
skin/images/dock-side@2x.png (themes/images/dock-side@2x.png)
|
||||
* skin/floating-scrollbars.css (themes/floating-scrollbars.css)
|
||||
skin/floating-scrollbars-light.css (themes/floating-scrollbars-light.css)
|
||||
skin/floating-scrollbars-dark-theme.css (themes/floating-scrollbars-dark-theme.css)
|
||||
skin/floating-scrollbars-responsive-design.css (themes/floating-scrollbars-responsive-design.css)
|
||||
skin/inspector.css (themes/inspector.css)
|
||||
skin/images/profiler-stopwatch.svg (themes/images/profiler-stopwatch.svg)
|
||||
skin/images/emojis/emoji-command-pick.svg (themes/images/emojis/emoji-command-pick.svg)
|
||||
|
@ -54,6 +54,7 @@ tree.labels.cookies=Cookies
|
||||
tree.labels.localStorage=Local Storage
|
||||
tree.labels.sessionStorage=Session Storage
|
||||
tree.labels.indexedDB=Indexed DB
|
||||
tree.labels.Cache=Cache Storage
|
||||
|
||||
# LOCALIZATION NOTE (table.headers.*.*):
|
||||
# These strings are the header names of the columns in the Storage Table for
|
||||
@ -84,6 +85,9 @@ table.headers.localStorage.value=Value
|
||||
table.headers.sessionStorage.name=Key
|
||||
table.headers.sessionStorage.value=Value
|
||||
|
||||
table.headers.Cache.url=URL
|
||||
table.headers.Cache.status=Status
|
||||
|
||||
table.headers.indexedDB.name=Key
|
||||
table.headers.indexedDB.db=Database Name
|
||||
table.headers.indexedDB.objectStore=Object Store Name
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
const gDeviceSizeWasPageSize = docShell.deviceSizeIsPageSize;
|
||||
const gFloatingScrollbarsStylesheet = Services.io.newURI("chrome://devtools/skin/floating-scrollbars.css", null, null);
|
||||
const gFloatingScrollbarsStylesheet = Services.io.newURI("chrome://devtools/skin/floating-scrollbars-responsive-design.css", null, null);
|
||||
var gRequiresFloatingScrollbars;
|
||||
|
||||
var active = false;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
(function() {
|
||||
const SCROLLBARS_URL = "chrome://devtools/skin/floating-scrollbars-light.css";
|
||||
const SCROLLBARS_URL = "chrome://devtools/skin/floating-scrollbars-dark-theme.css";
|
||||
let documentElement = document.documentElement;
|
||||
|
||||
let os;
|
||||
|
@ -57,7 +57,10 @@ StoragePanel.prototype = {
|
||||
this.emit("ready");
|
||||
|
||||
return this;
|
||||
}).catch(this.destroy);
|
||||
}).catch(e => {
|
||||
console.log("error while opening storage panel", e);
|
||||
this.destroy();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -61,6 +61,9 @@ const testCases = [
|
||||
[6, 7]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
|
||||
[16]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -14,6 +14,8 @@ const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
|
||||
const STORAGE_PREF = "devtools.storage.enabled";
|
||||
const DUMPEMIT_PREF = "devtools.dump.emit";
|
||||
const DEBUGGERLOG_PREF = "devtools.debugger.log";
|
||||
// Allows Cache API to be working on usage `http` test page
|
||||
const CACHES_ON_HTTP_PREF = "dom.caches.testing.enabled";
|
||||
const PATH = "browser/devtools/client/storage/test/";
|
||||
const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
|
||||
const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
|
||||
@ -27,6 +29,7 @@ var gToolbox, gPanelWindow, gWindow, gUI;
|
||||
// Services.prefs.setBoolPref(DEBUGGERLOG_PREF, true);
|
||||
|
||||
Services.prefs.setBoolPref(STORAGE_PREF, true);
|
||||
Services.prefs.setBoolPref(CACHES_ON_HTTP_PREF, true);
|
||||
DevToolsUtils.testing = true;
|
||||
registerCleanupFunction(() => {
|
||||
gToolbox = gPanelWindow = gWindow = gUI = null;
|
||||
@ -34,6 +37,7 @@ registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref(SPLIT_CONSOLE_PREF);
|
||||
Services.prefs.clearUserPref(DUMPEMIT_PREF);
|
||||
Services.prefs.clearUserPref(DEBUGGERLOG_PREF);
|
||||
Services.prefs.clearUserPref(CACHES_ON_HTTP_PREF);
|
||||
DevToolsUtils.testing = false;
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
@ -82,35 +86,20 @@ function addTab(url) {
|
||||
* @return {Promise} A promise that resolves after storage inspector is ready
|
||||
*/
|
||||
function* openTabAndSetupStorage(url) {
|
||||
/**
|
||||
* This method iterates over iframes in a window and setups the indexed db
|
||||
* required for this test.
|
||||
*/
|
||||
let setupIDBInFrames = (w, i, c) => {
|
||||
if (w[i] && w[i].idbGenerator) {
|
||||
w[i].setupIDB = w[i].idbGenerator(() => setupIDBInFrames(w, i + 1, c));
|
||||
w[i].setupIDB.next();
|
||||
} else if (w[i] && w[i + 1]) {
|
||||
setupIDBInFrames(w, i + 1, c);
|
||||
} else {
|
||||
c();
|
||||
}
|
||||
};
|
||||
|
||||
let content = yield addTab(url);
|
||||
|
||||
let def = promise.defer();
|
||||
// Setup the indexed db in main window.
|
||||
gWindow = content.wrappedJSObject;
|
||||
if (gWindow.idbGenerator) {
|
||||
gWindow.setupIDB = gWindow.idbGenerator(() => {
|
||||
setupIDBInFrames(gWindow, 0, () => {
|
||||
def.resolve();
|
||||
});
|
||||
});
|
||||
gWindow.setupIDB.next();
|
||||
yield def.promise;
|
||||
|
||||
// Setup the async storages in main window and for all its iframes
|
||||
let callSetup = function*(win) {
|
||||
if (typeof(win.setup) == "function") {
|
||||
yield win.setup();
|
||||
}
|
||||
for(var i = 0; i < win.frames.length; i++) {
|
||||
yield callSetup(win.frames[i]);
|
||||
}
|
||||
}
|
||||
yield callSetup(gWindow);
|
||||
|
||||
// open storage inspector
|
||||
return yield openStoragePanel();
|
||||
@ -498,6 +487,7 @@ function* selectTreeItem(ids) {
|
||||
|
||||
let selector = "[data-id='" + JSON.stringify(ids) + "'] > .tree-widget-item";
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, "tree item found with ids " + JSON.stringify(ids));
|
||||
|
||||
let updated = gUI.once("store-objects-updated");
|
||||
|
||||
@ -514,6 +504,7 @@ function* selectTreeItem(ids) {
|
||||
function* selectTableItem(id) {
|
||||
let selector = ".table-widget-cell[data-id='" + id + "']";
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, "table item found with ids " + id);
|
||||
|
||||
yield click(target);
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
@ -34,53 +34,63 @@ sessionStorage.setItem("ss2", "This~is~another~array");
|
||||
sessionStorage.setItem("ss3", "this#is~an#object~foo#bar");
|
||||
console.log("added cookies and stuff from main page");
|
||||
|
||||
function success(event) {
|
||||
setupIDB.next(event);
|
||||
}
|
||||
|
||||
window.idbGenerator = function*(callback) {
|
||||
let idbGenerator = function*() {
|
||||
let request = indexedDB.open("idb1", 1);
|
||||
request.onupgradeneeded = success;
|
||||
request.onsuccess = success;
|
||||
request.onerror = function() {
|
||||
throw new Error("error opening db connection");
|
||||
};
|
||||
let event = yield undefined;
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
|
||||
store1.createIndex("name", "name", { unique: false });
|
||||
store1.createIndex("email", "email", { unique: true });
|
||||
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
|
||||
let db = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
|
||||
store1.createIndex("name", "name", { unique: false });
|
||||
store1.createIndex("email", "email", { unique: true });
|
||||
db.createObjectStore("obj2", { keyPath: "id2" });
|
||||
store1.transaction.oncomplete = () => {
|
||||
done(db);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
store1.add({id: 1, name: "foo", email: "foo@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
// Prevents AbortError
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
let transaction = db.transaction(["obj1", "obj2"], "readwrite");
|
||||
let store1 = transaction.objectStore("obj1");
|
||||
let store2 = transaction.objectStore("obj2");
|
||||
|
||||
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
|
||||
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
|
||||
store2.add({
|
||||
id2: 1,
|
||||
name: "foo",
|
||||
email: "foo@bar.com",
|
||||
extra: "baz"}).onsuccess = success;
|
||||
yield undefined;
|
||||
extra: "baz"});
|
||||
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
request = indexedDB.open("idb2", 1);
|
||||
request.onupgradeneeded = success;
|
||||
request.onsuccess = success;
|
||||
event = yield undefined;
|
||||
let db2 = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db2 = event.target.result;
|
||||
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
store3.transaction.oncomplete = () => {
|
||||
done(db2);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
let db2 = event.target.result;
|
||||
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
// Prevents AbortError during close()
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
yield undefined;
|
||||
db2.close();
|
||||
console.log("added cookies and stuff from main page");
|
||||
callback();
|
||||
};
|
||||
|
||||
function deleteDB(dbName) {
|
||||
@ -90,6 +100,10 @@ function deleteDB(dbName) {
|
||||
});
|
||||
}
|
||||
|
||||
window.setup = function*() {
|
||||
yield idbGenerator();
|
||||
};
|
||||
|
||||
window.clear = function*() {
|
||||
document.cookie = "c1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/browser";
|
||||
document.cookie = "cs2=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
|
@ -28,53 +28,66 @@ localStorage.setItem("ls2", "foobar-2");
|
||||
sessionStorage.setItem("ss1", "foobar-3");
|
||||
dump("added cookies and stuff from main page\n");
|
||||
|
||||
function success(event) {
|
||||
setupIDB.next(event);
|
||||
}
|
||||
|
||||
window.idbGenerator = function*(callback) {
|
||||
let idbGenerator = function*() {
|
||||
let request = indexedDB.open("idb1", 1);
|
||||
request.onupgradeneeded = success;
|
||||
request.onsuccess = success;
|
||||
request.onerror = function() {
|
||||
throw new Error("error opening db connection");
|
||||
};
|
||||
let event = yield undefined;
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
|
||||
store1.createIndex("name", "name", { unique: false });
|
||||
store1.createIndex("email", "email", { unique: true });
|
||||
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
|
||||
let db = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
|
||||
store1.createIndex("name", "name", { unique: false });
|
||||
store1.createIndex("email", "email", { unique: true });
|
||||
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
|
||||
store1.transaction.oncomplete = () => {
|
||||
done(db);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
store1.add({id: 1, name: "foo", email: "foo@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
// Prevents AbortError
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
let transaction = db.transaction(["obj1", "obj2"], "readwrite");
|
||||
let store1 = transaction.objectStore("obj1");
|
||||
let store2 = transaction.objectStore("obj2");
|
||||
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
|
||||
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
|
||||
store2.add({
|
||||
id2: 1,
|
||||
name: "foo",
|
||||
email: "foo@bar.com",
|
||||
extra: "baz"}).onsuccess = success;
|
||||
yield undefined;
|
||||
extra: "baz"
|
||||
});
|
||||
// Prevents AbortError during close()
|
||||
yield new Promise(success => {
|
||||
transaction.oncomplete = success;
|
||||
});
|
||||
|
||||
yield undefined;
|
||||
db.close();
|
||||
|
||||
request = indexedDB.open("idb2", 1);
|
||||
request.onupgradeneeded = success;
|
||||
request.onsuccess = success;
|
||||
event = yield undefined;
|
||||
|
||||
let db2 = event.target.result;
|
||||
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
|
||||
yield undefined;
|
||||
let db2 = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db2 = event.target.result;
|
||||
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
store3.transaction.oncomplete = () => {
|
||||
done(db2);
|
||||
}
|
||||
};
|
||||
});
|
||||
// Prevents AbortError during close()
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
db2.close();
|
||||
|
||||
dump("added cookies and stuff from main page\n");
|
||||
callback();
|
||||
};
|
||||
|
||||
function deleteDB(dbName) {
|
||||
@ -84,6 +97,17 @@ function deleteDB(dbName) {
|
||||
});
|
||||
}
|
||||
|
||||
let cacheGenerator = function*() {
|
||||
let cache = yield caches.open("plop");
|
||||
yield cache.add("404_cached_file.js");
|
||||
yield cache.add("browser_storage_basic.js");
|
||||
};
|
||||
|
||||
window.setup = function*() {
|
||||
yield idbGenerator();
|
||||
yield cacheGenerator();
|
||||
};
|
||||
|
||||
window.clear = function*() {
|
||||
document.cookie = "c1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/browser";
|
||||
document.cookie =
|
||||
@ -98,6 +122,8 @@ window.clear = function*() {
|
||||
yield deleteDB("idb1");
|
||||
yield deleteDB("idb2");
|
||||
|
||||
yield caches.delete("plop");
|
||||
|
||||
dump("removed cookies, localStorage, sessionStorage and indexedDB data " +
|
||||
"from " + document.location + "\n");
|
||||
};
|
||||
|
@ -17,41 +17,55 @@ function success(event) {
|
||||
setupIDB.next(event);
|
||||
}
|
||||
|
||||
window.idbGenerator = function*(callback) {
|
||||
let idbGenerator = function*() {
|
||||
let request = indexedDB.open("idb-s1", 1);
|
||||
request.onupgradeneeded = success;
|
||||
request.onsuccess = success;
|
||||
request.onerror = function() {
|
||||
throw new Error("error opening db connection");
|
||||
};
|
||||
let event = yield undefined;
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj-s1", { keyPath: "id" });
|
||||
|
||||
store1.add({id: 6, name: "foo", email: "foo@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
|
||||
yield undefined;
|
||||
let db = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj-s1", { keyPath: "id" });
|
||||
store1.add({id: 6, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"});
|
||||
store1.transaction.oncomplete = () => {
|
||||
done(db);
|
||||
};
|
||||
};
|
||||
});
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
db.close();
|
||||
/*
|
||||
let transaction = db.transaction(["obj-s1"], "readwrite");
|
||||
let store1 = transaction.objectStore("obj-s1");
|
||||
store1.add({id: 6, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"});
|
||||
yield new Promise(success => {
|
||||
transaction.oncomplete = success;
|
||||
});
|
||||
*/
|
||||
|
||||
request = indexedDB.open("idb-s2", 1);
|
||||
request.onupgradeneeded = success;
|
||||
request.onsuccess = success;
|
||||
event = yield undefined;
|
||||
let db2 = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db2 = event.target.result;
|
||||
let store3 =
|
||||
db2.createObjectStore("obj-s2", { keyPath: "id3", autoIncrement: true });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
store3.add({id3: 16, name2: "foo", email: "foo@bar.com"});
|
||||
store3.transaction.oncomplete = () => {
|
||||
done(db2);
|
||||
};
|
||||
};
|
||||
});
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
let db2 = event.target.result;
|
||||
let store3 =
|
||||
db2.createObjectStore("obj-s2", { keyPath: "id3", autoIncrement: true });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
store3.add({id3: 16, name2: "foo", email: "foo@bar.com"}).onsuccess = success;
|
||||
yield undefined;
|
||||
|
||||
yield undefined;
|
||||
db2.close();
|
||||
dump("added cookies and stuff from secured iframe\n");
|
||||
callback();
|
||||
};
|
||||
|
||||
function deleteDB(dbName) {
|
||||
@ -61,6 +75,10 @@ function deleteDB(dbName) {
|
||||
});
|
||||
}
|
||||
|
||||
window.setup = function*() {
|
||||
yield idbGenerator();
|
||||
};
|
||||
|
||||
window.clear = function*() {
|
||||
document.cookie = "sc1=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
|
||||
|
||||
|
@ -341,11 +341,16 @@ StorageUI.prototype = {
|
||||
populateStorageTree: function(storageTypes) {
|
||||
this.storageTypes = {};
|
||||
for (let type in storageTypes) {
|
||||
// Ignore `from` field, which is just a protocol.js implementation artifact
|
||||
if (type === "from") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let typeLabel = L10N.getStr("tree.labels." + type);
|
||||
let typeLabel = type;
|
||||
try {
|
||||
typeLabel = L10N.getStr("tree.labels." + type);
|
||||
} catch(e) {
|
||||
console.error("Unable to localize tree label type:" + type);
|
||||
}
|
||||
this.tree.add([{id: type, label: typeLabel, type: "store"}]);
|
||||
if (!storageTypes[type].hosts) {
|
||||
continue;
|
||||
@ -568,7 +573,12 @@ StorageUI.prototype = {
|
||||
if (!uniqueKey) {
|
||||
this.table.uniqueId = uniqueKey = key;
|
||||
}
|
||||
columns[key] = L10N.getStr("table.headers." + type + "." + key);
|
||||
columns[key] = key;
|
||||
try {
|
||||
columns[key] = L10N.getStr("table.headers." + type + "." + key);
|
||||
} catch(e) {
|
||||
console.error("Unable to localize table header type:" + type + " key:" + key);
|
||||
}
|
||||
}
|
||||
this.table.setColumns(columns, null, HIDDEN_COLUMNS);
|
||||
this.shouldResetColumns = false;
|
||||
|
55
devtools/client/themes/floating-scrollbars-dark-theme.css
Normal file
@ -0,0 +1,55 @@
|
||||
@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
xul|scrollbar {
|
||||
-moz-appearance: none !important;
|
||||
position: relative;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
z-index: 2147483647;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
:root[platform="mac"] xul|scrollbar {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Scrollbar code will reset the margin to the correct side depending on
|
||||
where layout actually puts the scrollbar */
|
||||
xul|scrollbar[orient="vertical"] {
|
||||
margin-left: -10px;
|
||||
min-width: 10px;
|
||||
max-width: 10px;
|
||||
}
|
||||
|
||||
xul|scrollbar[orient="horizontal"] {
|
||||
margin-top: -10px;
|
||||
min-height: 10px;
|
||||
max-height: 10px;
|
||||
}
|
||||
|
||||
:root[platform="mac"] xul|slider {
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
|
||||
:root[platform="mac"] xul|thumb {
|
||||
-moz-appearance: none !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
xul|scrollbar xul|thumb {
|
||||
background-color: rgba(170,170,170,0.2) !important;
|
||||
}
|
||||
|
||||
:root[platform="win"] xul|thumb,
|
||||
:root[platform="linux"] xul|thumb {
|
||||
-moz-appearance: none !important;
|
||||
border-width: 0px !important;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
:root[platform="win"] xul|scrollbar xul|scrollbarbutton,
|
||||
:root[platform="linux"] xul|scrollbar xul|scrollbarbutton,
|
||||
:root[platform="win"] xul|scrollbar xul|gripper,
|
||||
:root[platform="linux"] xul|scrollbar xul|gripper {
|
||||
display: none;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
@import url("floating-scrollbars.css");
|
||||
|
||||
scrollbar thumb {
|
||||
background-color: rgba(170,170,170,0.2) !important;
|
||||
}
|
@ -7,9 +7,7 @@ scrollbar {
|
||||
background-image: none;
|
||||
z-index: 2147483647;
|
||||
padding: 2px;
|
||||
%ifdef XP_MACOSX
|
||||
border: 0px solid transparent;
|
||||
%endif
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Scrollbar code will reset the margin to the correct side depending on
|
||||
@ -26,7 +24,6 @@ scrollbar[orient="horizontal"] {
|
||||
max-height: 10px;
|
||||
}
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
slider {
|
||||
-moz-appearance: none !important;
|
||||
}
|
||||
@ -35,15 +32,11 @@ thumb {
|
||||
-moz-appearance: none !important;
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
%else
|
||||
scrollbar thumb {
|
||||
-moz-appearance: none !important;
|
||||
border-width: 0px !important;
|
||||
background-color: rgba(170,170,170,0.2) !important;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
scrollbar scrollbarbutton, scrollbar gripper {
|
||||
|
||||
scrollbar scrollbarbutton,
|
||||
scrollbar gripper {
|
||||
display: none;
|
||||
}
|
||||
%endif
|
@ -922,6 +922,131 @@ StorageActors.createActor({
|
||||
storeObjectType: "storagestoreobject"
|
||||
}, getObjectForLocalOrSessionStorage("sessionStorage"));
|
||||
|
||||
|
||||
let CacheAttributes = [
|
||||
"url",
|
||||
"status",
|
||||
];
|
||||
types.addDictType("cacheobject", {
|
||||
"url": "string",
|
||||
"status": "string"
|
||||
});
|
||||
|
||||
// Array of Cache store objects
|
||||
types.addDictType("cachestoreobject", {
|
||||
total: "number",
|
||||
offset: "number",
|
||||
data: "array:nullable:cacheobject"
|
||||
});
|
||||
|
||||
StorageActors.createActor({
|
||||
typeName: "Cache",
|
||||
storeObjectType: "cachestoreobject"
|
||||
}, {
|
||||
getCachesForHost: Task.async(function*(host) {
|
||||
let uri = Services.io.newURI(host, null, null);
|
||||
let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
|
||||
|
||||
// The first argument tells if you want to get |content| cache or |chrome| cache.
|
||||
// The |content| cache is the cache explicitely named by the web content
|
||||
// (service worker or web page).
|
||||
// The |chrome| cache is the cache implicitely cached by the platform, hosting the
|
||||
// source file of the service worker.
|
||||
let { CacheStorage } = this.storageActor.window;
|
||||
let cache = new CacheStorage("content", principal);
|
||||
return cache;
|
||||
}),
|
||||
|
||||
preListStores: Task.async(function*() {
|
||||
for (let host of this.hosts) {
|
||||
yield this.populateStoresForHost(host);
|
||||
}
|
||||
}),
|
||||
|
||||
form: function(form, detail) {
|
||||
if (detail === "actorid") {
|
||||
return this.actorID;
|
||||
}
|
||||
|
||||
let hosts = {};
|
||||
for (let host of this.hosts) {
|
||||
hosts[host] = this.getNamesForHost(host);
|
||||
}
|
||||
|
||||
return {
|
||||
actor: this.actorID,
|
||||
hosts: hosts
|
||||
};
|
||||
},
|
||||
|
||||
getNamesForHost: function(host) {
|
||||
// UI code expect each name to be a JSON string of an array :/
|
||||
return [...this.hostVsStores.get(host).keys()].map(a => JSON.stringify([a]));
|
||||
},
|
||||
|
||||
getValuesForHost: Task.async(function*(host, name) {
|
||||
if (!name) return [];
|
||||
// UI is weird and expect a JSON stringified array... and pass it back :/
|
||||
name = JSON.parse(name)[0];
|
||||
|
||||
let cache = this.hostVsStores.get(host).get(name);
|
||||
let requests = yield cache.keys();
|
||||
let results = [];
|
||||
for(let request of requests) {
|
||||
let response = yield cache.match(request);
|
||||
// Unwrap the response to get access to all its properties if the
|
||||
// response happen to be 'opaque', when it is a Cross Origin Request.
|
||||
response = response.cloneUnfiltered();
|
||||
results.push(yield this.processEntry(request, response));
|
||||
}
|
||||
return results;
|
||||
}),
|
||||
|
||||
processEntry: Task.async(function*(request, response) {
|
||||
return {
|
||||
url: String(request.url),
|
||||
status: String(response.statusText),
|
||||
};
|
||||
}),
|
||||
|
||||
getHostName: function(location) {
|
||||
if (!location.host) {
|
||||
return location.href;
|
||||
}
|
||||
return location.protocol + "//" + location.host;
|
||||
},
|
||||
|
||||
populateStoresForHost: Task.async(function*(host, window) {
|
||||
let storeMap = new Map();
|
||||
let caches = yield this.getCachesForHost(host);
|
||||
for (let name of (yield caches.keys())) {
|
||||
storeMap.set(name, (yield caches.open(name)));
|
||||
}
|
||||
this.hostVsStores.set(host, storeMap);
|
||||
}),
|
||||
|
||||
/**
|
||||
* This method is overriden and left blank as for Cache Storage, this
|
||||
* operation cannot be performed synchronously. Thus, the preListStores
|
||||
* method exists to do the same task asynchronously.
|
||||
*/
|
||||
populateStoresForHosts: function() {
|
||||
this.hostVsStores = new Map();
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a url, correctly determine its protocol + hostname part.
|
||||
*/
|
||||
getSchemaAndHost: function(url) {
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
return uri.scheme + "://" + uri.hostPort;
|
||||
},
|
||||
|
||||
toStoreObject: function(item) {
|
||||
return item;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Code related to the Indexed DB actor and front
|
||||
*/
|
||||
|
@ -440,7 +440,7 @@ DebuggerClient.prototype = {
|
||||
traits: cachedTab.traits,
|
||||
};
|
||||
DevToolsUtils.executeSoon(() => aOnResponse(cachedResponse, cachedTab));
|
||||
return;
|
||||
return promise.resolve([cachedResponse, cachedTab]);
|
||||
}
|
||||
|
||||
let packet = {
|
||||
@ -461,12 +461,13 @@ DebuggerClient.prototype = {
|
||||
attachWorker: function DC_attachWorker(aWorkerActor, aOnResponse = noop) {
|
||||
let workerClient = this._clients.get(aWorkerActor);
|
||||
if (workerClient !== undefined) {
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({
|
||||
let response = {
|
||||
from: workerClient.actor,
|
||||
type: "attached",
|
||||
url: workerClient.url
|
||||
}, workerClient));
|
||||
return;
|
||||
};
|
||||
DevToolsUtils.executeSoon(() => aOnResponse(response, workerClient));
|
||||
return promise.resolve([response, workerClient]);
|
||||
}
|
||||
|
||||
return this.request({ to: aWorkerActor, type: "attach" }).then(aResponse => {
|
||||
@ -556,8 +557,9 @@ DebuggerClient.prototype = {
|
||||
*/
|
||||
attachThread: function (aThreadActor, aOnResponse = noop, aOptions={}) {
|
||||
if (this._clients.has(aThreadActor)) {
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, this._clients.get(aThreadActor)));
|
||||
return;
|
||||
let client = this._clients.get(aThreadActor);
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, client));
|
||||
return promise.resolve([{}, client]);
|
||||
}
|
||||
|
||||
let packet = {
|
||||
@ -586,8 +588,9 @@ DebuggerClient.prototype = {
|
||||
*/
|
||||
attachTracer: function (aTraceActor, aOnResponse = noop) {
|
||||
if (this._clients.has(aTraceActor)) {
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, this._clients.get(aTraceActor)));
|
||||
return;
|
||||
let client = this._clients.get(aTraceActor);
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, client));
|
||||
return promise.resolve([{}, client]);
|
||||
}
|
||||
|
||||
let packet = {
|
||||
@ -1261,7 +1264,7 @@ TabClient.prototype = {
|
||||
attachThread: function(aOptions={}, aOnResponse = noop) {
|
||||
if (this.thread) {
|
||||
DevToolsUtils.executeSoon(() => aOnResponse({}, this.thread));
|
||||
return;
|
||||
return promise.resolve([{}, this.thread]);
|
||||
}
|
||||
|
||||
let packet = {
|
||||
@ -1827,11 +1830,10 @@ ThreadClient.prototype = {
|
||||
// If the debuggee is paused, we have to send the flag via a reconfigure
|
||||
// request.
|
||||
if (this.paused) {
|
||||
this.reconfigure({
|
||||
return this.reconfigure({
|
||||
pauseOnExceptions: aPauseOnExceptions,
|
||||
ignoreCaughtExceptions: aIgnoreCaughtExceptions
|
||||
}, aOnResponse);
|
||||
return;
|
||||
}
|
||||
// Otherwise send the flag using a standard resume request.
|
||||
return this.interrupt(aResponse => {
|
||||
|
@ -122,6 +122,10 @@ dependencies {
|
||||
compile 'com.google.android.gms:play-services-gcm:8.1.0'
|
||||
}
|
||||
|
||||
// Gradle based builds include LeakCanary. Mach based builds only include the no-op version of
|
||||
// this library.
|
||||
compile 'com.squareup.leakcanary:leakcanary-android:1.4-beta1'
|
||||
|
||||
compile project(':thirdparty')
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
|
@ -68,6 +68,7 @@ import org.mozilla.gecko.trackingprotection.TrackingProtectionPrompt;
|
||||
import org.mozilla.gecko.util.ActivityUtils;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.Experiments;
|
||||
import org.mozilla.gecko.util.FloatUtils;
|
||||
import org.mozilla.gecko.util.GamepadUtils;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
@ -76,7 +77,6 @@ import org.mozilla.gecko.util.MenuUtils;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
import org.mozilla.gecko.util.PrefUtils;
|
||||
import org.mozilla.gecko.util.ScreenshotObserver;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UIAsyncTask;
|
||||
@ -3050,6 +3050,8 @@ public class BrowserApp extends GeckoApp
|
||||
final MenuItem forward = aMenu.findItem(R.id.forward);
|
||||
final MenuItem share = aMenu.findItem(R.id.share);
|
||||
final MenuItem quickShare = aMenu.findItem(R.id.quickshare);
|
||||
final MenuItem bookmarksList = aMenu.findItem(R.id.bookmarks_list);
|
||||
final MenuItem historyList = aMenu.findItem(R.id.history_list);
|
||||
final MenuItem saveAsPDF = aMenu.findItem(R.id.save_as_pdf);
|
||||
final MenuItem print = aMenu.findItem(R.id.print);
|
||||
final MenuItem charEncoding = aMenu.findItem(R.id.char_encoding);
|
||||
@ -3259,6 +3261,11 @@ public class BrowserApp extends GeckoApp
|
||||
MenuUtils.safeSetVisible(aMenu, R.id.addons, false);
|
||||
}
|
||||
|
||||
if (!SwitchBoard.isInExperiment(this, Experiments.BOOKMARKS_HISTORY_MENU)) {
|
||||
bookmarksList.setVisible(false);
|
||||
historyList.setVisible(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3387,6 +3394,20 @@ public class BrowserApp extends GeckoApp
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemId == R.id.bookmarks_list) {
|
||||
final String url = AboutPages.getURLForBuiltinPanelType(PanelType.BOOKMARKS);
|
||||
Tabs.getInstance().loadUrl(url);
|
||||
Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, Experiments.BOOKMARKS_HISTORY_MENU);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemId == R.id.history_list) {
|
||||
final String url = AboutPages.getURLForBuiltinPanelType(PanelType.HISTORY);
|
||||
Tabs.getInstance().loadUrl(url);
|
||||
Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, Experiments.BOOKMARKS_HISTORY_MENU);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemId == R.id.save_as_pdf) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, "pdf");
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SaveAs:PDF", null));
|
||||
|
@ -24,6 +24,8 @@ import android.content.res.Configuration;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class GeckoApplication extends Application
|
||||
@ -127,6 +129,8 @@ public class GeckoApplication extends Application
|
||||
public void onCreate() {
|
||||
Log.i(LOG_TAG, "zerdatime " + SystemClock.uptimeMillis() + " - Fennec application start");
|
||||
|
||||
LeakCanary.install(this);
|
||||
|
||||
final Context context = getApplicationContext();
|
||||
HardwareUtils.init(context);
|
||||
Clipboard.init(context);
|
||||
|
@ -3,11 +3,13 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.util;
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.permissions.Permissions;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
@ -49,19 +51,35 @@ public class ScreenshotObserver {
|
||||
MediaStore.Images.ImageColumns.TITLE
|
||||
};
|
||||
|
||||
/**
|
||||
* Start ScreenshotObserver if this device is supported and all required runtime permissions
|
||||
* have been granted by the user. Calling this method will not prompt for permissions.
|
||||
*/
|
||||
public void start() {
|
||||
if (!Versions.feature14Plus) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (mediaObserver == null) {
|
||||
mediaObserver = new MediaObserver();
|
||||
context.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mediaObserver);
|
||||
Permissions.from(context)
|
||||
.withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.doNotPrompt()
|
||||
.run(startObserverRunnable());
|
||||
}
|
||||
|
||||
private Runnable startObserverRunnable() {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (mediaObserver == null) {
|
||||
mediaObserver = new MediaObserver();
|
||||
context.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mediaObserver);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Failure to start watching media: ", e);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Failure to start watching media: ", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
@ -69,6 +87,10 @@ public class ScreenshotObserver {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mediaObserver == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
context.getContentResolver().unregisterContentObserver(mediaObserver);
|
||||
mediaObserver = null;
|
@ -17,6 +17,7 @@ import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.animation.ViewHelper;
|
||||
import org.mozilla.gecko.home.HomeAdapter.OnAddPanelListener;
|
||||
import org.mozilla.gecko.home.HomeConfig.PanelConfig;
|
||||
import org.mozilla.gecko.util.Experiments;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.content.Context;
|
||||
@ -287,6 +288,9 @@ public class HomePager extends ViewPager {
|
||||
* * HomePager has not loaded yet
|
||||
* * Panel with the given panelId cannot be found
|
||||
*
|
||||
* If you're trying to open a built-in panel, consider loading the panel url directly with
|
||||
* {@link org.mozilla.gecko.AboutPages#getURLForBuiltinPanelType(HomeConfig.PanelType)}.
|
||||
*
|
||||
* @param panelId of the home panel to be shown.
|
||||
*/
|
||||
public void showPanel(String panelId) {
|
||||
@ -525,6 +529,7 @@ public class HomePager extends ViewPager {
|
||||
Telemetry.stopUISession(mCurrentPanelSession, mCurrentPanelSessionSuffix);
|
||||
mCurrentPanelSession = null;
|
||||
mCurrentPanelSessionSuffix = null;
|
||||
Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, Experiments.BOOKMARKS_HISTORY_MENU);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.util;
|
||||
|
||||
/**
|
||||
* This class should reflect the experiment names found in the Switchboard experiments config here:
|
||||
* https://github.com/mozilla-services/switchboard-experiments
|
||||
*/
|
||||
public class Experiments {
|
||||
public static final String BOOKMARKS_HISTORY_MENU = "bookmark-history-menu";
|
||||
}
|
@ -97,6 +97,7 @@ gujar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'util/ColorUtils.java',
|
||||
'util/DrawableUtil.java',
|
||||
'util/EventCallback.java',
|
||||
'util/Experiments.java',
|
||||
'util/FileUtils.java',
|
||||
'util/FloatUtils.java',
|
||||
'util/GamepadUtils.java',
|
||||
@ -119,7 +120,6 @@ gujar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'util/PrefUtils.java',
|
||||
'util/ProxySelector.java',
|
||||
'util/RawResource.java',
|
||||
'util/ScreenshotObserver.java',
|
||||
'util/StringUtils.java',
|
||||
'util/ThreadUtils.java',
|
||||
'util/UIAsyncTask.java',
|
||||
@ -506,6 +506,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||
'restrictions/RestrictedProfileConfiguration.java',
|
||||
'restrictions/RestrictionConfiguration.java',
|
||||
'restrictions/RestrictionProvider.java',
|
||||
'ScreenshotObserver.java',
|
||||
'ServiceNotificationClient.java',
|
||||
'SessionParser.java',
|
||||
'SharedPreferencesHelper.java',
|
||||
@ -778,6 +779,8 @@ gtjar.sources += [ thirdparty_source_dir + f for f in [
|
||||
'com/nineoldandroids/view/ViewPropertyAnimatorHC.java',
|
||||
'com/nineoldandroids/view/ViewPropertyAnimatorICS.java',
|
||||
'com/nineoldandroids/view/ViewPropertyAnimatorPreHC.java',
|
||||
'com/squareup/leakcanary/LeakCanary.java',
|
||||
'com/squareup/leakcanary/RefWatcher.java',
|
||||
'com/squareup/picasso/Action.java',
|
||||
'com/squareup/picasso/AssetBitmapHunter.java',
|
||||
'com/squareup/picasso/BitmapHunter.java',
|
||||
|
@ -54,6 +54,12 @@
|
||||
<item android:id="@+id/new_private_tab"
|
||||
android:title="@string/new_private_tab"/>
|
||||
|
||||
<item android:id="@+id/bookmarks_list"
|
||||
android:title="@string/bookmarks_title"/>
|
||||
|
||||
<item android:id="@+id/history_list"
|
||||
android:title="@string/history_title"/>
|
||||
|
||||
<item android:id="@+id/find_in_page"
|
||||
android:title="@string/find_in_page" />
|
||||
|
||||
|
@ -54,6 +54,12 @@
|
||||
<item android:id="@+id/new_private_tab"
|
||||
android:title="@string/new_private_tab"/>
|
||||
|
||||
<item android:id="@+id/bookmarks_list"
|
||||
android:title="@string/bookmarks_title"/>
|
||||
|
||||
<item android:id="@+id/history_list"
|
||||
android:title="@string/history_title"/>
|
||||
|
||||
<item android:id="@+id/find_in_page"
|
||||
android:title="@string/find_in_page" />
|
||||
|
||||
|
@ -54,6 +54,12 @@
|
||||
<item android:id="@+id/new_private_tab"
|
||||
android:title="@string/new_private_tab"/>
|
||||
|
||||
<item android:id="@+id/bookmarks_list"
|
||||
android:title="@string/bookmarks_title"/>
|
||||
|
||||
<item android:id="@+id/history_list"
|
||||
android:title="@string/history_title"/>
|
||||
|
||||
<item android:id="@+id/find_in_page"
|
||||
android:title="@string/find_in_page" />
|
||||
|
||||
|
@ -39,6 +39,12 @@
|
||||
android:title="@string/desktop_mode"
|
||||
android:checkable="true" />
|
||||
|
||||
<item android:id="@+id/bookmarks_list"
|
||||
android:title="@string/bookmarks_title"/>
|
||||
|
||||
<item android:id="@+id/history_list"
|
||||
android:title="@string/history_title"/>
|
||||
|
||||
<item android:id="@+id/page"
|
||||
android:title="@string/page">
|
||||
|
||||
|
7
mobile/android/config/proguard/leakcanary-keeps.cfg
Normal file
@ -0,0 +1,7 @@
|
||||
# LeakCanary
|
||||
-keep class org.eclipse.mat.** { *; }
|
||||
-keep class com.squareup.leakcanary.** { *; }
|
||||
-keep class com.squareup.haha.** { *; }
|
||||
|
||||
# With LeakCanary 1.4-beta1 this creates a pile of warnings
|
||||
-dontwarn com.squareup.haha.**
|
@ -247,3 +247,6 @@
|
||||
-dontnote android.support.**
|
||||
|
||||
-include "adjust-keeps.cfg"
|
||||
|
||||
-include "leakcanary-keeps.cfg"
|
||||
|
||||
|
4
mobile/android/thirdparty/build.gradle
vendored
@ -28,6 +28,10 @@ android {
|
||||
if (!mozconfig.substs.MOZ_INSTALL_TRACKING) {
|
||||
exclude 'com/adjust/**'
|
||||
}
|
||||
|
||||
// Exclude LeakCanary: It will be added again via a gradle dependency. This version
|
||||
// here is only the no-op library for mach-based builds.
|
||||
exclude 'com/squareup/leakcanary/**'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
mobile/android/thirdparty/com/squareup/leakcanary/LeakCanary.java
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package com.squareup.leakcanary;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
/**
|
||||
* A no-op version of {@link LeakCanary} that can be used in release builds.
|
||||
*/
|
||||
public final class LeakCanary {
|
||||
public static RefWatcher install(Application application) {
|
||||
return RefWatcher.DISABLED;
|
||||
}
|
||||
|
||||
private LeakCanary() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
20
mobile/android/thirdparty/com/squareup/leakcanary/RefWatcher.java
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package com.squareup.leakcanary;
|
||||
|
||||
/**
|
||||
* No-op implementation of {@link RefWatcher} for release builds. Please use {@link
|
||||
* RefWatcher#DISABLED}.
|
||||
*/
|
||||
public final class RefWatcher {
|
||||
public static final RefWatcher DISABLED = new RefWatcher();
|
||||
|
||||
private RefWatcher() {}
|
||||
|
||||
public void watch(Object watchedReference) {}
|
||||
|
||||
public void watch(Object watchedReference, String referenceName) {}
|
||||
}
|
@ -10,6 +10,7 @@ skip-if = os == 'linux' || os == 'win' # bug 632290
|
||||
skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
|
||||
[browser_bug562854.js]
|
||||
[browser_bug562890.js]
|
||||
skip-if = os == 'win' && !debug # Disabled on Windows opt/PGO builds due to intermittent failures (bug 1135866)
|
||||
[browser_bug562899.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_bug562992.js]
|
||||
@ -58,6 +59,7 @@ skip-if = buildapp == 'mulet'
|
||||
[browser_updateid.js]
|
||||
[browser_purchase.js]
|
||||
[browser_openDialog.js]
|
||||
skip-if = os == 'win' && !debug # Disabled on Windows opt/PGO builds due to intermittent failures (bug 1135866)
|
||||
[browser_types.js]
|
||||
[browser_inlinesettings.js]
|
||||
[browser_inlinesettings_custom.js]
|
||||
|