Merge fx-team to m-c a=merge

This commit is contained in:
Wes Kocher 2016-01-25 13:57:54 -08:00
commit 6649e55466
65 changed files with 685 additions and 367 deletions

View File

@ -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() });
}),
};

View File

@ -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();
});
}
};

View File

@ -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;
}
},
};

View File

@ -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}));
}

View File

@ -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");

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 B

View File

@ -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

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 B

View File

@ -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 => {

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);
});

View File

@ -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");
}
});

View File

@ -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");
}
});

View File

@ -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");
}
});

View File

@ -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");
}
});

View File

@ -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;
});

View File

@ -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.");
}
});

View File

@ -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.");
}
});

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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();
});
},
/**

View File

@ -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"]],
];
/**

View File

@ -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");

View File

@ -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";

View File

@ -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");
};

View File

@ -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";

View File

@ -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;

View 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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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
*/

View File

@ -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 => {

View File

@ -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'

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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";
}

View File

@ -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',

View File

@ -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" />

View File

@ -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" />

View File

@ -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" />

View File

@ -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">

View 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.**

View File

@ -247,3 +247,6 @@
-dontnote android.support.**
-include "adjust-keeps.cfg"
-include "leakcanary-keeps.cfg"

View File

@ -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/**'
}
}
}

View 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();
}
}

View 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) {}
}

View File

@ -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]