merge autoland to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2017-06-30 12:56:36 +02:00
Родитель 2bb6be5a33 f6130d3fe8
Коммит 95e5b4e67b
401 изменённых файлов: 19598 добавлений и 12057 удалений

Просмотреть файл

@ -215,6 +215,7 @@ dom/locales/**
dom/manifest/**
dom/mathml/**
dom/media/**
!dom/media/*.js*
dom/messagechannel/**
dom/network/**
dom/notification/**
@ -251,6 +252,9 @@ dom/xml/**
dom/xslt/**
dom/xul/**
# Third-party
dom/media/webvtt/**
# Exclude everything but self-hosted JS
js/ductwork/**
js/examples/**
@ -297,8 +301,14 @@ security/nss/**
services/sync/modules/constants.js
services/sync/services-sync.js
# testing/ exclusions
testing/marionette/**
# Remote protocol exclusions
testing/marionette/test_*.js
testing/marionette/atom.js
testing/marionette/legacyaction.js
testing/marionette/client/**
testing/marionette/harness/**
# other testing/ exclusions
testing/mochitest/**
# third party modules
testing/modules/ajv-4.1.1.js

Просмотреть файл

@ -385,7 +385,7 @@
#endif
context="placesContext"
openInTabs="children"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
oncommand="BookmarksEventHandler.onCommand(event);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="BookmarkingUI.onMainMenuPopupShowing(event);
if (!this.parentNode._placesView)

Просмотреть файл

@ -698,6 +698,20 @@ var PlacesCommandHook = {
organizer.PlacesOrganizer.selectLeftPaneContainerByHierarchy(aLeftPaneRoot);
organizer.focus();
}
},
searchBookmarks() {
if (!focusAndSelectUrlBar()) {
return;
}
for (let char of ["*", " "]) {
let code = char.charCodeAt(0);
gURLBar.inputField.dispatchEvent(new KeyboardEvent("keypress", {
keyCode: code,
charCode: code,
bubbles: true
}));
}
}
};
@ -883,7 +897,7 @@ var BookmarksEventHandler = {
PlacesUIUtils.openContainerNodeInTabs(target._placesNode, aEvent, aView);
} else if (aEvent.button == 1) {
// left-clicks with modifier are already served by onCommand
this.onCommand(aEvent, aView);
this.onCommand(aEvent);
}
},
@ -893,13 +907,11 @@ var BookmarksEventHandler = {
* Opens the item.
* @param aEvent
* DOMEvent for the command
* @param aView
* The places view which aEvent should be associated with.
*/
onCommand: function BEH_onCommand(aEvent, aView) {
onCommand: function BEH_onCommand(aEvent) {
var target = aEvent.originalTarget;
if (target._placesNode)
PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent, aView);
PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent);
},
fillInBHTooltip: function BEH_fillInBHTooltip(aDocument, aEvent) {
@ -1356,7 +1368,7 @@ var BookmarkingUI = {
// overflow panel, we want to show a subview instead.
if (this.button.getAttribute("cui-areatype") == CustomizableUI.TYPE_MENU_PANEL ||
(AppConstants.MOZ_PHOTON_THEME && this.button.hasAttribute("overflowedItem"))) {
this._showSubview();
this._showSubView();
event.preventDefault();
event.stopPropagation();
return;
@ -1840,11 +1852,14 @@ var BookmarkingUI = {
}, 1000);
},
_showSubview() {
showSubView(anchor) {
this._showSubView(anchor);
},
_showSubView(anchor = document.getElementById(this.BOOKMARK_BUTTON_ID)) {
let view = document.getElementById("PanelUI-bookmarks");
view.addEventListener("ViewShowing", this);
view.addEventListener("ViewHiding", this);
let anchor = document.getElementById(this.BOOKMARK_BUTTON_ID);
anchor.setAttribute("closemenu", "none");
PanelUI.showSubView("PanelUI-bookmarks", anchor,
CustomizableUI.AREA_PANEL);
@ -1857,7 +1872,7 @@ var BookmarkingUI = {
// Handle special case when the button is in the panel.
if (this.button.getAttribute("cui-areatype") == CustomizableUI.TYPE_MENU_PANEL) {
this._showSubview();
this._showSubView();
return;
}
let widget = CustomizableUI.getWidget(this.BOOKMARK_BUTTON_ID)
@ -1896,28 +1911,39 @@ var BookmarkingUI = {
},
onPanelMenuViewShowing: function BUI_onViewShowing(aEvent) {
let panelview = aEvent.target;
this.updateBookmarkPageMenuItem();
// Update checked status of the toolbar toggle.
let viewToolbar = document.getElementById("panelMenu_viewBookmarksToolbar");
let personalToolbar = document.getElementById("PersonalToolbar");
if (personalToolbar.collapsed)
viewToolbar.removeAttribute("checked");
else
viewToolbar.setAttribute("checked", "true");
if (viewToolbar) {
let personalToolbar = document.getElementById("PersonalToolbar");
if (personalToolbar.collapsed)
viewToolbar.removeAttribute("checked");
else
viewToolbar.setAttribute("checked", "true");
}
// Get all statically placed buttons to supply them with keyboard shortcuts.
let staticButtons = viewToolbar.parentNode.getElementsByTagName("toolbarbutton");
let staticButtons = panelview.getElementsByTagName("toolbarbutton");
for (let i = 0, l = staticButtons.length; i < l; ++i)
CustomizableUI.addShortcut(staticButtons[i]);
// Setup the Places view.
this._panelMenuView = new PlacesPanelMenuView("place:folder=BOOKMARKS_MENU",
"panelMenu_bookmarksMenu",
"panelMenu_bookmarksMenu", {
extraClasses: {
entry: "subviewbutton",
footer: "panel-subview-footer"
}
});
aEvent.target.removeEventListener("ViewShowing", this);
if (gPhotonStructure) {
// We restrict the amount of results to 42. Not 50, but 42. Why? Because 42.
let query = "place:queryType=" + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
"&sort=" + Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
"&maxResults=42&excludeQueries=1";
this._panelMenuView = new PlacesPanelview(document.getElementById("panelMenu_bookmarksMenu"),
panelview, query);
} else {
this._panelMenuView = new PlacesPanelMenuView("place:folder=BOOKMARKS_MENU",
"panelMenu_bookmarksMenu", "panelMenu_bookmarksMenu", {
extraClasses: {
entry: "subviewbutton",
footer: "panel-subview-footer"
}
});
}
panelview.removeEventListener("ViewShowing", this);
},
onPanelMenuViewHiding: function BUI_onViewHiding(aEvent) {
@ -1926,14 +1952,14 @@ var BookmarkingUI = {
aEvent.target.removeEventListener("ViewHiding", this);
},
onPanelMenuViewCommand: function BUI_onPanelMenuViewCommand(aEvent, aView) {
onPanelMenuViewCommand: function BUI_onPanelMenuViewCommand(aEvent) {
let target = aEvent.originalTarget;
if (!target._placesNode)
return;
if (PlacesUtils.nodeIsContainer(target._placesNode))
PlacesCommandHook.showPlacesOrganizer([ "BookmarksMenu", target._placesNode.itemId ]);
else
PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent, aView);
PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent);
PanelUI.hide();
},

Просмотреть файл

@ -18,7 +18,11 @@
color: var(--lwt-text-color) !important;
}
%ifndef MOZ_PHOTON_THEME
:root:-moz-lwtheme:not([customization-lwtheme]) {
%else
:root:-moz-lwtheme {
%endif
background-color: var(--lwt-accent-color) !important;
background-image: var(--lwt-header-image), var(--lwt-additional-images) !important;
background-position: var(--lwt-background-alignment) !important;
@ -470,6 +474,14 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
visibility: collapse;
}
/* The reload-button is only disabled temporarily when it becomes visible
to prevent users from accidentally clicking it. We don't however need
to show this disabled state, as the flicker that it generates is short
enough to be visible but not long enough to explain anything to users. */
#reload-button[disabled]:not(:-moz-window-inactive) > .toolbarbutton-icon {
opacity: 1 !important;
}
#PanelUI-feeds > .feed-toolbarbutton:-moz-locale-dir(rtl) {
direction: rtl;
}
@ -1184,6 +1196,7 @@ toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > #downloads-
%endif
/* Customize mode */
%ifndef MOZ_PHOTON_THEME
#navigator-toolbox,
#browser-bottombox,
#content-deck {
@ -1197,6 +1210,7 @@ toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > #downloads-
transition-duration: 1ms;
transition-timing-function: linear;
}
%endif
#PanelUI-contents > .panel-customization-placeholder > .panel-customization-placeholder-child {
list-style-image: none;
@ -1237,7 +1251,6 @@ toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > #downloads-
}
#customization-panelHolder > #widget-overflow-fixed-list {
padding-bottom: 50px; /* Make sure there's always space to drop stuff. */
flex: 0 1 auto; /* Size to content, but allow ourselves to shrink */
display: flex;
flex-direction: column;

Просмотреть файл

@ -8320,7 +8320,7 @@ var TabContextMenu = {
// Adjust the state of the toggle mute menu item.
let toggleMute = document.getElementById("context_toggleMuteTab");
if (this.contextTab.hasAttribute("blocked")) {
if (this.contextTab.hasAttribute("activemedia-blocked")) {
toggleMute.label = gNavigatorBundle.getString("playTab.label");
toggleMute.accessKey = gNavigatorBundle.getString("playTab.accesskey");
} else if (this.contextTab.hasAttribute("muted")) {

Просмотреть файл

@ -979,7 +979,7 @@
placespopup="true"
context="placesContext"
openInTabs="children"
oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
oncommand="BookmarksEventHandler.onCommand(event);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="BookmarkingUI.onPopupShowing(event);
BookmarkingUI.attachPlacesView(event, this);"
@ -1143,7 +1143,7 @@
id="PlacesToolbar"
context="placesContext"
onclick="BookmarksEventHandler.onClick(event, this._placesView);"
oncommand="BookmarksEventHandler.onCommand(event, this._placesView);"
oncommand="BookmarksEventHandler.onCommand(event);"
tooltip="bhTooltip"
popupsinherittooltip="true">
<hbox flex="1">

Просмотреть файл

@ -24,7 +24,7 @@
.tab-icon-image:not([src]):not([pinned]):not([crashed]):not([sharing]),
.tab-icon-image[busy],
.tab-throbber:not([busy]),
.tab-icon-sound:not([soundplaying]):not([muted]):not([blocked]),
.tab-icon-sound:not([soundplaying]):not([muted]):not([activemedia-blocked]),
.tab-icon-sound[pinned],
.tab-sharing-icon-overlay,
.tab-icon-overlay {
@ -34,7 +34,7 @@
.tab-sharing-icon-overlay[sharing]:not([selected]),
.tab-icon-overlay[soundplaying][pinned],
.tab-icon-overlay[muted][pinned],
.tab-icon-overlay[blocked][pinned],
.tab-icon-overlay[activemedia-blocked][pinned],
.tab-icon-overlay[crashed] {
display: -moz-box;
}

Просмотреть файл

@ -2162,7 +2162,7 @@
"audioPlaybackStopped", "pauseMedia", "stopMedia",
"blockMedia", "resumeMedia", "mute", "unmute", "blockedPopups", "lastURI",
"purgeSessionHistory", "stopScroll", "startScroll",
"userTypedValue", "userTypedClear"
"userTypedValue", "userTypedClear", "mediaBlocked"
]</field>
<method name="_createLazyBrowser">
@ -2226,8 +2226,21 @@
};
};
break;
case "blockMedia":
case "resumeMedia":
getter = () => {
return () => {
// No need to insert a browser, so we just call the browser's
// method.
aTab.addEventListener("SSTabRestoring", () => {
browser[name]();
}, { once: true });
};
};
break;
case "userTypedValue":
case "userTypedClear":
case "mediaBlocked":
getter = () => {
return SessionStore.getLazyTabValue(aTab, name);
};
@ -5081,7 +5094,7 @@
"tabs.muteAudio.tooltip";
label = stringWithShortcut(stringID, "key_toggleMute");
} else {
if (tab.linkedBrowser.audioBlocked) {
if (tab.hasAttribute("activemedia-blocked")) {
stringID = "tabs.unblockAudio.tooltip";
} else {
stringID = tab.linkedBrowser.audioMuted ?
@ -5740,9 +5753,9 @@
return;
}
if (!tab.hasAttribute("blocked")) {
tab.setAttribute("blocked", true);
this._tabAttrModified(tab, ["blocked"]);
if (!tab.hasAttribute("activemedia-blocked")) {
tab.setAttribute("activemedia-blocked", true);
this._tabAttrModified(tab, ["activemedia-blocked"]);
tab.startMediaBlockTimer();
}
]]>
@ -5754,9 +5767,9 @@
return;
}
if (tab.hasAttribute("blocked")) {
tab.removeAttribute("blocked");
this._tabAttrModified(tab, ["blocked"]);
if (tab.hasAttribute("activemedia-blocked")) {
tab.removeAttribute("activemedia-blocked");
this._tabAttrModified(tab, ["activemedia-blocked"]);
let hist = Services.telemetry.getHistogramById("TAB_AUDIO_INDICATOR_USED");
hist.add(2 /* unblockByVisitingTab */);
tab.finishMediaBlockTimer();
@ -6063,11 +6076,11 @@
</method>
<property name="_isCustomizing" readonly="true">
<getter>
<getter><![CDATA[
let root = document.documentElement;
return root.getAttribute("customizing") == "true" ||
root.getAttribute("customize-exiting") == "true";
</getter>
(!AppConstants.MOZ_PHOTON_THEME && root.getAttribute("customize-exiting") == "true");
]]></getter>
</property>
<method name="_setPositionalAttributes">
@ -7352,7 +7365,7 @@
anonid="sharing-icon"
class="tab-sharing-icon-overlay"
role="presentation"/>
<xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
<xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked"
anonid="overlay-icon"
class="tab-icon-overlay"
role="presentation"/>
@ -7365,7 +7378,7 @@
xbl:inherits="xbl:text=label,accesskey,fadein,pinned,selected=visuallyselected,attention"
role="presentation"/>
</xul:hbox>
<xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
<xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected,activemedia-blocked"
anonid="soundplaying-icon"
class="tab-icon-sound"
role="presentation"/>
@ -7438,11 +7451,6 @@
return this.getAttribute("muted") == "true";
</getter>
</property>
<property name="blocked" readonly="true">
<getter>
return this.getAttribute("blocked") == "true";
</getter>
</property>
<!--
Describes how the tab ended up in this mute state. May be any of:
@ -7467,9 +7475,9 @@
</getter>
</property>
<property name="soundBlocked" readonly="true">
<property name="activeMediaBlocked" readonly="true">
<getter>
return this.getAttribute("blocked") == "true";
return this.getAttribute("activemedia-blocked") == "true";
</getter>
</property>
@ -7490,7 +7498,7 @@
<getter><![CDATA[
let iconVisible = this.hasAttribute("soundplaying") ||
this.hasAttribute("muted") ||
this.hasAttribute("blocked");
this.hasAttribute("activemedia-blocked");
let soundPlayingIcon =
document.getAnonymousElementByAttribute(this, "anonid", "soundplaying-icon");
let overlayIcon =
@ -7587,9 +7595,9 @@
let modifiedAttrs = [];
let hist = Services.telemetry.getHistogramById("TAB_AUDIO_INDICATOR_USED");
if (browser.audioBlocked) {
this.removeAttribute("blocked");
modifiedAttrs.push("blocked");
if (this.hasAttribute("activemedia-blocked")) {
this.removeAttribute("activemedia-blocked");
modifiedAttrs.push("activemedia-blocked");
browser.resumeMedia();
hist.add(3 /* unblockByClickingIcon */);

Просмотреть файл

@ -3,6 +3,8 @@ support-files =
head.js
[browser_appmenu_reflows.js]
[browser_startup.js]
[browser_startup_images.js]
skip-if = !debug
[browser_tabclose_grow_reflows.js]
[browser_tabclose_reflows.js]
[browser_tabopen_reflows.js]

Просмотреть файл

@ -105,7 +105,7 @@ function test() {
return;
}
let data = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject.data;
let data = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject.data.code;
// Keep only the file name for components, as the path is an absolute file
// URL rather than a resource:// URL like for modules.
for (let phase in data) {

Просмотреть файл

@ -0,0 +1,229 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* A whitelist of images that are loaded at startup but not shown.
* List items support the following attributes:
* - file: The location of the loaded image file.
* - hidpi: An alternative hidpi file location for retina screens, if one exists.
* May be the magic string <not loaded> in strange cases where
* only the low-resolution image is loaded but not shown.
* - platforms: An array of the platforms where the issue is occurring.
* Possible values are linux, win, macosx.
* - intermittentNotLoaded: an array of platforms where this image is
* intermittently not loaded, e.g. because it is
* loaded during the time we stop recording.
* - intermittentShown: An array of platforms where this image is
* intermittently shown, contrary to what our
* whitelist says.
*
* Please don't add items to this list. Please remove items from this list.
*/
const whitelist = [
{
file: "chrome://browser/skin/fxa/sync-illustration.svg",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/tab-overflow-indicator.png",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/stop.svg",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/sidebars.svg",
platforms: ["linux", "win", "macosx"],
intermittentNotLoaded: ["macosx"],
},
{
file: "chrome://pocket-shared/skin/pocket.svg",
platforms: ["linux", "win", "macosx"],
intermittentNotLoaded: ["macosx"],
},
{
file: "chrome://browser/skin/places/toolbarDropMarker.png",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/bookmark-hollow.svg",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/tracking-protection-16.svg#enabled",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/toolbarbutton-dropdown-arrow.png",
platforms: ["win"],
},
{
file: "chrome://global/skin/icons/autoscroll.png",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/tab-background-end.png",
hidpi: "chrome://browser/skin/tabbrowser/tab-background-end@2x.png",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/tab-background-middle.png",
hidpi: "chrome://browser/skin/tabbrowser/tab-background-middle@2x.png",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/tab-background-start.png",
hidpi: "chrome://browser/skin/tabbrowser/tab-background-start@2x.png",
platforms: ["linux", "win", "macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/tabDragIndicator.png",
hidpi: "chrome://browser/skin/tabbrowser/tabDragIndicator@2x.png",
platforms: ["linux", "win", "macosx"],
},
{
file: "resource://gre-resources/loading-image.png",
platforms: ["win", "macosx"],
intermittentNotLoaded: ["win", "macosx"],
},
{
file: "resource://gre-resources/broken-image.png",
platforms: ["win", "macosx"],
intermittentNotLoaded: ["win", "macosx"],
},
{
file: "chrome://browser/skin/places/unfiledBookmarks.png",
hidpi: "<not loaded>",
platforms: ["win", "macosx"],
intermittentNotLoaded: ["win", "macosx"],
},
{
file: "chrome://browser/skin/urlbar-history-dropmarker.png",
hidpi: "<not loaded>",
platforms: ["win", "macosx"],
intermittentShown: ["win", "macosx"],
},
{
file: "chrome://browser/skin/yosemite/tab-selected-start-inactive.svg",
platforms: ["macosx"],
},
{
file: "chrome://browser/skin/yosemite/tab-active-middle-inactive.png",
platforms: ["macosx"],
},
{
file: "chrome://browser/skin/yosemite/tab-selected-end-inactive.svg",
platforms: ["macosx"],
},
{
file: "chrome://browser/skin/yosemite/tab-stroke-start-inactive.png",
platforms: ["macosx"],
},
{
file: "chrome://browser/skin/yosemite/tab-stroke-end-inactive.png",
platforms: ["macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/newtab.png",
platforms: ["macosx"],
},
{
file: "chrome://global/skin/icons/chevron.png",
hidpi: "chrome://global/skin/icons/chevron@2x.png",
platforms: ["macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png",
hidpi: "chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon@2x.png",
platforms: ["macosx"],
},
{
file: "chrome://global/skin/toolbar/chevron.gif",
platforms: ["win", "linux"],
},
{
file: "chrome://browser/skin/reload-stop-go.png",
platforms: ["win", "linux"],
intermittentShown: ["win", "linux"],
},
{
file: "chrome://browser/skin/tabbrowser/alltabs.png",
platforms: ["linux"],
},
{
file: "chrome://browser/skin/tabbrowser/tab-arrow-left.svg",
platforms: ["win"],
},
{
file: "chrome://global/skin/icons/resizer.png",
platforms: ["win"],
},
{
file: "chrome://global/skin/icons/resizer.png",
platforms: ["win"],
},
{
file: "chrome://browser/skin/tabbrowser/tab-arrow-left.png",
hidpi: "chrome://browser/skin/tabbrowser/tab-arrow-left@2x.png",
platforms: ["linux", "macosx"],
},
{
file: "chrome://browser/skin/tabbrowser/tab-arrow-right.png",
hidpi: "chrome://browser/skin/tabbrowser/tab-arrow-right@2x.png",
platforms: ["macosx"],
},
];
function test() {
let data = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject.data.images;
let platformWhitelist = whitelist.filter(el => el.platforms.includes(AppConstants.platform));
let loadedImages = data["image-loading"];
let shownImages = data["image-drawing"];
for (let loaded of loadedImages.values()) {
let whitelistItem = platformWhitelist.find(el => {
if (window.devicePixelRatio >= 2 && el.hidpi && el.hidpi == loaded) {
return true;
}
return el.file == loaded;
});
if (whitelistItem) {
if (!whitelistItem.intermittentShown ||
!whitelistItem.intermittentShown.includes(AppConstants.platform)) {
todo(shownImages.has(loaded), `Whitelisted image ${loaded} should not have been shown.`);
}
continue;
}
ok(shownImages.has(loaded), `Loaded image ${loaded} should have been shown.`);
}
// Check for unneeded whitelist entries.
for (let item of platformWhitelist) {
if (!item.intermittentNotLoaded ||
!item.intermittentNotLoaded.includes(AppConstants.platform)) {
if (window.devicePixelRatio >= 2 && item.hidpi) {
if (item.hidpi != "<not loaded>") {
ok(loadedImages.has(item.hidpi), `Whitelisted image ${item.hidpi} should have been loaded.`);
}
} else {
ok(loadedImages.has(item.file), `Whitelisted image ${item.file} should have been loaded.`);
}
}
}
}

Просмотреть файл

@ -32,7 +32,7 @@ var gExceptionPaths = [
if (AppConstants.platform == "macosx")
gExceptionPaths.push("resource://gre/res/cursors/");
var whitelist = new Set([
var whitelist = [
// browser/extensions/pdfjs/content/PdfStreamConverter.jsm
{file: "chrome://pdf.js/locale/chrome.properties"},
{file: "chrome://pdf.js/locale/viewer.properties"},
@ -124,15 +124,6 @@ var whitelist = new Set([
// Bug 1339424 (wontfix?)
{file: "chrome://browser/locale/taskbar.properties",
platforms: ["linux", "macosx"]},
// Bug 1343824
{file: "chrome://browser/skin/customizableui/customize-illustration-rtl@2x.png",
platforms: ["linux", "win"]},
{file: "chrome://browser/skin/customizableui/customize-illustration@2x.png",
platforms: ["linux", "win"]},
{file: "chrome://browser/skin/customizableui/info-icon-customizeTip@2x.png",
platforms: ["linux", "win"]},
{file: "chrome://browser/skin/customizableui/panelarrow-customizeTip@2x.png",
platforms: ["linux", "win"]},
// Bug 1316187
{file: "chrome://global/content/customizeToolbar.xul"},
// Bug 1343837
@ -182,7 +173,22 @@ var whitelist = new Set([
// Bug 1351637
{file: "resource://gre/modules/sdk/bootstrap.js"},
].filter(item =>
];
if (!AppConstants.MOZ_PHOTON_THEME) {
whitelist.push(
// Bug 1343824
{file: "chrome://browser/skin/customizableui/customize-illustration-rtl@2x.png",
platforms: ["linux", "win"]},
{file: "chrome://browser/skin/customizableui/customize-illustration@2x.png",
platforms: ["linux", "win"]},
{file: "chrome://browser/skin/customizableui/info-icon-customizeTip@2x.png",
platforms: ["linux", "win"]},
{file: "chrome://browser/skin/customizableui/panelarrow-customizeTip@2x.png",
platforms: ["linux", "win"]});
}
whitelist = new Set(whitelist.filter(item =>
("isFromDevTools" in item) == isDevtools &&
(!item.skipNightly || !AppConstants.NIGHTLY_BUILD) &&
(!item.platforms || item.platforms.includes(AppConstants.platform))

Просмотреть файл

@ -332,9 +332,11 @@ CustomizeMode.prototype = {
this.visiblePalette.hidden = true;
this.visiblePalette.removeAttribute("showing");
// Disable the button-text fade-out mask
// during the transition for increased perf.
window.PanelUI.contents.setAttribute("customize-transitioning", "true");
if (!AppConstants.MOZ_PHOTON_THEME) {
// Disable the button-text fade-out mask
// during the transition for increased perf.
window.PanelUI.contents.setAttribute("customize-transitioning", "true");
}
// Move the mainView in the panel to the holder so that we can see it
// while customizing.
@ -412,7 +414,9 @@ CustomizeMode.prototype = {
this._updateEmptyPaletteNotice();
this._updateLWThemeButtonIcon();
this.maybeShowTip(panelHolder);
if (!AppConstants.MOZ_PHOTON_THEME) {
this.maybeShowTip(panelHolder);
}
this._handler.isEnteringCustomizeMode = false;
if (!gPhotonStructure) {
@ -634,6 +638,17 @@ CustomizeMode.prototype = {
* excluding certain styles while in any phase of customize mode.
*/
_doTransition(aEntering) {
if (AppConstants.MOZ_PHOTON_THEME) {
let docEl = this.document.documentElement;
if (aEntering) {
docEl.setAttribute("customizing", true);
docEl.setAttribute("customize-entered", true);
} else {
docEl.removeAttribute("customizing");
docEl.removeAttribute("customize-entered");
}
return Promise.resolve();
}
let deck = this.document.getElementById("content-deck");
let customizeTransitionEndPromise = new Promise(resolve => {
let customizeTransitionEnd = (aEvent) => {

Просмотреть файл

@ -205,6 +205,15 @@ this.PanelMultiView = class {
return this.__screenManager = Cc["@mozilla.org/gfx/screenmanager;1"]
.getService(Ci.nsIScreenManager);
}
/**
* Getter that returns the currently visible subview OR the subview that is
* about to be shown whilst a 'ViewShowing' event is being dispatched.
*
* @return {panelview}
*/
get current() {
return this._viewShowing || this._currentSubView
}
get _currentSubView() {
return this.panelViews ? this.panelViews.currentView : this.__currentSubView;
}
@ -295,6 +304,10 @@ this.PanelMultiView = class {
value: (...args) => this[method](...args)
});
});
Object.defineProperty(this.node, "current", {
enumerable: true,
get: () => this.current
});
}
destructor() {
@ -320,6 +333,7 @@ this.PanelMultiView = class {
this._panel.removeEventListener("popupshowing", this);
this._panel.removeEventListener("popupshown", this);
this._panel.removeEventListener("popuphidden", this);
this.node.dispatchEvent(new this.window.CustomEvent("destructed"));
this.node = this._clickCapturer = this._viewContainer = this._mainViewContainer =
this._subViews = this._viewStack = this.__dwu = this._panelViewCache = null;
}
@ -344,6 +358,16 @@ this.PanelMultiView = class {
}
}
_placeSubView(viewNode) {
if (this.panelViews) {
this._viewStack.appendChild(viewNode);
if (!this.panelViews.includes(viewNode))
this.panelViews.push(viewNode);
} else {
this._subViews.appendChild(viewNode);
}
}
goBack(target) {
let [current, previous] = this.panelViews.back();
return this.showSubView(current, target, previous);
@ -409,15 +433,12 @@ this.PanelMultiView = class {
if (!viewNode) {
viewNode = document.getElementById(aViewId);
if (viewNode) {
if (this.panelViews) {
this._viewStack.appendChild(viewNode);
this.panelViews.push(viewNode);
} else {
this._subViews.appendChild(viewNode);
}
this._placeSubView(viewNode);
} else {
throw new Error(`Subview ${aViewId} doesn't exist!`);
}
} else if (viewNode.parentNode == this._panelViewCache) {
this._placeSubView(viewNode);
}
let reverse = !!aPreviousView;
@ -472,6 +493,7 @@ this.PanelMultiView = class {
if (this.panelViews && this._mainViewWidth)
viewNode.style.maxWidth = viewNode.style.minWidth = this._mainViewWidth + "px";
this._viewShowing = viewNode;
let evt = new window.CustomEvent("ViewShowing", { bubbles: true, cancelable: true, detail });
viewNode.dispatchEvent(evt);
@ -491,6 +513,7 @@ this.PanelMultiView = class {
return;
}
this._viewShowing = null;
this._currentSubView = viewNode;
viewNode.setAttribute("current", true);
if (this.panelViews) {

Просмотреть файл

@ -210,18 +210,29 @@
<label value="&bookmarksMenu.label;" class="panel-subview-header"/>
<vbox class="panel-subview-body">
<toolbarbutton id="panelMenuBookmarkThisPage"
#ifndef MOZ_PHOTON_THEME
class="subviewbutton"
#else
class="subviewbutton subviewbutton-iconic"
#endif
observes="bookmarkThisPageBroadcaster"
command="Browser:AddBookmarkAs"
onclick="PanelUI.hide();"/>
#ifndef MOZ_PHOTON_THEME
<toolbarseparator/>
#endif
<toolbarbutton id="panelMenu_viewBookmarksSidebar"
label="&viewBookmarksSidebar2.label;"
#ifndef MOZ_PHOTON_THEME
class="subviewbutton"
#else
class="subviewbutton subviewbutton-iconic"
#endif
key="viewBookmarksSidebarKb"
oncommand="SidebarUI.toggle('viewBookmarksSidebar'); PanelUI.hide();">
<observes element="viewBookmarksSidebar" attribute="checked"/>
</toolbarbutton>
#ifndef MOZ_PHOTON_THEME
<toolbarbutton id="panelMenu_viewBookmarksToolbar"
label="&viewBookmarksToolbar.label;"
type="checkbox"
@ -238,11 +249,23 @@
class="subviewbutton cui-withicon"
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); PanelUI.hide();"/>
<toolbarseparator class="small-separator"/>
#else
<toolbarbutton id="panelMenu_searchBookmarks"
label="&searchBookmarks.label;"
class="subviewbutton subviewbutton-iconic"
oncommand="PlacesCommandHook.searchBookmarks(); PanelUI.hide();"/>
<toolbarseparator/>
<label id="panelMenu_recentBookmarks"
value="&recentBookmarks.label;"
class="subview-subheader"/>
#endif
<toolbaritem id="panelMenu_bookmarksMenu"
orient="vertical"
smoothscroll="false"
#ifndef MOZ_PHOTON_THEME
onclick="if (event.button == 1) BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);"
oncommand="BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);"
#endif
flatList="true"
tooltip="bhTooltip">
<!-- bookmarks menu items will go here -->
@ -353,7 +376,8 @@
<vbox id="widget-overflow-list" class="widget-overflow-list"
overflowfortoolbar="nav-bar"/>
<toolbarseparator id="widget-overflow-fixed-separator" hidden="true"/>
<vbox id="widget-overflow-fixed-list" class="widget-overflow-list" hidden="true"/>
<vbox id="widget-overflow-fixed-list" class="widget-overflow-list" hidden="true"
emptylabel="&customizeMode.emptyOverflowList.description;"/>
</vbox>
#ifdef MOZ_PHOTON_THEME
</panelview>
@ -710,6 +734,11 @@
</panelview>
<panelview id="appMenu-libraryView" class="PanelUI-subView">
<vbox class="panel-subview-body">
<toolbarbutton id="appMenu-library-bookmarks-button"
class="subviewbutton subviewbutton-iconic subviewbutton-nav"
label="&bookmarksMenuButton.label;"
closemenu="none"
oncommand="BookmarkingUI.showSubView(this);"/>
<toolbarbutton id="appMenu-library-history-button"
class="subviewbutton subviewbutton-iconic subviewbutton-nav"
label="&historyMenu.label;"

Просмотреть файл

@ -524,7 +524,7 @@ const DownloadsIndicatorView = {
get _progressIcon() {
return this.__progressIcon ||
(this.__progressIcon = document.getElementById("downloads-indicator-progress-icon"));
(this.__progressIcon = document.getElementById("downloads-indicator-progress-inner"));
},
get notifier() {

Просмотреть файл

@ -25,8 +25,11 @@
its arrow unexpectedly. -->
<stack id="downloads-indicator-anchor"
consumeanchor="downloads-button">
<stack id="downloads-indicator-icon">
<vbox id="downloads-indicator-progress-icon"/>
#ifdef MOZ_PHOTON_ANIMATIONS
<box id="downloads-indicator-icon"/>
#endif
<stack id="downloads-indicator-progress-outer">
<box id="downloads-indicator-progress-inner"/>
</stack>
</stack>
</toolbarbutton>

Просмотреть файл

@ -8,7 +8,7 @@ browser.jar:
content/browser/downloads/downloads.js (content/downloads.js)
* content/browser/downloads/downloadsOverlay.xul (content/downloadsOverlay.xul)
content/browser/downloads/indicator.js (content/indicator.js)
content/browser/downloads/indicatorOverlay.xul (content/indicatorOverlay.xul)
* content/browser/downloads/indicatorOverlay.xul (content/indicatorOverlay.xul)
* content/browser/downloads/allDownloadsViewOverlay.xul (content/allDownloadsViewOverlay.xul)
content/browser/downloads/allDownloadsViewOverlay.js (content/allDownloadsViewOverlay.js)
* content/browser/downloads/contentAreaDownloadsView.xul (content/contentAreaDownloadsView.xul)

Просмотреть файл

@ -10,7 +10,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
let listenerCount = 0;
function getTree(rootGuid, onlyChildren) {
const getTree = (rootGuid, onlyChildren) => {
function convert(node, parent) {
let treenode = {
id: node.guid,
@ -57,9 +57,9 @@ function getTree(rootGuid, onlyChildren) {
// It seems like the array always just contains the root node.
return [treenode];
}).catch(e => Promise.reject({message: e.message}));
}
};
function convert(result) {
const convertBookmarks = result => {
let node = {
id: result.guid,
title: result.title || "",
@ -78,7 +78,7 @@ function convert(result) {
}
return node;
}
};
let observer = {
skipTags: true,
@ -163,19 +163,19 @@ let observer = {
};
EventEmitter.decorate(observer);
function decrementListeners() {
const decrementListeners = () => {
listenerCount -= 1;
if (!listenerCount) {
PlacesUtils.bookmarks.removeObserver(observer);
}
}
};
function incrementListeners() {
const incrementListeners = () => {
listenerCount++;
if (listenerCount == 1) {
PlacesUtils.bookmarks.addObserver(observer);
}
}
};
this.bookmarks = class extends ExtensionAPI {
getAPI(context) {
@ -191,7 +191,7 @@ this.bookmarks = class extends ExtensionAPI {
if (!bookmark) {
throw new Error("Bookmark not found");
}
bookmarks.push(convert(bookmark));
bookmarks.push(convertBookmarks(bookmark));
}
return bookmarks;
} catch (error) {
@ -213,11 +213,11 @@ this.bookmarks = class extends ExtensionAPI {
},
search: function(query) {
return PlacesUtils.bookmarks.search(query).then(result => result.map(convert));
return PlacesUtils.bookmarks.search(query).then(result => result.map(convertBookmarks));
},
getRecent: function(numberOfItems) {
return PlacesUtils.bookmarks.getRecent(numberOfItems).then(result => result.map(convert));
return PlacesUtils.bookmarks.getRecent(numberOfItems).then(result => result.map(convertBookmarks));
},
create: function(bookmark) {
@ -244,7 +244,7 @@ this.bookmarks = class extends ExtensionAPI {
}
try {
return PlacesUtils.bookmarks.insert(info).then(convert)
return PlacesUtils.bookmarks.insert(info).then(convertBookmarks)
.catch(error => Promise.reject({message: error.message}));
} catch (e) {
return Promise.reject({message: `Invalid bookmark: ${JSON.stringify(info)}`});
@ -263,7 +263,7 @@ this.bookmarks = class extends ExtensionAPI {
PlacesUtils.bookmarks.DEFAULT_INDEX : destination.index;
try {
return PlacesUtils.bookmarks.update(info).then(convert)
return PlacesUtils.bookmarks.update(info).then(convertBookmarks)
.catch(error => Promise.reject({message: error.message}));
} catch (e) {
return Promise.reject({message: `Invalid bookmark: ${JSON.stringify(info)}`});
@ -283,7 +283,7 @@ this.bookmarks = class extends ExtensionAPI {
}
try {
return PlacesUtils.bookmarks.update(info).then(convert)
return PlacesUtils.bookmarks.update(info).then(convertBookmarks)
.catch(error => Promise.reject({message: error.message}));
} catch (e) {
return Promise.reject({message: `Invalid bookmark: ${JSON.stringify(info)}`});
@ -317,7 +317,7 @@ this.bookmarks = class extends ExtensionAPI {
}
},
onCreated: new SingletonEventManager(context, "bookmarks.onCreated", fire => {
onCreated: new EventManager(context, "bookmarks.onCreated", fire => {
let listener = (event, bookmark) => {
fire.sync(bookmark.id, bookmark);
};
@ -330,7 +330,7 @@ this.bookmarks = class extends ExtensionAPI {
};
}).api(),
onRemoved: new SingletonEventManager(context, "bookmarks.onRemoved", fire => {
onRemoved: new EventManager(context, "bookmarks.onRemoved", fire => {
let listener = (event, data) => {
fire.sync(data.guid, data.info);
};
@ -343,7 +343,7 @@ this.bookmarks = class extends ExtensionAPI {
};
}).api(),
onChanged: new SingletonEventManager(context, "bookmarks.onChanged", fire => {
onChanged: new EventManager(context, "bookmarks.onChanged", fire => {
let listener = (event, data) => {
fire.sync(data.guid, data.info);
};
@ -356,7 +356,7 @@ this.bookmarks = class extends ExtensionAPI {
};
}).api(),
onMoved: new SingletonEventManager(context, "bookmarks.onMoved", fire => {
onMoved: new EventManager(context, "bookmarks.onMoved", fire => {
let listener = (event, data) => {
fire.sync(data.guid, data.info);
};

Просмотреть файл

@ -8,7 +8,7 @@ XPCOMUtils.defineLazyModuleGetter(global, "EventEmitter",
// This function is pretty tightly tied to Extension.jsm.
// Its job is to fill in the |tab| property of the sender.
function getSender(extension, target, sender) {
const getSender = (extension, target, sender) => {
let tabId;
if ("tabId" in sender) {
// The message came from a privileged extension page running in a tab. In
@ -26,7 +26,7 @@ function getSender(extension, target, sender) {
sender.tab = tab.convert();
}
}
}
};
// Used by Extension.jsm
global.tabGetSender = getSender;

Просмотреть файл

@ -43,14 +43,14 @@ const POPUP_RESULT_HISTOGRAM = "WEBEXT_BROWSERACTION_POPUP_PRELOAD_RESULT_COUNT"
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
function isAncestorOrSelf(target, node) {
const isAncestorOrSelf = (target, node) => {
for (; node; node = node.parentNode) {
if (node === target) {
return true;
}
}
return false;
}
};
// WeakMap[Extension -> BrowserAction]
const browserActionMap = new WeakMap();
@ -205,7 +205,7 @@ this.browserAction = class extends ExtensionAPI {
// This isn't not a hack, but it seems to provide the correct behavior
// with the fewest complications.
event.preventDefault();
this.emit("click");
this.emit("click", tabbrowser.selectedBrowser);
}
},
});
@ -566,9 +566,10 @@ this.browserAction = class extends ExtensionAPI {
return {
browserAction: {
onClicked: new SingletonEventManager(context, "browserAction.onClicked", fire => {
let listener = () => {
fire.async(tabManager.convert(tabTracker.activeTab));
onClicked: new InputEventManager(context, "browserAction.onClicked", fire => {
let listener = (event, browser) => {
context.withPendingBrowser(browser, () =>
fire.sync(tabManager.convert(tabTracker.activeTab)));
};
browserAction.on("click", listener);
return () => {

Просмотреть файл

@ -32,18 +32,18 @@ XPCOMUtils.defineLazyGetter(this, "sanitizer", () => {
return sanitizer;
});
function makeRange(options) {
const makeRange = options => {
return (options.since == null) ?
null :
[PlacesUtils.toPRTime(options.since), PlacesUtils.toPRTime(Date.now())];
}
};
function clearCache() {
const clearCache = () => {
// Clearing the cache does not support timestamps.
return sanitizer.items.cache.clear();
}
};
let clearCookies = async function(options) {
const clearCookies = async function(options) {
let cookieMgr = Services.cookies;
// This code has been borrowed from sanitize.js.
let yieldCounter = 0;
@ -70,19 +70,19 @@ let clearCookies = async function(options) {
}
};
function clearDownloads(options) {
const clearDownloads = options => {
return sanitizer.items.downloads.clear(makeRange(options));
}
};
function clearFormData(options) {
const clearFormData = options => {
return sanitizer.items.formdata.clear(makeRange(options));
}
};
function clearHistory(options) {
const clearHistory = options => {
return sanitizer.items.history.clear(makeRange(options));
}
};
let clearPasswords = async function(options) {
const clearPasswords = async function(options) {
let loginManager = Services.logins;
let yieldCounter = 0;
@ -104,11 +104,11 @@ let clearPasswords = async function(options) {
}
};
function clearPluginData(options) {
const clearPluginData = options => {
return sanitizer.items.pluginData.clear(makeRange(options));
}
};
let clearServiceWorkers = async function() {
const clearServiceWorkers = async function() {
// Clearing service workers does not support timestamps.
let yieldCounter = 0;
@ -124,7 +124,7 @@ let clearServiceWorkers = async function() {
}
};
function doRemoval(options, dataToRemove, extension) {
const doRemoval = (options, dataToRemove, extension) => {
if (options.originTypes &&
(options.originTypes.protectedWeb || options.originTypes.extension)) {
return Promise.reject(
@ -170,7 +170,7 @@ function doRemoval(options, dataToRemove, extension) {
`Firefox does not support dataTypes: ${invalidDataTypes.toString()}.`);
}
return Promise.all(removalPromises);
}
};
this.browsingData = class extends ExtensionAPI {
getAPI(context) {

Просмотреть файл

@ -102,7 +102,7 @@ class ChildDevToolsPanel extends EventEmitter {
api() {
return {
onShown: new SingletonEventManager(
onShown: new EventManager(
this.context, "devtoolsPanel.onShown", fire => {
const listener = (eventName, panelContentWindow) => {
fire.asyncWithoutClone(panelContentWindow);
@ -113,7 +113,7 @@ class ChildDevToolsPanel extends EventEmitter {
};
}).api(),
onHidden: new SingletonEventManager(
onHidden: new EventManager(
this.context, "devtoolsPanel.onHidden", fire => {
const listener = () => {
fire.async();
@ -160,7 +160,7 @@ this.devtools_panels = class extends ExtensionAPI {
get themeName() {
return themeChangeObserver.themeName;
},
onThemeChanged: new SingletonEventManager(
onThemeChanged: new EventManager(
context, "devtools.panels.onThemeChanged", fire => {
const listener = (eventName, themeName) => {
fire.async(themeName);

Просмотреть файл

@ -5,6 +5,10 @@
// The ext-* files are imported into the same scopes.
/* import-globals-from ../../../toolkit/components/extensions/ext-c-toolkit.js */
var {
withHandlingUserInput,
} = ExtensionUtils;
// If id is not specified for an item we use an integer.
// This ID need only be unique within a single addon. Since all addon code that
// can use this API runs in the same process, this local variable suffices.
@ -158,9 +162,10 @@ this.menusInternal = class extends ExtensionAPI {
return context.childManager.callParentAsyncFunction("menusInternal.removeAll", []);
},
onClicked: new SingletonEventManager(context, "menus.onClicked", fire => {
onClicked: new EventManager(context, "menus.onClicked", fire => {
let listener = (info, tab) => {
fire.async(info, tab);
withHandlingUserInput(context.contentWindow,
() => fire.sync(info, tab));
};
let event = context.childManager.getParentEvent("menusInternal.onClicked");

Просмотреть файл

@ -9,7 +9,7 @@ this.omnibox = class extends ExtensionAPI {
getAPI(context) {
return {
omnibox: {
onInputChanged: new SingletonEventManager(context, "omnibox.onInputChanged", fire => {
onInputChanged: new EventManager(context, "omnibox.onInputChanged", fire => {
let listener = (text, id) => {
fire.asyncWithoutClone(text, suggestions => {
context.childManager.callParentFunctionNoReturn("omnibox_internal.addSuggestions", [

Просмотреть файл

@ -7,7 +7,7 @@
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionPreferencesManager",
"resource://gre/modules/ExtensionPreferencesManager.jsm");
function searchInitialized() {
const searchInitialized = () => {
return new Promise(resolve => {
if (Services.search.isInitialized) {
resolve();
@ -22,7 +22,7 @@ function searchInitialized() {
resolve();
}, SEARCH_SERVICE_TOPIC);
});
}
};
this.chrome_settings_overrides = class extends ExtensionAPI {
async onManifestEntry(entryName) {

Просмотреть файл

@ -241,7 +241,7 @@ this.commands = class extends ExtensionAPI {
});
}));
},
onCommand: new SingletonEventManager(context, "commands.onCommand", fire => {
onCommand: new EventManager(context, "commands.onCommand", fire => {
let listener = (eventName, commandName) => {
fire.async(commandName);
};

Просмотреть файл

@ -10,7 +10,7 @@ this.devtools_network = class extends ExtensionAPI {
return {
devtools: {
network: {
onNavigated: new SingletonEventManager(context, "devtools.onNavigated", fire => {
onNavigated: new EventManager(context, "devtools.onNavigated", fire => {
let listener = (event, data) => {
fire.async(data.url);
};

Просмотреть файл

@ -22,7 +22,7 @@ var {
ExtensionError,
} = ExtensionUtils;
function parseSym(data) {
const parseSym = data => {
const worker = new ChromeWorker("resource://app/modules/ParseSymbols-worker.js");
const promise = new Promise((resolve, reject) => {
worker.onmessage = (e) => {
@ -35,7 +35,7 @@ function parseSym(data) {
});
worker.postMessage(data);
return promise;
}
};
class NMParser {
constructor() {
@ -120,14 +120,14 @@ class CppFiltParser {
}
}
async function readAllData(pipe, processData) {
const readAllData = async function(pipe, processData) {
let data;
while ((data = await pipe.readString())) {
processData(data);
}
}
};
async function spawnProcess(name, cmdArgs, processData, stdin = null) {
const spawnProcess = async function(name, cmdArgs, processData, stdin = null) {
const opts = {
command: await Subprocess.pathSearch(name),
arguments: cmdArgs,
@ -141,9 +141,9 @@ async function spawnProcess(name, cmdArgs, processData, stdin = null) {
}
await readAllData(proc.stdout, processData);
}
};
async function getSymbolsFromNM(path, arch) {
const getSymbolsFromNM = async function(path, arch) {
const parser = new NMParser();
const args = [path];
@ -173,20 +173,20 @@ async function getSymbolsFromNM(path, arch) {
}
return ParseSymbols.convertSymsMapToExpectedSymFormat(syms, approximateLength);
}
};
function pathComponentsForSymbolFile(debugName, breakpadId) {
const pathComponentsForSymbolFile = (debugName, breakpadId) => {
const symName = debugName.replace(/(\.pdb)?$/, ".sym");
return [debugName, breakpadId, symName];
}
};
function urlForSymFile(debugName, breakpadId) {
const urlForSymFile = (debugName, breakpadId) => {
const profilerSymbolsURL = Services.prefs.getCharPref(PREF_SYMBOLS_URL,
"http://symbols.mozilla.org/");
return profilerSymbolsURL + pathComponentsForSymbolFile(debugName, breakpadId).join("/");
}
};
function getContainingObjdirDist(path) {
const getContainingObjdirDist = path => {
let curPath = path;
let curPathBasename = OS.Path.basename(curPath);
while (curPathBasename) {
@ -201,9 +201,9 @@ function getContainingObjdirDist(path) {
curPathBasename = OS.Path.basename(curPath);
}
return null;
}
};
function filePathForSymFileInObjDir(binaryPath, debugName, breakpadId) {
const filePathForSymFileInObjDir = (binaryPath, debugName, breakpadId) => {
// `mach buildsymbols` generates symbol files located
// at /path/to/objdir/dist/crashreporter-symbols/.
const objDirDist = getContainingObjdirDist(binaryPath);
@ -213,15 +213,15 @@ function filePathForSymFileInObjDir(binaryPath, debugName, breakpadId) {
return OS.Path.join(objDirDist,
"crashreporter-symbols",
...pathComponentsForSymbolFile(debugName, breakpadId));
}
};
const symbolCache = new Map();
function primeSymbolStore(libs) {
const primeSymbolStore = libs => {
for (const {debugName, breakpadId, path, arch} of libs) {
symbolCache.set(urlForSymFile(debugName, breakpadId), {path, arch});
}
}
};
const isRunningObserver = {
_observers: new Set(),
@ -374,7 +374,7 @@ this.geckoProfiler = class extends ExtensionAPI {
throw new Error(`Ran out of options to get symbols from library ${debugName} ${breakpadId}.`);
},
onRunning: new SingletonEventManager(context, "geckoProfiler.onRunning", fire => {
onRunning: new EventManager(context, "geckoProfiler.onRunning", fire => {
isRunningObserver.addObserver(fire.async);
return () => {
isRunningObserver.removeObserver(fire.async);

Просмотреть файл

@ -28,7 +28,7 @@ for (let [transition, transitionType] of TRANSITION_TO_TRANSITION_TYPES_MAP) {
TRANSITION_TYPE_TO_TRANSITIONS_MAP.set(transitionType, transition);
}
function getTransitionType(transition) {
const getTransitionType = transition => {
// cannot set a default value for the transition argument as the framework sets it to null
transition = transition || "link";
let transitionType = TRANSITION_TO_TRANSITION_TYPES_MAP.get(transition);
@ -36,18 +36,18 @@ function getTransitionType(transition) {
throw new Error(`|${transition}| is not a supported transition for history`);
}
return transitionType;
}
};
function getTransition(transitionType) {
const getTransition = transitionType => {
return TRANSITION_TYPE_TO_TRANSITIONS_MAP.get(transitionType) || "link";
}
};
/*
* Converts a nsINavHistoryResultNode into a HistoryItem
*
* https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryResultNode
*/
function convertNodeToHistoryItem(node) {
const convertNodeToHistoryItem = node => {
return {
id: node.pageGuid,
url: node.uri,
@ -55,14 +55,14 @@ function convertNodeToHistoryItem(node) {
lastVisitTime: PlacesUtils.toDate(node.time).getTime(),
visitCount: node.accessCount,
};
}
};
/*
* Converts a nsINavHistoryResultNode into a VisitItem
*
* https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryResultNode
*/
function convertNodeToVisitItem(node) {
const convertNodeToVisitItem = node => {
return {
id: node.pageGuid,
visitId: node.visitId,
@ -70,14 +70,14 @@ function convertNodeToVisitItem(node) {
referringVisitId: node.fromVisitId,
transition: getTransition(node.visitType),
};
}
};
/*
* Converts a nsINavHistoryContainerResultNode into an array of objects
*
* https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryContainerResultNode
*/
function convertNavHistoryContainerResultNode(container, converter) {
const convertNavHistoryContainerResultNode = (container, converter) => {
let results = [];
container.containerOpen = true;
for (let i = 0; i < container.childCount; i++) {
@ -86,11 +86,11 @@ function convertNavHistoryContainerResultNode(container, converter) {
}
container.containerOpen = false;
return results;
}
};
var _observer;
function getObserver() {
const getHistoryObserver = () => {
if (!_observer) {
_observer = {
onDeleteURI: function(uri, guid, reason) {
@ -126,7 +126,7 @@ function getObserver() {
PlacesUtils.history.addObserver(_observer);
}
return _observer;
}
};
this.history = class extends ExtensionAPI {
getAPI(context) {
@ -219,36 +219,36 @@ this.history = class extends ExtensionAPI {
return Promise.resolve(results);
},
onVisited: new SingletonEventManager(context, "history.onVisited", fire => {
onVisited: new EventManager(context, "history.onVisited", fire => {
let listener = (event, data) => {
fire.sync(data);
};
getObserver().on("visited", listener);
getHistoryObserver().on("visited", listener);
return () => {
getObserver().off("visited", listener);
getHistoryObserver().off("visited", listener);
};
}).api(),
onVisitRemoved: new SingletonEventManager(context, "history.onVisitRemoved", fire => {
onVisitRemoved: new EventManager(context, "history.onVisitRemoved", fire => {
let listener = (event, data) => {
fire.sync(data);
};
getObserver().on("visitRemoved", listener);
getHistoryObserver().on("visitRemoved", listener);
return () => {
getObserver().off("visitRemoved", listener);
getHistoryObserver().off("visitRemoved", listener);
};
}).api(),
onTitleChanged: new SingletonEventManager(context, "history.onTitleChanged", fire => {
onTitleChanged: new EventManager(context, "history.onTitleChanged", fire => {
let listener = (event, data) => {
fire.sync(data);
};
getObserver().on("titleChanged", listener);
getHistoryObserver().on("titleChanged", listener);
return () => {
getObserver().off("titleChanged", listener);
getHistoryObserver().off("titleChanged", listener);
};
}).api(),
},

Просмотреть файл

@ -298,7 +298,7 @@ global.actionContextMenu = function(contextData) {
gMenuBuilder.buildActionContextMenu(contextData);
};
function getContexts(contextData) {
const getMenuContexts = contextData => {
let contexts = new Set();
if (contextData.inFrame) {
@ -355,7 +355,7 @@ function getContexts(contextData) {
}
return contexts;
}
};
function MenuItem(extension, createProperties, isRoot = false) {
this.extension = extension;
@ -546,7 +546,7 @@ MenuItem.prototype = {
},
enabledForContext(contextData) {
let contexts = getContexts(contextData);
let contexts = getMenuContexts(contextData);
if (!this.contexts.some(n => contexts.has(n))) {
return false;
}
@ -673,9 +673,10 @@ this.menusInternal = class extends ExtensionAPI {
}
},
onClicked: new SingletonEventManager(context, "menusInternal.onClicked", fire => {
onClicked: new EventManager(context, "menusInternal.onClicked", fire => {
let listener = (event, info, tab) => {
fire.async(info, tab);
context.withPendingBrowser(tab.linkedBrowser,
() => fire.sync(info, tab));
};
extension.on("webext-menu-menuitem-click", listener);

Просмотреть файл

@ -40,7 +40,7 @@ this.omnibox = class extends ExtensionAPI {
}
},
onInputStarted: new SingletonEventManager(context, "omnibox.onInputStarted", fire => {
onInputStarted: new EventManager(context, "omnibox.onInputStarted", fire => {
let listener = (eventName) => {
fire.sync();
};
@ -50,7 +50,7 @@ this.omnibox = class extends ExtensionAPI {
};
}).api(),
onInputCancelled: new SingletonEventManager(context, "omnibox.onInputCancelled", fire => {
onInputCancelled: new EventManager(context, "omnibox.onInputCancelled", fire => {
let listener = (eventName) => {
fire.sync();
};
@ -60,7 +60,7 @@ this.omnibox = class extends ExtensionAPI {
};
}).api(),
onInputEntered: new SingletonEventManager(context, "omnibox.onInputEntered", fire => {
onInputEntered: new EventManager(context, "omnibox.onInputEntered", fire => {
let listener = (eventName, text, disposition) => {
fire.sync(text, disposition);
};
@ -81,7 +81,7 @@ this.omnibox = class extends ExtensionAPI {
}
},
onInputChanged: new SingletonEventManager(context, "omnibox_internal.onInputChanged", fire => {
onInputChanged: new EventManager(context, "omnibox_internal.onInputChanged", fire => {
let listener = (eventName, text, id) => {
fire.sync(text, id);
};

Просмотреть файл

@ -232,7 +232,7 @@ this.pageAction = class extends ExtensionAPI {
// If the page action has a |popup| property, a panel is opened to
// that URL. Otherwise, a "click" event is emitted, and dispatched to
// the any click listeners in the add-on.
handleClick(window) {
async handleClick(window) {
TelemetryStopwatch.start(popupOpenTimingHistogram, this);
let tab = window.gBrowser.selectedTab;
let popupURL = this.tabContext.get(tab).popup;
@ -244,8 +244,9 @@ this.pageAction = class extends ExtensionAPI {
// If it has no popup URL defined, we dispatch a click event, but do not
// open a popup.
if (popupURL) {
new PanelPopup(this.extension, this.getButton(window), popupURL,
this.browserStyle);
let popup = new PanelPopup(this.extension, this.getButton(window),
popupURL, this.browserStyle);
await popup.contentReady;
TelemetryStopwatch.finish(popupOpenTimingHistogram, this);
} else {
TelemetryStopwatch.cancel(popupOpenTimingHistogram, this);
@ -268,9 +269,10 @@ this.pageAction = class extends ExtensionAPI {
return {
pageAction: {
onClicked: new SingletonEventManager(context, "pageAction.onClicked", fire => {
onClicked: new InputEventManager(context, "pageAction.onClicked", fire => {
let listener = (evt, tab) => {
fire.async(tabManager.convert(tab));
context.withPendingBrowser(tab.linkedBrowser, () =>
fire.sync(tabManager.convert(tab)));
};
pageAction.on("click", listener);

Просмотреть файл

@ -15,7 +15,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
const SS_ON_CLOSED_OBJECTS_CHANGED = "sessionstore-closed-objects-changed";
function getRecentlyClosed(maxResults, extension) {
const getRecentlyClosed = (maxResults, extension) => {
let recentlyClosed = [];
// Get closed windows
@ -39,9 +39,9 @@ function getRecentlyClosed(maxResults, extension) {
// Sort windows and tabs
recentlyClosed.sort((a, b) => b.lastModified - a.lastModified);
return recentlyClosed.slice(0, maxResults);
}
};
async function createSession(restored, extension, sessionId) {
const createSession = async function createSession(restored, extension, sessionId) {
if (!restored) {
throw new ExtensionError(`Could not restore object using sessionId ${sessionId}.`);
}
@ -53,7 +53,7 @@ async function createSession(restored, extension, sessionId) {
}
sessionObj.tab = extension.tabManager.convert(restored);
return sessionObj;
}
};
this.sessions = class extends ExtensionAPI {
getAPI(context) {
@ -127,7 +127,7 @@ this.sessions = class extends ExtensionAPI {
return createSession(session, extension, closedId);
},
onChanged: new SingletonEventManager(context, "sessions.onChanged", fire => {
onChanged: new EventManager(context, "sessions.onChanged", fire => {
let observer = () => {
fire.async();
};

Просмотреть файл

@ -100,7 +100,7 @@ this.tabs = class extends ExtensionAPI {
let self = {
tabs: {
onActivated: new SingletonEventManager(context, "tabs.onActivated", fire => {
onActivated: new EventManager(context, "tabs.onActivated", fire => {
let listener = (eventName, event) => {
fire.async(event);
};
@ -111,7 +111,7 @@ this.tabs = class extends ExtensionAPI {
};
}).api(),
onCreated: new SingletonEventManager(context, "tabs.onCreated", fire => {
onCreated: new EventManager(context, "tabs.onCreated", fire => {
let listener = (eventName, event) => {
fire.async(tabManager.convert(event.nativeTab, event.currentTab));
};
@ -128,7 +128,7 @@ this.tabs = class extends ExtensionAPI {
* the tabId in an array to match the API.
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
*/
onHighlighted: new SingletonEventManager(context, "tabs.onHighlighted", fire => {
onHighlighted: new EventManager(context, "tabs.onHighlighted", fire => {
let listener = (eventName, event) => {
fire.async({tabIds: [event.tabId], windowId: event.windowId});
};
@ -139,7 +139,7 @@ this.tabs = class extends ExtensionAPI {
};
}).api(),
onAttached: new SingletonEventManager(context, "tabs.onAttached", fire => {
onAttached: new EventManager(context, "tabs.onAttached", fire => {
let listener = (eventName, event) => {
fire.async(event.tabId, {newWindowId: event.newWindowId, newPosition: event.newPosition});
};
@ -150,7 +150,7 @@ this.tabs = class extends ExtensionAPI {
};
}).api(),
onDetached: new SingletonEventManager(context, "tabs.onDetached", fire => {
onDetached: new EventManager(context, "tabs.onDetached", fire => {
let listener = (eventName, event) => {
fire.async(event.tabId, {oldWindowId: event.oldWindowId, oldPosition: event.oldPosition});
};
@ -161,7 +161,7 @@ this.tabs = class extends ExtensionAPI {
};
}).api(),
onRemoved: new SingletonEventManager(context, "tabs.onRemoved", fire => {
onRemoved: new EventManager(context, "tabs.onRemoved", fire => {
let listener = (eventName, event) => {
fire.async(event.tabId, {windowId: event.windowId, isWindowClosing: event.isWindowClosing});
};
@ -172,11 +172,11 @@ this.tabs = class extends ExtensionAPI {
};
}).api(),
onReplaced: new SingletonEventManager(context, "tabs.onReplaced", fire => {
onReplaced: new EventManager(context, "tabs.onReplaced", fire => {
return () => {};
}).api(),
onMoved: new SingletonEventManager(context, "tabs.onMoved", fire => {
onMoved: new EventManager(context, "tabs.onMoved", fire => {
// There are certain circumstances where we need to ignore a move event.
//
// Namely, the first time the tab is moved after it's created, we need
@ -219,7 +219,7 @@ this.tabs = class extends ExtensionAPI {
};
}).api(),
onUpdated: new SingletonEventManager(context, "tabs.onUpdated", fire => {
onUpdated: new EventManager(context, "tabs.onUpdated", fire => {
const restricted = ["url", "favIconUrl", "title"];
function sanitize(extension, changeInfo) {
@ -679,7 +679,7 @@ this.tabs = class extends ExtensionAPI {
return Promise.resolve();
},
onZoomChange: new SingletonEventManager(context, "tabs.onZoomChange", fire => {
onZoomChange: new EventManager(context, "tabs.onZoomChange", fire => {
let getZoomLevel = browser => {
let {ZoomManager} = browser.ownerGlobal;

Просмотреть файл

@ -122,7 +122,7 @@ class WindowTracker extends WindowTrackerBase {
* @param {function} listener
* The listener function to call when a DOM event is received.
*/
global.WindowEventManager = class extends SingletonEventManager {
global.WindowEventManager = class extends EventManager {
constructor(context, name, event, listener) {
super(context, name, fire => {
let listener2 = listener.bind(null, fire);

Просмотреть файл

@ -17,9 +17,9 @@ var {
promiseObserved,
} = ExtensionUtils;
function onXULFrameLoaderCreated({target}) {
const onXULFrameLoaderCreated = ({target}) => {
target.messageManager.sendAsyncMessage("AllowScriptsToClose", {});
}
};
this.windows = class extends ExtensionAPI {
getAPI(context) {
@ -39,7 +39,7 @@ this.windows = class extends ExtensionAPI {
fire.async(windowTracker.getId(window));
}).api(),
onFocusChanged: new SingletonEventManager(context, "windows.onFocusChanged", fire => {
onFocusChanged: new EventManager(context, "windows.onFocusChanged", fire => {
// Keep track of the last windowId used to fire an onFocusChanged event
let lastOnFocusChangedWindowId;

Просмотреть файл

@ -1,6 +1,6 @@
button,
select,
input[type="checkbox"] + label::before {
button.browser-style,
select.browser-style,
.browser-style > input[type="checkbox"] + label::before {
border-radius: 4px;
}

Просмотреть файл

@ -1,14 +1,7 @@
/* stylelint-disable property-no-vendor-prefix */
/* stylelint-disable property-no-vendor-prefix */
/* Base */
button,
select,
option,
input {
-moz-appearance: none;
}
/* Variables */
/* Global */
html,
body {
background: transparent;
@ -28,10 +21,16 @@ body * {
text-align: start;
}
.browser-style {
-moz-appearance: none;
margin-bottom: 6px;
text-align: left;
}
/* stylelint-disable property-no-vendor-prefix */
/* Buttons */
button,
select {
button.browser-style,
select.browser-style {
background-color: #fbfbfb;
border: 1px solid #b1b1b1;
box-shadow: 0 0 0 0 transparent;
@ -43,7 +42,7 @@ select {
transition-property: box-shadow, border;
}
select {
select.browser-style {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==);
background-position: calc(100% - 4px) center;
background-repeat: no-repeat;
@ -51,17 +50,17 @@ select {
text-overflow: ellipsis;
}
label {
label.browser-style-label {
font: caption;
}
button::-moz-focus-inner {
button.browser-style::-moz-focus-inner {
border: 0;
outline: 0;
}
/* Dropdowns */
select {
select.browser-style {
background-color: #fbfbfb;
border: 1px solid #b1b1b1;
box-shadow: 0 0 0 0 transparent;
@ -73,7 +72,7 @@ select {
transition-property: box-shadow, border;
}
select {
select.browser-style {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==);
background-position: calc(100% - 4px) center;
background-repeat: no-repeat;
@ -81,75 +80,70 @@ select {
text-overflow: ellipsis;
}
select:-moz-focusring {
select.browser-style:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
select:-moz-focusring * {
select.browser-style:-moz-focusring * {
color: #000;
text-shadow: none;
}
button.hover,
select.hover {
button.browser-style.hover,
select.browser-style.hover {
background-color: #ebebeb;
border: 1px solid #b1b1b1;
}
button.pressed,
select.pressed {
button.browser-style.pressed,
select.browser-style.pressed {
background-color: #d4d4d4;
border: 1px solid #858585;
}
button.disabled,
select.disabled {
button.browser-style.disabled,
select.browser-style.disabled {
color: #999;
opacity: .5;
}
button.focused,
select.focused {
button.browser-style.focused,
select.browser-style.focused {
border-color: #fff;
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
}
button.default {
button.browser-style.default {
background-color: #0996f8;
border-color: #0670cc;
color: #fff;
}
button.default.hover {
button.browser-style.default.hover {
background-color: #0670cc;
border-color: #005bab;
}
button.default.pressed {
button.browser-style.default.pressed {
background-color: #005bab;
border-color: #004480;
}
button.default.focused {
button.browser-style.default.focused {
border-color: #fff;
}
/* Radio Buttons */
.radioItem {
margin-bottom: 6px;
text-align: left;
}
input[type="radio"] {
.browser-style > input[type="radio"] {
display: none;
}
input[type="radio"] + label {
.browser-style > input[type="radio"] + label {
-moz-user-select: none;
}
input[type="radio"] + label::before {
.browser-style > input[type="radio"] + label::before {
background-color: #fff;
background-position: center;
border: 1px solid #b1b1b1;
@ -162,67 +156,62 @@ input[type="radio"] + label::before {
width: 16px;
}
input[type="radio"]:hover + label::before,
.radioItem.hover input[type="radio"]:not(active) + label::before {
.browser-style > input[type="radio"]:hover + label::before,
.browser-style.hover > input[type="radio"]:not(active) + label::before {
background-color: #fbfbfb;
border-color: #b1b1b1;
}
input[type="radio"]:hover:active + label::before,
.radioItem.pressed input[type="radio"]:not(active) + label::before {
.browser-style > input[type="radio"]:hover:active + label::before,
.browser-style.pressed > input[type="radio"]:not(active) + label::before {
background-color: #ebebeb;
border-color: #858585;
}
input[type="radio"]:checked + label::before {
.browser-style > input[type="radio"]:checked + label::before {
background-color: #0996f8;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8Y2lyY2xlIGN4PSI4IiBjeT0iOCIgcj0iNCIgZmlsbD0iI2ZmZiIgLz4KPC9zdmc+Cg==);
border-color: #0670cc;
}
input[type="radio"]:checked:hover + label::before,
.radioItem.hover input[type="radio"]:checked:not(active) + label::before {
.browser-style > input[type="radio"]:checked:hover + label::before,
.browser-style.hover > input[type="radio"]:checked:not(active) + label::before {
background-color: #0670cc;
border-color: #005bab;
}
input[type="radio"]:checked:hover:active + label::before,
.radioItem.pressed input[type="radio"]:checked:not(active) + label::before {
.browser-style > input[type="radio"]:checked:hover:active + label::before,
.browser-style.pressed > input[type="radio"]:checked:not(active) + label::before {
background-color: #005bab;
border-color: #004480;
}
.radioItem.disabled input[type="radio"] + label,
.radioItem.disabled input[type="radio"]:hover + label,
.radioItem.disabled input[type="radio"]:hover:active + label {
.browser-style.disabled > input[type="radio"] + label,
.browser-style.disabled > input[type="radio"]:hover + label,
.browser-style.disabled > input[type="radio"]:hover:active + label {
color: #999;
opacity: .5;
}
.radioItem.focused input[type="radio"] + label::before {
.browser-style.focused > input[type="radio"] + label::before {
border-color: #0996f8;
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
}
.radioItem.focused input[type="radio"]:checked + label::before {
.browser-style.focused > input[type="radio"]:checked + label::before {
border-color: #fff;
}
/* Checkboxes */
.checkboxItem {
margin-bottom: 6px;
text-align: left;
}
input[type="checkbox"] {
.browser-style > input[type="checkbox"] {
display: none;
}
input[type="checkbox"] + label {
.browser-style > input[type="checkbox"] + label {
-moz-user-select: none;
}
input[type="checkbox"] + label::before {
.browser-style > input[type="checkbox"] + label::before {
background-color: #fff;
background-position: center;
border: 1px solid #b1b1b1;
@ -234,54 +223,54 @@ input[type="checkbox"] + label::before {
width: 16px;
}
input[type="checkbox"]:hover + label::before,
.checkboxItem.hover input[type="checkbox"]:not(active) + label::before {
.browser-style > input[type="checkbox"]:hover + label::before,
.browser-style.hover > input[type="checkbox"]:not(active) + label::before {
background-color: #fbfbfb;
border-color: #b1b1b1;
}
input[type="checkbox"]:hover:active + label::before,
.checkboxItem.pressed input[type="checkbox"]:not(active) + label::before {
.browser-style > input[type="checkbox"]:hover:active + label::before,
.browser-style.pressed > input[type="checkbox"]:not(active) + label::before {
background-color: #ebebeb;
border-color: #858585;
}
input[type="checkbox"]:checked + label::before {
.browser-style > input[type="checkbox"]:checked + label::before {
background-color: #0996f8;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNNy43LDEyLjkgQzcuNCwxMy4zIDYuOCwxMy40IDYuNCwxMyBMMy4yLDkuOCBDMi44LDkuNCAyLjgsOC42IDMuMiw4LjIgQzMuNiw3LjggNC40LDcuOCA0LjgsOC4yIEw2LjksMTAuMyBMMTEuMSw0LjQgQzExLjUsMy45IDEyLjIsMy44IDEyLjcsNC4xIEMxMy4yLDQuNSAxMy4zLDUuMiAxMyw1LjcgTDcuNywxMi45IEw3LjcsMTIuOSBaIiBmaWxsPSIjZmZmIiAvPgo8L3N2Zz4K);
border-color: #0670cc;
}
input[type="checkbox"]:checked:hover + label::before,
.checkboxItem.hover input[type="checkbox"]:checked:not(active) + label::before {
.browser-style > input[type="checkbox"]:checked:hover + label::before,
.browser-style.hover > input[type="checkbox"]:checked:not(active) + label::before {
background-color: #0670cc;
border-color: #005bab;
}
input[type="checkbox"]:checked:hover:active + label::before,
.checkboxItem.pressed input[type="checkbox"]:checked:not(active) + label::before {
.browser-style > input[type="checkbox"]:checked:hover:active + label::before,
.browser-style.pressed > input[type="checkbox"]:checked:not(active) + label::before {
background-color: #005bab;
border-color: #004480;
}
.checkboxItem.disabled input[type="checkbox"] + label,
.checkboxItem.disabled input[type="checkbox"]:hover + label,
.checkboxItem.disabled input[type="checkbox"]:hover:active + label {
.browser-style.disabled > input[type="checkbox"] + label,
.browser-style.disabled > input[type="checkbox"]:hover + label,
.browser-style.disabled > input[type="checkbox"]:hover:active + label {
color: #999;
opacity: .5;
}
.checkboxItem.focused input[type="checkbox"] + label::before {
.browser-style.focused > input[type="checkbox"] + label::before {
border-color: #0996f8;
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
}
.checkboxItem.focused input[type="checkbox"]:checked + label::before {
.browser-style.focused > input[type="checkbox"]:checked + label::before {
border-color: #fff;
}
/* Expander Button */
button.expander {
button.browser-style.expander {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNOCwxMkwzLDcsNCw2bDQsNCw0LTQsMSwxWiIgZmlsbD0iIzZBNkE2QSIgLz4KPC9zdmc+Cg==);
background-position: center;
background-repeat: no-repeat;
@ -291,36 +280,36 @@ button.expander {
}
/* Interactive States */
button:hover:not(.pressed):not(.disabled):not(.focused),
select:hover:not(.pressed):not(.disabled):not(.focused) {
button.browser-style:hover:not(.pressed):not(.disabled):not(.focused),
select.browser-style:hover:not(.pressed):not(.disabled):not(.focused) {
background-color: #ebebeb;
border: 1px solid #b1b1b1;
}
button:hover:active:not(.hover):not(.disabled):not(.focused),
select:hover:active:not(.hover):not(.disabled):not(.focused) {
button.browser-style:hover:active:not(.hover):not(.disabled):not(.focused),
select.browser-style:hover:active:not(.hover):not(.disabled):not(.focused) {
background-color: #d4d4d4;
border: 1px solid #858585;
}
button.default:hover:not(.pressed):not(.disabled):not(.focused) {
button.browser-style.default:hover:not(.pressed):not(.disabled):not(.focused) {
background-color: #0670cc;
border-color: #005bab;
}
button.default:hover:active:not(.hover):not(.disabled):not(.focused) {
button.browser-style.default:hover:active:not(.hover):not(.disabled):not(.focused) {
background-color: #005bab;
border-color: #004480;
}
button:focus:not(.disabled) {
button.browser-style:focus:not(.disabled) {
border-color: #fff !important;
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
}
/* Fields */
input[type="text"],
textarea {
.browser-style > input[type="text"],
textarea.browser-style {
background-color: #fff;
border: 1px solid #b1b1b1;
box-shadow: 0 0 0 0 rgba(97, 181, 255, 0);
@ -330,37 +319,37 @@ textarea {
transition-property: box-shadow;
}
input[type="text"] {
.browser-style > input[type="text"] {
height: 24px;
}
input[type="text"].hover,
textarea.hover {
.browser-style > input[type="text"].hover,
textarea.browser-style.hover {
border: 1px solid #858585;
}
input[type="text"].disabled,
textarea.disabled {
.browser-style > input[type="text"].disabled,
textarea.browser-style.disabled {
color: #999;
opacity: .5;
}
input[type="text"].focused,
textarea.focused {
.browser-style > input[type="text"].focused,
textarea.browser-style.focused {
border-color: #0996f8;
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
}
/* Interactive States */
input[type="text"]:not(disabled):hover,
textarea:not(disabled):hover {
.browser-style > input[type="text"]:not(disabled):hover,
textarea.browser-style:not(disabled):hover {
border: 1px solid #858585;
}
input[type="text"]:focus,
input[type="text"]:focus:hover,
textarea:focus,
textarea:focus:hover {
.browser-style > input[type="text"]:focus,
.browser-style > input[type="text"]:focus:hover,
textarea.browser-style:focus,
textarea.browser-style:focus:hover {
border-color: #0996f8;
box-shadow: 0 0 0 2px rgba(97, 181, 255, 0.75);
}
@ -470,7 +459,7 @@ textarea:focus:hover {
}
.panel-formElements-item input[type="text"],
.panel-formElements-item select {
.panel-formElements-item select.browser-style {
flex-grow: 1;
}
@ -556,12 +545,12 @@ textarea:focus:hover {
background-color: rgba(0, 0, 0, 0.1);
}
.panel-section-tabs-button.selected {
.panel-section-tabs-button.select.browser-styleed {
box-shadow: 0 -1px 0 #0670cc inset, 0 -4px 0 #0996f8 inset;
color: #0996f8;
}
.panel-section-tabs-button.selected:hover {
.panel-section-tabs-button.select.browser-styleed:hover {
color: #0670cc;
}

Просмотреть файл

@ -143,6 +143,7 @@ skip-if = debug || asan # Bug 1354681
[browser_ext_themes_validation.js]
[browser_ext_url_overrides_newtab.js]
[browser_ext_url_overrides_home.js]
[browser_ext_user_events.js]
[browser_ext_webRequest.js]
[browser_ext_webNavigation_frameId0.js]
[browser_ext_webNavigation_getFrames.js]
@ -157,7 +158,6 @@ tags = fullscreen
[browser_ext_windows_create_tabId.js]
[browser_ext_windows_create_url.js]
[browser_ext_windows_events.js]
skip-if = os == 'mac' && debug # bug 1308068
[browser_ext_windows_size.js]
skip-if = os == 'mac' # Fails when windows are randomly opened in fullscreen mode
[browser_ext_windows_update.js]

Просмотреть файл

@ -11,15 +11,46 @@ async function testOptionsBrowserStyle(optionsUI, assertMessage) {
browser.test.notifyFail("options-ui-browser_style");
}
let style = window.getComputedStyle(document.getElementById("button"));
let buttonBackgroundColor = style.backgroundColor;
let browserStyleBackgroundColor = "rgb(9, 150, 248)";
if (!("browser_style" in optionsUI) || optionsUI.browser_style) {
browser.test.assertEq(browserStyleBackgroundColor, buttonBackgroundColor, assertMessage);
} else {
browser.test.assertTrue(browserStyleBackgroundColor !== buttonBackgroundColor, assertMessage);
let browserStyle = !("browser_style" in optionsUI) || optionsUI.browser_style;
function verifyButton(buttonElement, expected) {
let buttonStyle = window.getComputedStyle(buttonElement);
let buttonBackgroundColor = buttonStyle.backgroundColor;
if (browserStyle && expected.hasBrowserStyleClass) {
browser.test.assertEq("rgb(9, 150, 248)", buttonBackgroundColor, assertMessage);
} else {
browser.test.assertTrue(buttonBackgroundColor !== "rgb(9, 150, 248)", assertMessage);
}
}
function verifyCheckboxOrRadio(type, element, expected) {
let style = window.getComputedStyle(element);
if (browserStyle && expected.hasBrowserStyleClass) {
browser.test.assertEq("none", style.display, `Expected ${type} item to be hidden`);
} else {
browser.test.assertTrue(style.display != "none", `Expected ${type} item to be visible`);
}
}
let normalButton = document.getElementById("normalButton");
let browserStyleButton = document.getElementById("browserStyleButton");
verifyButton(normalButton, {hasBrowserStyleClass: false});
verifyButton(browserStyleButton, {hasBrowserStyleClass: true});
let normalCheckbox1 = document.getElementById("normalCheckbox1");
let normalCheckbox2 = document.getElementById("normalCheckbox2");
let browserStyleCheckbox = document.getElementById("browserStyleCheckbox");
verifyCheckboxOrRadio("checkbox", normalCheckbox1, {hasBrowserStyleClass: false});
verifyCheckboxOrRadio("checkbox", normalCheckbox2, {hasBrowserStyleClass: false});
verifyCheckboxOrRadio("checkbox", browserStyleCheckbox, {hasBrowserStyleClass: true});
let normalRadio1 = document.getElementById("normalRadio1");
let normalRadio2 = document.getElementById("normalRadio2");
let browserStyleRadio = document.getElementById("browserStyleRadio");
verifyCheckboxOrRadio("radio", normalRadio1, {hasBrowserStyleClass: false});
verifyCheckboxOrRadio("radio", normalRadio2, {hasBrowserStyleClass: false});
verifyCheckboxOrRadio("radio", browserStyleRadio, {hasBrowserStyleClass: true});
browser.test.notifyPass("options-ui-browser_style");
});
browser.test.sendMessage("options-ui-ready");
@ -36,7 +67,21 @@ async function testOptionsBrowserStyle(optionsUI, assertMessage) {
"options.html": `
<!DOCTYPE html>
<html>
<button id="button" name="button" class="default">Default</button>
<button id="normalButton" name="button" class="default">Default</button>
<button id="browserStyleButton" name="button" class="browser-style default">Default</button>
<input id="normalCheckbox1" type="checkbox"/>
<input id="normalCheckbox2" type="checkbox"/><label>Checkbox</label>
<div class="browser-style">
<input id="browserStyleCheckbox" type="checkbox"><label for="browserStyleCheckbox">Checkbox</label>
</div>
<input id="normalRadio1" type="radio"/>
<input id="normalRadio2" type="radio"/><label>Radio</label>
<div class="browser-style">
<input id="browserStyleRadio" checked="" type="radio"><label for="browserStyleRadio">Radio</label>
</div>
<script src="options.js" type="text/javascript"></script>
</html>`,
"options.js": optionsScript,
@ -53,7 +98,6 @@ async function testOptionsBrowserStyle(optionsUI, assertMessage) {
extension.sendMessage("check-style", optionsUI, assertMessage);
await extension.awaitFinish("options-ui-browser_style");
await BrowserTestUtils.removeTab(tab);
await extension.unload();

Просмотреть файл

@ -33,7 +33,7 @@ async function testSidebarBrowserStyle(sidebarAction, assertMessage) {
"panel.html": `
<!DOCTYPE html>
<html>
<button id="button" name="button" class="default">Default</button>
<button id="button" name="button" class="browser-style default">Default</button>
<script src="panel.js" type="text/javascript"></script>
</html>`,
"panel.js": sidebarScript,

Просмотреть файл

@ -0,0 +1,70 @@
"use strict";
// Test that different types of events are all considered
// "handling user input".
add_task(async function testSources() {
let extension = ExtensionTestUtils.loadExtension({
async background() {
async function request() {
try {
let result = await browser.permissions.request({
permissions: ["cookies"],
});
browser.test.sendMessage("request", {success: true, result});
} catch (err) {
browser.test.sendMessage("request", {success: false, errmsg: err.message});
}
}
let tabs = await browser.tabs.query({active: true, currentWindow: true});
await browser.pageAction.show(tabs[0].id);
browser.test.sendMessage("page-action-shown");
browser.pageAction.onClicked.addListener(request);
browser.browserAction.onClicked.addListener(request);
browser.contextMenus.create({
id: "menu",
title: "test user events",
contexts: ["page"],
});
browser.contextMenus.onClicked.addListener(request);
},
manifest: {
browser_action: {default_title: "test"},
page_action: {default_title: "test"},
permissions: ["contextMenus"],
optional_permissions: ["cookies"],
},
});
async function check(what) {
let result = await extension.awaitMessage("request");
ok(result.success, `request() did not throw when called from ${what}`);
is(result.result, true, `request() succeeded when called from ${what}`);
}
await extension.startup();
await extension.awaitMessage("page-action-shown");
clickPageAction(extension);
await check("page action click");
clickBrowserAction(extension);
await check("browser action click");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
gBrowser.selectedTab = tab;
let menu = await openContextMenu("body");
let items = menu.getElementsByAttribute("label", "test user events");
is(items.length, 1, "Found context menu item");
EventUtils.synthesizeMouseAtCenter(items[0], {});
await check("context menu click");
await BrowserTestUtils.removeTab(tab);
await extension.unload();
});

Просмотреть файл

@ -16,27 +16,19 @@ add_task(async function testWindowsEvents() {
browser.test.sendMessage("window-created", window.id);
});
let lastWindowId, os;
browser.windows.onFocusChanged.addListener(async windowId => {
browser.test.log(`onFocusChange: windowId=${windowId} lastWindowId=${lastWindowId}`);
let lastWindowId;
browser.windows.onFocusChanged.addListener(async eventWindowId => {
browser.test.log(`onFocusChange: windowId=${eventWindowId} lastWindowId=${lastWindowId}`);
if (windowId === browser.windows.WINDOW_ID_NONE && os === "linux") {
browser.test.log("Ignoring a superfluous WINDOW_ID_NONE (blur) event on Linux");
return;
}
browser.test.assertTrue(lastWindowId !== windowId,
browser.test.assertTrue(lastWindowId !== eventWindowId,
"onFocusChanged fired once for the given window");
lastWindowId = windowId;
lastWindowId = eventWindowId;
browser.test.assertTrue(Number.isInteger(windowId),
browser.test.assertTrue(Number.isInteger(eventWindowId),
"windowId is an integer");
let window = await browser.windows.getLastFocused();
browser.test.assertEq(windowId, window.id,
"Last focused window has the correct id");
browser.test.sendMessage(`window-focus-changed`, window.id);
browser.test.sendMessage("window-focus-changed", {winId: eventWindowId, lastFocusedWindowId: window.id});
});
browser.windows.onRemoved.addListener(windowId => {
@ -44,22 +36,30 @@ add_task(async function testWindowsEvents() {
browser.test.assertTrue(Number.isInteger(windowId),
"windowId is an integer");
browser.test.sendMessage(`window-removed`, windowId);
browser.test.sendMessage("window-removed", windowId);
browser.test.notifyPass("windows.events");
});
browser.runtime.getPlatformInfo(info => {
os = info.os;
browser.test.sendMessage("ready");
});
browser.test.sendMessage("ready", browser.windows.WINDOW_ID_NONE);
}
let extension = ExtensionTestUtils.loadExtension({
background: `(${background})()`,
background,
});
await extension.startup();
await extension.awaitMessage("ready");
const WINDOW_ID_NONE = await extension.awaitMessage("ready");
async function awaitFocusChanged() {
let windowInfo = await extension.awaitMessage("window-focus-changed");
if (windowInfo.winId === WINDOW_ID_NONE) {
info("Ignoring a superfluous WINDOW_ID_NONE (blur) event.");
windowInfo = await extension.awaitMessage("window-focus-changed");
}
is(windowInfo.winId, windowInfo.lastFocusedWindowId,
"Last focused window has the correct id");
return windowInfo.winId;
}
let {Management: {global: {windowTracker}}} = Cu.import("resource://gre/modules/Extension.jsm", {});
@ -67,7 +67,7 @@ add_task(async function testWindowsEvents() {
let currentWindowId = windowTracker.getId(currentWindow);
info(`Current window ID: ${currentWindowId}`);
info(`Create browser window 1`);
info("Create browser window 1");
let win1 = await BrowserTestUtils.openNewBrowserWindow();
let win1Id = await extension.awaitMessage("window-created");
info(`Window 1 ID: ${win1Id}`);
@ -76,40 +76,40 @@ add_task(async function testWindowsEvents() {
// it a try.
win1.focus();
let winId = await extension.awaitMessage(`window-focus-changed`);
let winId = await awaitFocusChanged();
is(winId, win1Id, "Got focus change event for the correct window ID.");
info(`Create browser window 2`);
info("Create browser window 2");
let win2 = await BrowserTestUtils.openNewBrowserWindow();
let win2Id = await extension.awaitMessage("window-created");
info(`Window 2 ID: ${win2Id}`);
win2.focus();
winId = await extension.awaitMessage(`window-focus-changed`);
winId = await awaitFocusChanged();
is(winId, win2Id, "Got focus change event for the correct window ID.");
info(`Focus browser window 1`);
info("Focus browser window 1");
await focusWindow(win1);
winId = await extension.awaitMessage(`window-focus-changed`);
winId = await awaitFocusChanged();
is(winId, win1Id, "Got focus change event for the correct window ID.");
info(`Close browser window 2`);
info("Close browser window 2");
await BrowserTestUtils.closeWindow(win2);
winId = await extension.awaitMessage(`window-removed`);
winId = await extension.awaitMessage("window-removed");
is(winId, win2Id, "Got removed event for the correct window ID.");
info(`Close browser window 1`);
info("Close browser window 1");
await BrowserTestUtils.closeWindow(win1);
currentWindow.focus();
winId = await extension.awaitMessage(`window-removed`);
winId = await extension.awaitMessage("window-removed");
is(winId, win1Id, "Got removed event for the correct window ID.");
winId = await extension.awaitMessage(`window-focus-changed`);
winId = await awaitFocusChanged();
is(winId, currentWindowId, "Got focus change event for the correct window ID.");
await extension.awaitFinish("windows.events");

Просмотреть файл

@ -664,6 +664,10 @@ this.PlacesUIUtils = {
getViewForNode: function PUIU_getViewForNode(aNode) {
let node = aNode;
if (node.localName == "panelview" && node._placesView) {
return node._placesView;
}
// The view for a <menu> of which its associated menupopup is a places
// view, is the menupopup.
if (node.localName == "menu" && !node._placesNode &&
@ -1010,12 +1014,10 @@ this.PlacesUIUtils = {
* @param aEvent
* The DOM mouse/key event with modifier keys set that track the
* user's preferred destination window or tab.
* @param aView
* The controller associated with aNode.
*/
openNodeWithEvent:
function PUIU_openNodeWithEvent(aNode, aEvent, aView) {
let window = aView.ownerWindow;
function PUIU_openNodeWithEvent(aNode, aEvent) {
let window = aEvent.target.ownerGlobal;
this._openNodeIn(aNode, window.whereToOpenLink(aEvent, false, true), window);
},

Просмотреть файл

@ -12,10 +12,14 @@ Components.utils.import("resource://gre/modules/Services.jsm");
* The base view implements everything that's common to the toolbar and
* menu views.
*/
function PlacesViewBase(aPlace, aOptions) {
this.place = aPlace;
function PlacesViewBase(aPlace, aOptions = {}) {
if ("rootElt" in aOptions)
this._rootElt = aOptions.rootElt;
if ("viewElt" in aOptions)
this._viewElt = aOptions.viewElt;
this.options = aOptions;
this._controller = new PlacesController(this);
this.place = aPlace;
this._viewElt.controllers.appendController(this._controller);
}
@ -233,6 +237,9 @@ PlacesViewBase.prototype = {
},
_cleanPopup: function PVB_cleanPopup(aPopup, aDelay) {
// Ensure markers are here when `invalidateContainer` is called before the
// popup is shown, which may the case for panelviews, for example.
this._ensureMarkers(aPopup);
// Remove Places nodes from the popup.
let child = aPopup._startMarker;
while (child.nextSibling != aPopup._endMarker) {
@ -317,8 +324,8 @@ PlacesViewBase.prototype = {
}
},
_createMenuItemForPlacesNode:
function PVB__createMenuItemForPlacesNode(aPlacesNode) {
_createDOMNodeForPlacesNode:
function PVB__createDOMNodeForPlacesNode(aPlacesNode) {
this._domNodes.delete(aPlacesNode);
let element;
@ -392,7 +399,7 @@ PlacesViewBase.prototype = {
_insertNewItemToPopup:
function PVB__insertNewItemToPopup(aNewChild, aPopup, aBefore) {
let element = this._createMenuItemForPlacesNode(aNewChild);
let element = this._createDOMNodeForPlacesNode(aNewChild);
let before = aBefore || aPopup._endMarker;
if (element.localName == "menuitem" || element.localName == "menu") {
@ -716,12 +723,23 @@ PlacesViewBase.prototype = {
}, Components.utils.reportError);
},
/**
* Checks whether the popup associated with the provided element is open.
* This method may be overridden by classes that extend this base class.
*
* @param {nsIDOMElement} elt
* @return {Boolean}
*/
_isPopupOpen(elt) {
return !!elt.parentNode.open;
},
invalidateContainer: function PVB_invalidateContainer(aPlacesNode) {
let elt = this._getDOMNodeForPlacesNode(aPlacesNode);
elt._built = false;
// If the menupopup is open we should live-update it.
if (elt.parentNode.open)
if (this._isPopupOpen(elt))
this._rebuildPopup(elt);
},
@ -855,7 +873,7 @@ PlacesViewBase.prototype = {
// _endMarker is a DOM node that lives after places nodes, specified with
// the 'insertionPoint' option or will be a hidden menuseparator.
let node = ("insertionPoint" in this.options) ?
let node = this.options.insertionPoint ?
aPopup.querySelector(this.options.insertionPoint) : null;
if (node) {
aPopup._endMarker = node;
@ -912,14 +930,14 @@ PlacesViewBase.prototype = {
},
_addEventListeners:
function PVB__addEventListeners(aObject, aEventNames, aCapturing) {
function PVB__addEventListeners(aObject, aEventNames, aCapturing = false) {
for (let i = 0; i < aEventNames.length; i++) {
aObject.addEventListener(aEventNames[i], this, aCapturing);
}
},
_removeEventListeners:
function PVB__removeEventListeners(aObject, aEventNames, aCapturing) {
function PVB__removeEventListeners(aObject, aEventNames, aCapturing = false) {
for (let i = 0; i < aEventNames.length; i++) {
aObject.removeEventListener(aEventNames[i], this, aCapturing);
}
@ -1958,3 +1976,196 @@ PlacesPanelMenuView.prototype = {
}
}
};
class PlacesPanelview extends PlacesViewBase {
constructor(container, panelview, place, options = {}) {
options.rootElt = container;
options.viewElt = panelview;
super(place, options);
this._viewElt._placesView = this;
// We're simulating a popup show, because a panelview may only be shown when
// its containing popup is already shown.
this._onPopupShowing({ originalTarget: this._viewElt });
this._addEventListeners(window, ["unload"]);
this._rootElt.setAttribute("context", "placesContext");
}
get events() {
if (this._events)
return this._events;
return this._events = ["command", "destructed", "dragend", "dragstart",
"ViewHiding", "ViewShowing", "ViewShown"];
}
get panel() {
return this.panelMultiView.parentNode;
}
get panelMultiView() {
return this._viewElt.panelMultiView;
}
handleEvent(event) {
switch (event.type) {
case "command":
this._onCommand(event);
break;
case "destructed":
this._onDestructed(event);
break;
case "dragend":
this._onDragEnd(event);
break;
case "dragstart":
this._onDragStart(event);
break;
case "unload":
this.uninit(event);
break;
case "ViewHiding":
this._onPopupHidden(event);
break;
case "ViewShowing":
this._onPopupShowing(event);
break;
case "ViewShown":
this._onViewShown(event);
break;
}
}
_onCommand(event) {
let button = event.originalTarget;
if (!button._placesNode)
return;
PlacesUIUtils.openNodeWithEvent(button._placesNode, event);
}
_onDestructed(event) {
// The panelmultiview is ephemeral, so let's keep an eye out when the root
// element is showing again.
this._removeEventListeners(event.target, this.events);
this._addEventListeners(this._viewElt, ["ViewShowing"]);
}
_onDragEnd() {
this._draggedElt = null;
}
_onDragStart(event) {
let draggedElt = event.originalTarget;
if (draggedElt.parentNode != this._rootElt || !draggedElt._placesNode)
return;
// Activate the view and cache the dragged element.
this._draggedElt = draggedElt._placesNode;
this._rootElt.focus();
this._controller.setDataTransfer(event);
event.stopPropagation();
}
uninit(event) {
this._removeEventListeners(this.panelMultiView, this.events);
this._removeEventListeners(this._viewElt, ["ViewShowing"]);
this._removeEventListeners(window, ["unload"]);
super.uninit(event);
}
_createDOMNodeForPlacesNode(placesNode) {
this._domNodes.delete(placesNode);
let element;
let type = placesNode.type;
if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
element = document.createElement("toolbarseparator");
} else {
if (type != Ci.nsINavHistoryResultNode.RESULT_TYPE_URI)
throw "Unexpected node";
element = document.createElement("toolbarbutton");
element.classList.add("subviewbutton", "subviewbutton-iconic", "bookmark-item");
element.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(placesNode.uri));
element.setAttribute("label", PlacesUIUtils.getBestTitle(placesNode));
let icon = placesNode.icon;
if (icon)
element.setAttribute("image", icon);
}
element._placesNode = placesNode;
if (!this._domNodes.has(placesNode))
this._domNodes.set(placesNode, element);
return element;
}
_setEmptyPopupStatus(panelview, empty = false) {
if (!panelview._emptyMenuitem) {
let label = PlacesUIUtils.getString("bookmarksMenuEmptyFolder");
panelview._emptyMenuitem = document.createElement("toolbarbutton");
panelview._emptyMenuitem.setAttribute("label", label);
panelview._emptyMenuitem.setAttribute("disabled", true);
panelview._emptyMenuitem.className = "subviewbutton";
if (typeof this.options.extraClasses.entry == "string")
panelview._emptyMenuitem.classList.add(this.options.extraClasses.entry);
}
if (empty) {
panelview.setAttribute("emptyplacesresult", "true");
// Don't add the menuitem if there is static content.
if (!panelview._startMarker.previousSibling &&
!panelview._endMarker.nextSibling)
panelview.insertBefore(panelview._emptyMenuitem, panelview._endMarker);
} else {
panelview.removeAttribute("emptyplacesresult");
try {
panelview.removeChild(panelview._emptyMenuitem);
} catch (ex) {}
}
}
_isPopupOpen() {
return this.panel.state == "open" && this.panelMultiView.current == this._viewElt;
}
_onPopupHidden(event) {
let panelview = event.originalTarget;
let placesNode = panelview._placesNode;
// Avoid handling ViewHiding of inner views
if (placesNode && PlacesUIUtils.getViewForNode(panelview) == this) {
// UI performance: folder queries are cheap, keep the resultnode open
// so we don't rebuild its contents whenever the popup is reopened.
// Though, we want to always close feed containers so their expiration
// status will be checked at next opening.
if (!PlacesUtils.nodeIsFolder(placesNode) ||
this.controller.hasCachedLivemarkInfo(placesNode)) {
placesNode.containerOpen = false;
}
}
}
_onPopupShowing(event) {
// If the event came from the root element, this is a sign that the panelmultiview
// was just instantiated (see `_onDestructed` above) or this is the first time
// we ever get here.
if (event.originalTarget == this._viewElt) {
this._removeEventListeners(this._viewElt, ["ViewShowing"]);
// Start listening for events from all panels inside the panelmultiview.
this._addEventListeners(this.panelMultiView, this.events);
}
super._onPopupShowing(event);
}
_onViewShown(event) {
if (event.originalTarget != this._viewElt)
return;
// Because PanelMultiView reparents the panelview internally, the controller
// may get lost. In that case we'll append it again, because we certainly
// need it later!
if (!this.controllers.getControllerCount() && this._controller)
this.controllers.appendController(this._controller);
}
}

Просмотреть файл

@ -1365,7 +1365,7 @@ var ContentTree = {
openSelectedNode: function CT_openSelectedNode(aEvent) {
let view = this.view;
PlacesUIUtils.openNodeWithEvent(view.selectedNode, aEvent, view);
PlacesUIUtils.openNodeWithEvent(view.selectedNode, aEvent);
},
onClick: function CT_onClick(aEvent) {

Просмотреть файл

@ -52,17 +52,15 @@ var SidebarUtils = {
// do this *before* attempting to load the link since openURL uses
// selection as an indication of which link to load.
tbo.view.selection.select(cell.row);
PlacesUIUtils.openNodeWithEvent(aTree.selectedNode, aEvent, aTree);
PlacesUIUtils.openNodeWithEvent(aTree.selectedNode, aEvent);
}
},
handleTreeKeyPress: function SU_handleTreeKeyPress(aEvent) {
// XXX Bug 627901: Post Fx4, this method should take a tree parameter.
let tree = aEvent.target;
let node = tree.selectedNode;
let node = aEvent.target.selectedNode;
if (node) {
if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN)
PlacesUIUtils.openNodeWithEvent(node, aEvent, tree);
PlacesUIUtils.openNodeWithEvent(node, aEvent);
}
},

Просмотреть файл

@ -43,7 +43,7 @@ add_task(async function() {
await promiseClipboard(populate, PlacesUtils.TYPE_X_MOZ_PLACE);
focusTag(PlacesOrganizer);
PlacesOrganizer._places.controller.paste();
await PlacesOrganizer._places.controller.paste();
// re-focus the history again
PlacesOrganizer.selectLeftPaneQuery("History");

Просмотреть файл

@ -54,7 +54,7 @@ add_task(async function() {
info("Selecting UnfiledBookmarks in the left pane");
PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
info("Pasting clipboard");
ContentTree.view.controller.paste();
await ContentTree.view.controller.paste();
await selectBookmarksIn(organizer, bookmarks, "UnfiledBookmarks");
});

Просмотреть файл

@ -21,7 +21,7 @@ add_task(async function copy_toolbar_shortcut() {
PlacesUtils.TYPE_X_MOZ_PLACE);
library.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
library.ContentTree.view.controller.paste();
await library.ContentTree.view.controller.paste();
let toolbarCopyNode = library.ContentTree.view.view.nodeForTreeIndex(0);
is(toolbarCopyNode.type,
@ -44,7 +44,7 @@ add_task(async function copy_history_query() {
PlacesUtils.TYPE_X_MOZ_PLACE);
library.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
library.ContentTree.view.controller.paste();
await library.ContentTree.view.controller.paste();
let historyCopyNode = library.ContentTree.view.view.nodeForTreeIndex(0);
is(historyCopyNode.type,

Просмотреть файл

@ -34,24 +34,27 @@ add_task(async function test() {
* @param aMimeType
* The mime type to use for the drop operation.
*/
let simulateDragDrop = function(aEffect, aMimeType) {
const uriSpec = "http://www.mozilla.org/D1995729-A152-4e30-8329-469B01F30AA7";
let uri = makeURI(uriSpec);
let simulateDragDrop = async function(aEffect, aMimeType) {
const url = "http://www.mozilla.org/D1995729-A152-4e30-8329-469B01F30AA7";
let promiseItemAddedNotification = promiseBookmarksNotification(
"onItemAdded", (itemId, parentId, index, type, uri, guid) => uri.spec == url);
EventUtils.synthesizeDrop(placesItems.childNodes[0],
placesItems,
[[{type: aMimeType,
data: uriSpec}]],
data: url}]],
aEffect, window);
// Verify that the drop produces exactly one bookmark.
let bookmarkIds = PlacesUtils.bookmarks
.getBookmarkIdsForURI(uri);
ok(bookmarkIds.length == 1, "There should be exactly one bookmark");
await promiseItemAddedNotification;
PlacesUtils.bookmarks.removeItem(bookmarkIds[0]);
// Verify that the drop produces exactly one bookmark.
let bookmark = await PlacesUtils.bookmarks.fetch({url});
Assert.ok(bookmark, "There should be exactly one bookmark");
await PlacesUtils.bookmarks.remove(bookmark.guid);
// Verify that we removed the bookmark successfully.
ok(!PlacesUtils.bookmarks.isBookmarked(uri), "URI should be removed");
Assert.equal(await PlacesUtils.bookmarks.fetch({url}), null, "URI should be removed");
};
/**
@ -62,44 +65,48 @@ add_task(async function test() {
* @param aMimeType
* The mime type to use for the drop operation.
*/
let simulateDragDropMultiple = function(aEffect, aMimeType) {
const uriSpecs = [
let simulateDragDropMultiple = async function(aEffect, aMimeType) {
const urls = [
"http://www.mozilla.org/C54263C6-A484-46CF-8E2B-FE131586348A",
"http://www.mozilla.org/71381257-61E6-4376-AF7C-BF3C5FD8870D",
"http://www.mozilla.org/091A88BD-5743-4C16-A005-3D2EA3A3B71E"
];
let uris = uriSpecs.map(spec => makeURI(spec));
let data;
if (aMimeType == "text/x-moz-url")
data = uriSpecs.map(spec => spec + "\n" + spec).join("\n");
data = urls.map(spec => spec + "\n" + spec).join("\n");
else
data = uriSpecs.join("\n");
data = urls.join("\n");
let promiseItemAddedNotification = promiseBookmarksNotification(
"onItemAdded", (itemId, parentId, index, type, uri, guid) => uri.spec == urls[2]);
EventUtils.synthesizeDrop(placesItems.childNodes[0],
placesItems,
[[{type: aMimeType,
data}]],
aEffect, window);
// Verify that the drop produces exactly one bookmark per each URL.
for (let uri of uris) {
let bookmarkIds = PlacesUtils.bookmarks
.getBookmarkIdsForURI(uri);
ok(bookmarkIds.length == 1, "There should be exactly one bookmark");
await promiseItemAddedNotification;
PlacesUtils.bookmarks.removeItem(bookmarkIds[0]);
// Verify that the drop produces exactly one bookmark per each URL.
for (let url of urls) {
let bookmark = await PlacesUtils.bookmarks.fetch({url});
Assert.equal(typeof(bookmark), "object", "There should be exactly one bookmark");
await PlacesUtils.bookmarks.remove(bookmark.guid);
// Verify that we removed the bookmark successfully.
ok(!PlacesUtils.bookmarks.isBookmarked(uri), "URI should be removed");
Assert.equal(await PlacesUtils.bookmarks.fetch({url}), null, "URI should be removed");
}
};
// Simulate a bookmark drop for all of the mime types and effects.
let mimeTypes = ["text/plain", "text/unicode", "text/x-moz-url"];
let effects = ["move", "copy", "link"];
effects.forEach(function(effect) {
mimeTypes.forEach(function(mimeType) {
simulateDragDrop(effect, mimeType);
simulateDragDropMultiple(effect, mimeType);
});
});
for (let effect of effects) {
for (let mimeType of mimeTypes) {
await simulateDragDrop(effect, mimeType);
await simulateDragDropMultiple(effect, mimeType);
}
}
});

Просмотреть файл

@ -2,7 +2,7 @@
add_task(async function() {
info("Bug 479348 - Properties on a root should be read-only.");
let uri = NetUtil.newURI("http://example.com/");
let uri = Services.io.newURI("http://example.com/");
let bm = await PlacesUtils.bookmarks.insert({
url: uri.spec,
parentGuid: PlacesUtils.bookmarks.unfiledGuid
@ -26,10 +26,13 @@ add_task(async function() {
let fooTag = tagsContainer.getChild(0);
let tagNode = fooTag;
tree.selectNode(fooTag);
is(tagNode.title, "tag1", "tagNode title is correct");
Assert.equal(tagNode.title, "tag1", "tagNode title is correct");
ok(tree.controller.isCommandEnabled("placesCmd_show:info"),
"'placesCmd_show:info' on current selected node is enabled");
Assert.ok(tree.controller.isCommandEnabled("placesCmd_show:info"),
"'placesCmd_show:info' on current selected node is enabled");
let promiseTitleResetNotification = promiseBookmarksNotification(
"onItemChanged", (itemId, prop, isAnno, val) => prop == "title" && val == "tag1");
await withBookmarksDialog(
true,
@ -38,12 +41,12 @@ add_task(async function() {
},
async function test(dialogWin) {
// Check that the dialog is not read-only.
ok(!dialogWin.gEditItemOverlay.readOnly, "Dialog should not be read-only");
Assert.ok(!dialogWin.gEditItemOverlay.readOnly, "Dialog should not be read-only");
// Check that name picker is not read only
let namepicker = dialogWin.document.getElementById("editBMPanel_namePicker");
ok(!namepicker.readOnly, "Name field should not be read-only");
is(namepicker.value, "tag1", "Node title is correct");
Assert.ok(!namepicker.readOnly, "Name field should not be read-only");
Assert.equal(namepicker.value, "tag1", "Node title is correct");
let promiseTitleChangeNotification = promiseBookmarksNotification(
"onItemChanged", (itemId, prop, isAnno, val) => prop == "title" && val == "tag2");
@ -52,20 +55,22 @@ add_task(async function() {
await promiseTitleChangeNotification;
is(namepicker.value, "tag2", "Node title has been properly edited");
Assert.equal(namepicker.value, "tag2", "Node title has been properly edited");
// Check the shortcut's title.
is(tree.selectedNode.title, "tag2", "The node has the correct title");
Assert.equal(tree.selectedNode.title, "tag2", "The node has the correct title");
// Check the tags have been edited.
let tags = PlacesUtils.tagging.getTagsForURI(uri);
is(tags.length, 1, "Found the right number of tags");
ok(tags.includes("tag2"), "Found the expected tag");
Assert.equal(tags.length, 1, "Found the right number of tags");
Assert.ok(tags.includes("tag2"), "Found the expected tag");
}
);
await promiseTitleResetNotification;
// Check the tag change has been reverted.
let tags = PlacesUtils.tagging.getTagsForURI(uri);
is(tags.length, 1, "Found the right number of tags");
ok(tags.includes("tag1"), "Found the expected tag");
Assert.equal(tags.length, 1, "Found the right number of tags");
Assert.deepEqual(tags, ["tag1"], "Found the expected tag");
});

Просмотреть файл

@ -7,107 +7,86 @@
const TEST_URL = "http://www.batch.delete.me/";
var gTests = [];
var gLibrary;
// ------------------------------------------------------------------------------
add_task(async function test_setup() {
gLibrary = await promiseLibrary();
gTests.push({
desc: "Create and batch remove bookmarks",
run() {
let testURI = makeURI(TEST_URL);
PlacesUtils.history.runInBatchMode({
runBatched(aUserData) {
// Create a folder in unserted and populate it with bookmarks.
let folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.unfiledBookmarksFolderId, "deleteme",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
PlacesUtils.bookmarks.createFolder(
PlacesUtils.unfiledBookmarksFolderId, "keepme",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
for (let i = 0; i < 10; i++) {
PlacesUtils.bookmarks.insertBookmark(folder,
testURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bm" + i);
}
}
}, null);
// Select and open the left pane "History" query.
let PO = gLibrary.PlacesOrganizer;
PO.selectLeftPaneQuery("UnfiledBookmarks");
isnot(PO._places.selectedNode, null, "Selected unsorted bookmarks");
let unsortedNode = PlacesUtils.asContainer(PO._places.selectedNode);
unsortedNode.containerOpen = true;
is(unsortedNode.childCount, 2, "Unsorted node has 2 children");
let folderNode = unsortedNode.getChild(0);
is(folderNode.title, "deleteme", "Folder found in unsorted bookmarks");
// Check delete command is available.
PO._places.selectNode(folderNode);
is(PO._places.selectedNode.title, "deleteme", "Folder node selected");
ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
// Execute the delete command and check bookmark has been removed.
PO._places.controller.doCommand("cmd_delete");
ok(!PlacesUtils.bookmarks.isBookmarked(testURI),
"Bookmark has been correctly removed");
// Test live update.
is(unsortedNode.childCount, 1, "Unsorted node has 1 child");
is(PO._places.selectedNode.title, "keepme", "Folder node selected");
unsortedNode.containerOpen = false;
nextTest();
}
});
// ------------------------------------------------------------------------------
gTests.push({
desc: "Ensure correct selection and functionality in Library",
run() {
let PO = gLibrary.PlacesOrganizer;
let ContentTree = gLibrary.ContentTree;
// Move selection forth and back.
PO.selectLeftPaneQuery("History");
PO.selectLeftPaneQuery("UnfiledBookmarks");
// Now select the "keepme" folder in the right pane and delete it.
ContentTree.view.selectNode(ContentTree.view.result.root.getChild(0));
is(ContentTree.view.selectedNode.title, "keepme",
"Found folder in content pane");
// Test live update.
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
makeURI(TEST_URL),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bm");
is(ContentTree.view.result.root.childCount, 2,
"Right pane was correctly updated");
nextTest();
}
});
// ------------------------------------------------------------------------------
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
PlacesUtils.bookmarks
.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
});
gLibrary = openLibrary(nextTest);
}
function nextTest() {
if (gTests.length) {
var testCase = gTests.shift();
info("Start of test: " + testCase.desc);
testCase.run();
} else {
// Close Library window.
gLibrary.close();
finish();
}
}
});
});
add_task(async function test_create_and_batch_remove_bookmarks() {
let testURI = makeURI(TEST_URL);
PlacesUtils.history.runInBatchMode({
runBatched(aUserData) {
// Create a folder in unserted and populate it with bookmarks.
let folder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.unfiledBookmarksFolderId, "deleteme",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
PlacesUtils.bookmarks.createFolder(
PlacesUtils.unfiledBookmarksFolderId, "keepme",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
for (let i = 0; i < 10; i++) {
PlacesUtils.bookmarks.insertBookmark(folder,
testURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bm" + i);
}
}
}, null);
// Select and open the left pane "History" query.
let PO = gLibrary.PlacesOrganizer;
PO.selectLeftPaneQuery("UnfiledBookmarks");
Assert.notEqual(PO._places.selectedNode, null, "Selected unsorted bookmarks");
let unsortedNode = PlacesUtils.asContainer(PO._places.selectedNode);
unsortedNode.containerOpen = true;
Assert.equal(unsortedNode.childCount, 2, "Unsorted node has 2 children");
let folderNode = unsortedNode.getChild(0);
Assert.equal(folderNode.title, "deleteme", "Folder found in unsorted bookmarks");
// Check delete command is available.
PO._places.selectNode(folderNode);
Assert.equal(PO._places.selectedNode.title, "deleteme", "Folder node selected");
Assert.ok(PO._places.controller.isCommandEnabled("cmd_delete"),
"Delete command is enabled");
let promiseItemRemovedNotification = promiseBookmarksNotification(
"onItemRemoved", (itemId, parentId, index, type, uri, guid) => guid == folderNode.bookmarkGuid);
// Execute the delete command and check bookmark has been removed.
PO._places.controller.doCommand("cmd_delete");
await promiseItemRemovedNotification;
Assert.ok(!PlacesUtils.bookmarks.isBookmarked(testURI),
"Bookmark has been correctly removed");
// Test live update.
Assert.equal(unsortedNode.childCount, 1, "Unsorted node has 1 child");
Assert.equal(PO._places.selectedNode.title, "keepme", "Folder node selected");
unsortedNode.containerOpen = false;
});
add_task(async function test_ensure_correct_selection_and_functionality() {
let PO = gLibrary.PlacesOrganizer;
let ContentTree = gLibrary.ContentTree;
// Move selection forth and back.
PO.selectLeftPaneQuery("History");
PO.selectLeftPaneQuery("UnfiledBookmarks");
// Now select the "keepme" folder in the right pane and delete it.
ContentTree.view.selectNode(ContentTree.view.result.root.getChild(0));
Assert.equal(ContentTree.view.selectedNode.title, "keepme",
"Found folder in content pane");
// Test live update.
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
makeURI(TEST_URL),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"bm");
Assert.equal(ContentTree.view.result.root.childCount, 2,
"Right pane was correctly updated");
});

Просмотреть файл

@ -9,15 +9,22 @@ var gSearchResultsPane = {
listSearchMenuitemIndicators: new Set(),
searchResultsCategory: null,
searchInput: null,
inited: false,
init() {
if (this.inited) {
return;
}
this.inited = true;
this.searchResultsCategory = document.getElementById("category-search-results");
this.searchInput = document.getElementById("searchInput");
this.searchInput.hidden = !Services.prefs.getBoolPref("browser.preferences.search");
if (!this.searchInput.hidden) {
this.searchInput.addEventListener("command", this);
this.searchInput.addEventListener("focus", this);
window.addEventListener("load", () => {
this.searchInput.focus();
this.initializeCategories();
});
// Throttling the resize event to reduce the callback frequency
let callbackId;
@ -37,8 +44,6 @@ var gSearchResultsPane = {
handleEvent(event) {
if (event.type === "command") {
this.searchFunction(event);
} else if (event.type === "focus") {
this.initializeCategories();
}
},

Просмотреть файл

@ -45,7 +45,10 @@ add_task(async function() {
// Performs search
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
searchInput.focus();
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
"Search input should be focused when visiting preferences");
searchInput.value = "password";
searchInput.doCommand();
@ -84,7 +87,10 @@ add_task(async function() {
// Performs search
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
searchInput.focus();
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
"Search input should be focused when visiting preferences");
searchInput.value = "password";
searchInput.doCommand();
@ -141,7 +147,10 @@ add_task(async function() {
// Performs search
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
searchInput.focus();
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
"Search input should be focused when visiting preferences");
searchInput.value = "coach";
searchInput.doCommand();
@ -167,7 +176,10 @@ add_task(async function() {
// Performs search
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
searchInput.focus();
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
"Search input should be focused when visiting preferences");
searchInput.value = "password";
searchInput.doCommand();
@ -194,7 +206,10 @@ add_task(async function() {
// Performs search
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
searchInput.focus();
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
"Search input should be focused when visiting preferences");
searchInput.value = "site data";
searchInput.doCommand();
@ -220,7 +235,10 @@ add_task(async function() {
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
let searchResultsCategory = gBrowser.contentDocument.getElementById("category-search-results");
searchInput.focus();
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
"Search input should be focused when visiting preferences");
searchInput.value = "password";
searchInput.doCommand();
is(searchResultsCategory.hidden, false, "search results category should be shown");

Просмотреть файл

@ -27,7 +27,10 @@ add_task(async function() {
// Performs search.
let searchInput = gBrowser.contentDocument.getElementById("searchInput");
searchInput.focus();
is(searchInput, gBrowser.contentDocument.activeElement.closest("#searchInput"),
"Search input should be focused when visiting preferences");
searchInput.value = "Create Account";
searchInput.doCommand();

Просмотреть файл

@ -7,7 +7,6 @@ support-files =
offline/manifest.appcache
[browser_applications_selection.js]
[browser_advanced_siteData.js]
[browser_advanced_update.js]
skip-if = !updater
[browser_basic_rebuild_fonts_test.js]
@ -44,6 +43,8 @@ skip-if = e10s
[browser_sanitizeOnShutdown_prefLocked.js]
[browser_searchsuggestions.js]
[browser_security.js]
[browser_siteData.js]
[browser_siteData2.js]
[browser_site_login_exceptions.js]
[browser_subdialogs.js]
support-files =

Просмотреть файл

@ -15,11 +15,8 @@ const TEST_QUOTA_USAGE_URL = TEST_QUOTA_USAGE_ORIGIN + "/browser/browser/compone
const TEST_OFFLINE_HOST = "example.org";
const TEST_OFFLINE_ORIGIN = "https://" + TEST_OFFLINE_HOST;
const TEST_OFFLINE_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/offline/offline.html";
const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const { DownloadUtils } = Cu.import("resource://gre/modules/DownloadUtils.jsm", {});
const { SiteDataManager } = Cu.import("resource:///modules/SiteDataManager.jsm", {});
const { OfflineAppCacheHelper } = Cu.import("resource:///modules/offlineAppCache.jsm", {});
const mockOfflineAppCacheHelper = {
@ -38,45 +35,6 @@ const mockOfflineAppCacheHelper = {
}
};
const mockSiteDataManager = {
_originalGetQuotaUsage: null,
_originalRemoveQuotaUsage: null,
_getQuotaUsage() {
let results = [];
this.fakeSites.forEach(site => {
results.push({
origin: site.principal.origin,
usage: site.usage,
persisted: site.persisted
});
});
SiteDataManager._getQuotaUsagePromise = Promise.resolve(results);
return SiteDataManager._getQuotaUsagePromise;
},
_removeQuotaUsage(site) {
var target = site.principals[0].URI.host;
this.fakeSites = this.fakeSites.filter(fakeSite => {
return fakeSite.principal.URI.host != target;
});
},
register() {
this._originalGetQuotaUsage = SiteDataManager._getQuotaUsage;
SiteDataManager._getQuotaUsage = this._getQuotaUsage.bind(this);
this._originalRemoveQuotaUsage = SiteDataManager._removeQuotaUsage;
SiteDataManager._removeQuotaUsage = this._removeQuotaUsage.bind(this);
this.fakeSites = null;
},
unregister() {
SiteDataManager._getQuotaUsage = this._originalGetQuotaUsage;
SiteDataManager._removeQuotaUsage = this._originalRemoveQuotaUsage;
}
};
function addPersistentStoragePerm(origin) {
let uri = NetUtil.newURI(origin);
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
@ -126,60 +84,12 @@ const cacheUsageGetter = {
]),
};
function openSettingsDialog() {
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let settingsBtn = doc.getElementById("siteDataSettings");
let dialogOverlay = win.gSubDialog._preloadDialog._overlay;
let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
is(dialogOverlay.style.visibility, "visible", "The Settings dialog should be visible");
});
settingsBtn.doCommand();
return fullyLoadPromise;
}
function promiseSettingsDialogClose() {
return new Promise(resolve => {
let win = gBrowser.selectedBrowser.contentWindow;
let dialogOverlay = win.gSubDialog._topDialog._overlay;
let dialogWin = win.gSubDialog._topDialog._frame.contentWindow;
dialogWin.addEventListener("unload", function unload() {
if (dialogWin.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
resolve();
}
}, { once: true });
});
}
function promiseSitesUpdated() {
return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
}
function promiseCookiesCleared() {
return TestUtils.topicObserved("cookie-changed", (subj, data) => {
return data === "cleared";
});
}
function assertSitesListed(doc, hosts) {
let win = gBrowser.selectedBrowser.contentWindow;
let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
is(totalSitesNumber, hosts.length, "Should list the right sites number");
hosts.forEach(host => {
let site = sitesList.querySelector(`richlistitem[host="${host}"]`);
ok(site, `Should list the site of ${host}`);
});
is(removeBtn.disabled, false, "Should enable the removeSelected button");
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}
registerCleanupFunction(function() {
delete window.sinon;
mockOfflineAppCacheHelper.unregister();
@ -576,301 +486,3 @@ add_task(async function() {
mockSiteDataManager.unregister();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Test selecting and removing all sites one by one
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register();
mockSiteDataManager.fakeSites = [
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://shopping.xyz.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://email.bar.com"),
persisted: false
},
];
let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
let updatePromise = promiseSitesUpdated();
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatePromise;
await openSettingsDialog();
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertSitesListed(doc, fakeHosts);
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeAllSitesOneByOne();
assertAllSitesNotListed();
cancelBtn.doCommand();
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button but cancelling save
let cancelPromise = promiseAlertDialogOpen("cancel");
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
await cancelPromise;
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button and accepting save
let acceptPromise = promiseAlertDialogOpen("accept");
settingsDialogClosePromise = promiseSettingsDialogClose();
updatePromise = promiseSitesUpdated();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
await acceptPromise;
await settingsDialogClosePromise;
await updatePromise;
await openSettingsDialog();
assertAllSitesNotListed();
mockSiteDataManager.unregister();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeAllSitesOneByOne() {
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
for (let i = sites.length - 1; i >= 0; --i) {
sites[i].click();
removeBtn.doCommand();
}
}
function assertAllSitesNotListed() {
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, 0, "Should not list all sites");
is(removeBtn.disabled, true, "Should disable the removeSelected button");
is(removeAllBtn.disabled, true, "Should disable the removeAllBtn button");
}
});
// Test selecting and removing partial sites
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register();
mockSiteDataManager.fakeSites = [
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://shopping.xyz.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://email.bar.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://s3-us-west-2.amazonaws.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://127.0.0.1"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://[0:0:0:0:0:0:0:1]"),
persisted: true
},
];
let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
let updatePromise = promiseSitesUpdated();
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatePromise;
await openSettingsDialog();
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let removeDialogOpenPromise = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertSitesListed(doc, fakeHosts);
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
cancelBtn.doCommand();
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button but canceling save
removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
saveBtn.doCommand();
await removeDialogOpenPromise;
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button and accepting save
removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
saveBtn.doCommand();
await removeDialogOpenPromise;
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts.slice(2));
mockSiteDataManager.unregister();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeSelectedSite(hosts) {
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
hosts.forEach(host => {
let site = sitesList.querySelector(`richlistitem[host="${host}"]`);
if (site) {
site.click();
removeBtn.doCommand();
} else {
ok(false, `Should not select and remove inexistent site of ${host}`);
}
});
}
});
// Test searching and then removing only visible sites
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register(SiteDataManager);
mockSiteDataManager.fakeSites = [
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://shopping.xyz.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://email.bar.com"),
persisted: false
},
];
let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
let updatePromise = promiseSitesUpdated();
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatePromise;
await openSettingsDialog();
// Search "foo" to only list foo.com sites
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "xyz";
searchBox.doCommand();
assertSitesListed(doc, fakeHosts.filter(host => host.includes("xyz")));
// Test only removing all visible sites listed
updatePromise = promiseSitesUpdated();
let acceptRemovePromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
let settingsDialogClosePromise = promiseSettingsDialogClose();
let removeAllBtn = frameDoc.getElementById("removeAll");
let saveBtn = frameDoc.getElementById("save");
removeAllBtn.doCommand();
saveBtn.doCommand();
await acceptRemovePromise;
await settingsDialogClosePromise;
await updatePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts.filter(host => !host.includes("xyz")));
mockSiteDataManager.unregister();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

Просмотреть файл

@ -0,0 +1,299 @@
"use strict";
// Test selecting and removing all sites one by one
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register();
mockSiteDataManager.fakeSites = [
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://shopping.xyz.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://email.bar.com"),
persisted: false
},
];
let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
let updatePromise = promiseSitesUpdated();
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatePromise;
await openSettingsDialog();
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertSitesListed(doc, fakeHosts);
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeAllSitesOneByOne();
assertAllSitesNotListed();
cancelBtn.doCommand();
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button but cancelling save
let cancelPromise = promiseAlertDialogOpen("cancel");
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
await cancelPromise;
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button and accepting save
let acceptPromise = promiseAlertDialogOpen("accept");
settingsDialogClosePromise = promiseSettingsDialogClose();
updatePromise = promiseSitesUpdated();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeAllSitesOneByOne();
assertAllSitesNotListed();
saveBtn.doCommand();
await acceptPromise;
await settingsDialogClosePromise;
await updatePromise;
await openSettingsDialog();
assertAllSitesNotListed();
mockSiteDataManager.unregister();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeAllSitesOneByOne() {
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
for (let i = sites.length - 1; i >= 0; --i) {
sites[i].click();
removeBtn.doCommand();
}
}
function assertAllSitesNotListed() {
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, 0, "Should not list all sites");
is(removeBtn.disabled, true, "Should disable the removeSelected button");
is(removeAllBtn.disabled, true, "Should disable the removeAllBtn button");
}
});
// Test selecting and removing partial sites
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register();
mockSiteDataManager.fakeSites = [
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://shopping.xyz.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://email.bar.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://s3-us-west-2.amazonaws.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://127.0.0.1"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://[0:0:0:0:0:0:0:1]"),
persisted: true
},
];
let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
let updatePromise = promiseSitesUpdated();
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatePromise;
await openSettingsDialog();
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let removeDialogOpenPromise = null;
let settingsDialogClosePromise = null;
// Test the initial state
assertSitesListed(doc, fakeHosts);
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
cancelBtn.doCommand();
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button but canceling save
removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
saveBtn.doCommand();
await removeDialogOpenPromise;
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts);
// Test the "Save Changes" button and accepting save
removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeHosts.slice(0, 2));
assertSitesListed(doc, fakeHosts.slice(2));
saveBtn.doCommand();
await removeDialogOpenPromise;
await settingsDialogClosePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts.slice(2));
mockSiteDataManager.unregister();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeSelectedSite(hosts) {
frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let sitesList = frameDoc.getElementById("sitesList");
hosts.forEach(host => {
let site = sitesList.querySelector(`richlistitem[host="${host}"]`);
if (site) {
site.click();
removeBtn.doCommand();
} else {
ok(false, `Should not select and remove inexistent site of ${host}`);
}
});
}
});
// Test searching and then removing only visible sites
add_task(async function() {
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
mockSiteDataManager.register(SiteDataManager);
mockSiteDataManager.fakeSites = [
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("https://shopping.xyz.com"),
persisted: false
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
persisted: true
},
{
usage: 1024,
principal: Services.scriptSecurityManager
.createCodebasePrincipalFromOrigin("http://email.bar.com"),
persisted: false
},
];
let fakeHosts = mockSiteDataManager.fakeSites.map(site => site.principal.URI.host);
let updatePromise = promiseSitesUpdated();
await openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
await updatePromise;
await openSettingsDialog();
// Search "foo" to only list foo.com sites
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
searchBox.value = "xyz";
searchBox.doCommand();
assertSitesListed(doc, fakeHosts.filter(host => host.includes("xyz")));
// Test only removing all visible sites listed
updatePromise = promiseSitesUpdated();
let acceptRemovePromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
let settingsDialogClosePromise = promiseSettingsDialogClose();
let removeAllBtn = frameDoc.getElementById("removeAll");
let saveBtn = frameDoc.getElementById("save");
removeAllBtn.doCommand();
saveBtn.doCommand();
await acceptRemovePromise;
await settingsDialogClosePromise;
await updatePromise;
await openSettingsDialog();
assertSitesListed(doc, fakeHosts.filter(host => !host.includes("xyz")));
mockSiteDataManager.unregister();
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

Просмотреть файл

@ -13,6 +13,46 @@ registerCleanupFunction(function() {
});
const kDefaultWait = 2000;
const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
const { SiteDataManager } = Cu.import("resource:///modules/SiteDataManager.jsm", {});
const mockSiteDataManager = {
_originalGetQuotaUsage: null,
_originalRemoveQuotaUsage: null,
_getQuotaUsage() {
let results = [];
this.fakeSites.forEach(site => {
results.push({
origin: site.principal.origin,
usage: site.usage,
persisted: site.persisted
});
});
SiteDataManager._getQuotaUsagePromise = Promise.resolve(results);
return SiteDataManager._getQuotaUsagePromise;
},
_removeQuotaUsage(site) {
var target = site.principals[0].URI.host;
this.fakeSites = this.fakeSites.filter(fakeSite => {
return fakeSite.principal.URI.host != target;
});
},
register() {
this._originalGetQuotaUsage = SiteDataManager._getQuotaUsage;
SiteDataManager._getQuotaUsage = this._getQuotaUsage.bind(this);
this._originalRemoveQuotaUsage = SiteDataManager._removeQuotaUsage;
SiteDataManager._removeQuotaUsage = this._removeQuotaUsage.bind(this);
this.fakeSites = null;
},
unregister() {
SiteDataManager._getQuotaUsage = this._originalGetQuotaUsage;
SiteDataManager._removeQuotaUsage = this._originalRemoveQuotaUsage;
}
};
function is_hidden(aElement) {
var style = aElement.ownerGlobal.getComputedStyle(aElement);
@ -190,3 +230,51 @@ function promiseWindowDialogOpen(buttonAction, url) {
function promiseAlertDialogOpen(buttonAction) {
return promiseWindowDialogOpen(buttonAction, "chrome://global/content/commonDialog.xul");
}
function openSettingsDialog() {
let win = gBrowser.selectedBrowser.contentWindow;
let doc = gBrowser.selectedBrowser.contentDocument;
let settingsBtn = doc.getElementById("siteDataSettings");
let dialogOverlay = win.gSubDialog._preloadDialog._overlay;
let dialogLoadPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul");
let dialogInitPromise = TestUtils.topicObserved("sitedata-settings-init", () => true);
let fullyLoadPromise = Promise.all([ dialogLoadPromise, dialogInitPromise ]).then(() => {
is(dialogOverlay.style.visibility, "visible", "The Settings dialog should be visible");
});
settingsBtn.doCommand();
return fullyLoadPromise;
}
function assertSitesListed(doc, hosts) {
let win = gBrowser.selectedBrowser.contentWindow;
let frameDoc = win.gSubDialog._topDialog._frame.contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
is(totalSitesNumber, hosts.length, "Should list the right sites number");
hosts.forEach(host => {
let site = sitesList.querySelector(`richlistitem[host="${host}"]`);
ok(site, `Should list the site of ${host}`);
});
is(removeBtn.disabled, false, "Should enable the removeSelected button");
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}
function promiseSitesUpdated() {
return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
}
function promiseSettingsDialogClose() {
return new Promise(resolve => {
let win = gBrowser.selectedBrowser.contentWindow;
let dialogOverlay = win.gSubDialog._topDialog._overlay;
let dialogWin = win.gSubDialog._topDialog._frame.contentWindow;
dialogWin.addEventListener("unload", function unload() {
if (dialogWin.document.documentURI === "chrome://browser/content/preferences/siteDataSettings.xul") {
isnot(dialogOverlay.style.visibility, "visible", "The Settings dialog should be hidden");
resolve();
}
}, { once: true });
});
}

Просмотреть файл

@ -4,10 +4,12 @@ support-files =
file_dummy.html
file_navigator.html
file_navigatorWorker.js
file_workerNetInfo.js
file_workerPerformance.js
head.js
[browser_navigator.js]
[browser_netInfo.js]
[browser_performanceAPI.js]
[browser_roundedWindow_dialogWindow.js]
[browser_roundedWindow_newWindow.js]

Просмотреть файл

@ -0,0 +1,61 @@
/**
* Bug 1372072 - A test case for check whether network information API has been
* spoofed correctly when 'privacy.resistFingerprinting' is true;
*/
const TEST_PATH = "http://example.net/browser/browser/" +
"components/resistfingerprinting/test/browser/"
async function testWindow() {
// Open a tab to test network information in a content.
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_dummy.html");
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
ok("connection" in content.navigator, "navigator.connection should exist");
is(content.navigator.connection.type, "unknown", "The connection type is spoofed correctly");
});
await BrowserTestUtils.removeTab(tab);
}
async function testWorker() {
// Open a tab to test network information in a worker.
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser, TEST_PATH + "file_dummy.html");
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
await new Promise(resolve => {
let worker = new content.Worker("file_workerNetInfo.js");
worker.onmessage = function(e) {
if (e.data.type == "status") {
ok(e.data.status, e.data.msg);
} else if (e.data.type == "finish") {
resolve();
} else {
ok(false, "Unknown message type");
resolve();
}
}
worker.postMessage({type: "runTests"});
});
});
await BrowserTestUtils.removeTab(tab);
}
add_task(async function runTest() {
await SpecialPowers.pushPrefEnv({"set":
[
["privacy.resistFingerprinting", true],
["dom.netinfo.enabled", true]
]
});
await testWindow();
await testWorker();
});

Просмотреть файл

@ -0,0 +1,26 @@
function ok(a, msg) {
postMessage({type: "status", status: !!a, msg});
}
function is(a, b, msg) {
ok(a === b, msg);
}
function finish() {
postMessage({type: "finish"});
}
function runTests() {
ok("connection" in navigator, "navigator.connection should exist");
is(navigator.connection.type, "unknown", "The connection type is spoofed correctly");
finish();
}
self.onmessage = function(e) {
if (e.data.type === "runTests") {
runTests();
} else {
ok(false, "Unknown message type");
}
}

Просмотреть файл

@ -3598,6 +3598,12 @@ var SessionStoreInternal = {
tab.toggleMuteAudio(tabData.muteReason);
}
if (tabData.mediaBlocked) {
browser.blockMedia();
} else {
browser.resumeMedia();
}
if (tabData.lastAccessed) {
tab.updateLastAccessed(tabData.lastAccessed);
}

Просмотреть файл

@ -14,8 +14,11 @@ this.EXPORTED_SYMBOLS = ["TabAttributes"];
// 'pending' is used internal by sessionstore and managed accordingly.
// 'iconLoadingPrincipal' is same as 'image' that it should be handled by
// using the gBrowser.getIcon()/setIcon() methods.
// 'activemedia-blocked' should not be accessed directly but handled by using
// tab's toggleMuteAudio() or linkedBrowser's methods
// activeMediaBlockStarted()/activeMediaBlockBlockStopped().
const ATTRIBUTES_TO_SKIP = new Set(["image", "muted", "pending", "iconLoadingPrincipal",
"skipbackgroundnotify"]);
"skipbackgroundnotify", "activemedia-blocked"]);
// A set of tab attributes to persist. We will read a given list of tab
// attributes when collecting tab data and will re-set those attributes when

Просмотреть файл

@ -102,6 +102,8 @@ var TabStateInternal = {
tabData.muteReason = tab.muteReason;
}
tabData.mediaBlocked = browser.mediaBlocked;
// Save tab attributes.
tabData.attributes = TabAttributes.get(tab);

Просмотреть файл

@ -156,6 +156,16 @@ SessionStartup.prototype = {
return;
}
let initialState = this._initialState;
Services.tm.idleDispatchToMainThread(() => {
let pinnedTabCount = initialState.windows.reduce((winAcc, win) => {
return winAcc + win.tabs.reduce((tabAcc, tab) => {
return tabAcc + (tab.pinned ? 1 : 0);
}, 0);
}, 0);
Services.telemetry.scalarSet("browser.engagement.restored_pinned_tabs_count", pinnedTabCount);
}, 60000);
let shouldResumeSessionOnce = Services.prefs.getBoolPref("browser.sessionstore.resume_session_once");
let shouldResumeSession = shouldResumeSessionOnce ||
Services.prefs.getIntPref("browser.startup.page") == BROWSER_STARTUP_RESUME_SESSION;

Просмотреть файл

@ -4,15 +4,21 @@
/**
* This test makes sure that we correctly preserve tab attributes when storing
* and restoring tabs. It also ensures that we skip special attributes like
* 'image', 'muted' and 'pending' that need to be handled differently or internally.
* 'image', 'muted', 'activemedia-blocked' and 'pending' that need to be
* handled differently or internally.
*/
const PREF = "browser.sessionstore.restore_on_demand";
const PREF2 = "media.block-autoplay-until-in-foreground";
add_task(async function test() {
Services.prefs.setBoolPref(PREF, true)
registerCleanupFunction(() => Services.prefs.clearUserPref(PREF));
// Since we need to test 'activemedia-blocked' attribute.
Services.prefs.setBoolPref(PREF2, true)
registerCleanupFunction(() => Services.prefs.clearUserPref(PREF2));
// Add a new tab with a nice icon.
let tab = BrowserTestUtils.addTab(gBrowser, "about:robots");
await promiseBrowserLoaded(tab.linkedBrowser);
@ -25,15 +31,21 @@ add_task(async function test() {
// Check that the tab has a 'muted' attribute.
ok(tab.hasAttribute("muted"), "tab.muted exists");
// Make sure we do not persist 'image' or 'muted' attributes.
// Pretend to start autoplay media in tab, tab should get the notification.
tab.linkedBrowser.activeMediaBlockStarted();
ok(tab.hasAttribute("activemedia-blocked"), "tab.activemedia-blocked exists");
// Make sure we do not persist 'image','muted' and 'activemedia-blocked' attributes.
ss.persistTabAttribute("image");
ss.persistTabAttribute("muted");
ss.persistTabAttribute("iconLoadingPrincipal");
ss.persistTabAttribute("activemedia-blocked");
let {attributes} = JSON.parse(ss.getTabState(tab));
ok(!("image" in attributes), "'image' attribute not saved");
ok(!("iconLoadingPrincipal" in attributes), "'iconLoadingPrincipal' attribute not saved");
ok(!("muted" in attributes), "'muted' attribute not saved");
ok(!("custom" in attributes), "'custom' attribute not saved");
ok(!("activemedia-blocked" in attributes), "'activemedia-blocked' attribute not saved");
// Test persisting a custom attribute.
tab.setAttribute("custom", "foobar");

Просмотреть файл

@ -26,7 +26,13 @@ if (AppConstants.platform == "linux")
function startupRecorder() {
this.wrappedJSObject = this;
this.loader = Cc["@mozilla.org/moz/jsloader;1"].getService(Ci.xpcIJSModuleLoader);
this.data = {};
this.data = {
images: {
"image-drawing": new Set(),
"image-loading": new Set(),
},
code: {}
};
}
startupRecorder.prototype = {
classID: Components.ID("{11c095b2-e42e-4bdf-9dd0-aed87595f6a4}"),
@ -34,7 +40,7 @@ startupRecorder.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
record(name) {
this.data[name] = {
this.data.code[name] = {
components: this.loader.loadedComponents(),
modules: this.loader.loadedModules(),
services: Object.keys(Cc).filter(c => {
@ -57,6 +63,8 @@ startupRecorder.prototype = {
let topics = [
"profile-do-change", // This catches stuff loaded during app-startup
"toplevel-window-ready", // Catches stuff from final-ui-startup
"image-loading",
"image-drawing",
firstPaintNotification,
"sessionstore-windows-restored",
];
@ -65,6 +73,11 @@ startupRecorder.prototype = {
return;
}
if (topic == "image-drawing" || topic == "image-loading") {
this.data.images[topic].add(data);
return;
}
Services.obs.removeObserver(this, topic);
if (topic == "sessionstore-windows-restored") {
@ -73,6 +86,9 @@ startupRecorder.prototype = {
// to react to user events.
Services.tm.idleDispatchToMainThread(
this.record.bind(this, "before handling user events"));
Services.obs.removeObserver(this, "image-drawing");
Services.obs.removeObserver(this, "image-loading");
} else {
const topicsToNames = {
"profile-do-change": "before profile selection",

Просмотреть файл

@ -8,6 +8,7 @@ ac_add_options --disable-crashreporter
ac_add_options --disable-elf-hack
ac_add_options --enable-debug
ac_add_options --disable-sandbox
ac_add_options --disable-profiling
MOZ_CODE_COVERAGE=1
export CFLAGS="--coverage"

6
browser/extensions/e10srollout/bootstrap.js поставляемый
Просмотреть файл

@ -22,8 +22,10 @@ const TEST_THRESHOLD = {
// If a user qualifies for the e10s-multi experiement, this is how many
// content processes to use and whether to allow addons for the experiment.
const MULTI_EXPERIMENT = {
"beta": { buckets: { 1: .5, 4: 1, }, // 1 process: 50%, 4 processes: 50%
addonsDisableExperiment: false },
"beta": { buckets: { 4: 1, }, // 4 processes: 100%
// See below for an explanation, this only allows webextensions.
get addonsDisableExperiment() { return getAddonsDisqualifyForMulti(); } },
"release": { buckets: { 1: .2, 4: 1 }, // 1 process: 20%, 4 processes: 80%

Просмотреть файл

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>e10srollout@mozilla.org</em:id>
<em:version>1.60</em:version>
<em:version>1.70</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

Просмотреть файл

@ -193,24 +193,38 @@ class AutofillRecords {
*/
add(record) {
this.log.debug("add:", record);
let recordToSave;
if (record.deleted) {
if (!record.guid) {
throw new Error("you must specify the GUID when creating a tombstone");
}
if (this._findByGUID(record.guid, {includeDeleted: true})) {
throw new Error("a record with this GUID already exists");
}
recordToSave = {
guid: record.guid,
timeLastModified: record.timeLastModified || Date.now(),
deleted: true,
};
} else {
recordToSave = this._clone(record);
this._normalizeRecord(recordToSave);
let recordToSave = this._clone(record);
this._normalizeRecord(recordToSave);
let guid;
while (!guid || this._findByGUID(guid)) {
guid = gUUIDGenerator.generateUUID().toString()
.replace(/[{}-]/g, "").substring(0, 12);
}
recordToSave.guid = guid;
recordToSave.version = this.version;
let guid;
while (!guid || this._findByGUID(guid)) {
guid = gUUIDGenerator.generateUUID().toString()
.replace(/[{}-]/g, "").substring(0, 12);
// Metadata
let now = Date.now();
recordToSave.timeCreated = now;
recordToSave.timeLastModified = now;
recordToSave.timeLastUsed = 0;
recordToSave.timesUsed = 0;
}
recordToSave.guid = guid;
recordToSave.version = this.version;
// Metadata
let now = Date.now();
recordToSave.timeCreated = now;
recordToSave.timeLastModified = now;
recordToSave.timeLastUsed = 0;
recordToSave.timesUsed = 0;
this._store.data[this._collectionName].push(recordToSave);
this._store.saveSoon();
@ -283,8 +297,17 @@ class AutofillRecords {
remove(guid) {
this.log.debug("remove:", guid);
this._store.data[this._collectionName] =
this._store.data[this._collectionName].filter(record => record.guid != guid);
let index = this._findIndexByGUID(guid);
if (index == -1) {
this.log.warn("attempting to remove non-existing entry", guid);
return;
}
// replace the record with a tombstone.
this._store.data[this._collectionName][index] = {
guid,
timeLastModified: Date.now(),
deleted: true,
};
this._store.saveSoon();
Services.obs.notifyObservers(null, "formautofill-storage-changed", "remove");
@ -315,19 +338,20 @@ class AutofillRecords {
/**
* Returns all records.
*
* @param {Object} config
* Specifies how data will be retrieved.
* @param {boolean} config.noComputedFields
* @param {boolean} [options.noComputedFields = false]
* Returns raw record without those computed fields.
* @param {boolean} [options.includeDeleted = false]
* Also return any tombstone records.
* @returns {Array.<Object>}
* An array containing clones of all records.
*/
getAll(config = {}) {
this.log.debug("getAll", config);
getAll({noComputedFields = false, includeDeleted = false} = {}) {
this.log.debug("getAll", noComputedFields, includeDeleted);
let records = this._store.data[this._collectionName].filter(r => !r.deleted || includeDeleted);
// Records are cloned to avoid accidental modifications from outside.
let clonedRecords = this._store.data[this._collectionName].map(this._clone);
clonedRecords.forEach(record => this._recordReadProcessor(record, config));
let clonedRecords = records.map(this._clone);
clonedRecords.forEach(record => this._recordReadProcessor(record, {noComputedFields}));
return clonedRecords;
}
@ -362,13 +386,15 @@ class AutofillRecords {
return Object.assign({}, record);
}
_findByGUID(guid) {
let found = this._findIndexByGUID(guid);
_findByGUID(guid, {includeDeleted = false} = {}) {
let found = this._findIndexByGUID(guid, {includeDeleted});
return found < 0 ? undefined : this._store.data[this._collectionName][found];
}
_findIndexByGUID(guid) {
return this._store.data[this._collectionName].findIndex(record => record.guid == guid);
_findIndexByGUID(guid, {includeDeleted = false} = {}) {
return this._store.data[this._collectionName].findIndex(record => {
return record.guid == guid && (!record.deleted || includeDeleted);
});
}
_normalizeRecord(record) {
@ -386,7 +412,7 @@ class AutofillRecords {
}
// An interface to be inherited.
_recordReadProcessor(record, config) {}
_recordReadProcessor(record, {noComputedFields = false} = {}) {}
// An interface to be inherited.
_recordWriteProcessor(record) {}
@ -579,7 +605,7 @@ class Addresses extends AutofillRecords {
mergeToStorage(targetAddress) {
let mergedGUIDs = [];
for (let address of this._store.data[this._collectionName]) {
if (this.mergeIfPossible(address.guid, targetAddress)) {
if (!address.deleted && this.mergeIfPossible(address.guid, targetAddress)) {
mergedGUIDs.push(address.guid);
}
}

Просмотреть файл

@ -0,0 +1,120 @@
/**
* Tests tombstones in address/creditcard records.
*/
"use strict";
const {ProfileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
const TEST_STORE_FILE_NAME = "test-tombstones.json";
const TEST_ADDRESS_1 = {
"given-name": "Timothy",
"additional-name": "John",
"family-name": "Berners-Lee",
organization: "World Wide Web Consortium",
"street-address": "32 Vassar Street\nMIT Room 32-G524",
"address-level2": "Cambridge",
"address-level1": "MA",
"postal-code": "02139",
country: "US",
tel: "+1 617 253 5702",
email: "timbl@w3.org",
};
const TEST_CC_1 = {
"cc-name": "John Doe",
"cc-number": "1234567812345678",
"cc-exp-month": 4,
"cc-exp-year": 2017,
};
let do_check_tombstone_record = (profile) => {
Assert.ok(profile.deleted);
Assert.deepEqual(Object.keys(profile).sort(),
["guid", "timeLastModified", "deleted"].sort());
};
// Like add_task, but actually adds 2 - one for addresses and one for cards.
function add_storage_task(test_function) {
add_task(async function() {
let path = getTempFile(TEST_STORE_FILE_NAME).path;
let profileStorage = new ProfileStorage(path);
await profileStorage.initialize();
for (let [storage, record] of [[profileStorage.addresses, TEST_ADDRESS_1],
[profileStorage.creditCards, TEST_CC_1]]) {
await test_function(storage, record);
}
});
}
add_storage_task(async function test_simple_tombstone(storage, record) {
do_print("check simple tombstone semantics");
let guid = storage.add(record);
do_check_eq(storage.getAll().length, 1);
storage.remove(guid);
// should be unable to get it normally.
Assert.equal(storage.get(guid), null);
// and getAll should also not return it.
Assert.equal(storage.getAll().length, 0);
// but getAll allows us to access deleted items.
let all = storage.getAll({includeDeleted: true});
Assert.equal(all.length, 1);
do_check_tombstone_record(all[0]);
});
add_storage_task(async function test_add_tombstone(storage, record) {
do_print("Should be able to add a new tombstone");
let guid = storage.add({guid: "test-guid-1", deleted: true});
// should be unable to get it normally.
Assert.equal(storage.get(guid), null);
// and getAll should also not return it.
Assert.equal(storage.getAll().length, 0);
// but getAll allows us to access deleted items.
let all = storage.getAll({includeDeleted: true});
Assert.equal(all.length, 1);
do_check_tombstone_record(all[0]);
});
add_storage_task(async function test_add_tombstone_without_guid(storage, record) {
do_print("Should not be able to add a new tombstone without specifying the guid");
Assert.throws(() => { storage.add({deleted: true}); });
Assert.equal(storage.getAll({includeDeleted: true}).length, 0);
});
add_storage_task(async function test_add_tombstone_existing_guid(storage, record) {
do_print("Should not be able to add a new tombstone when a record with that ID exists");
let guid = storage.add(record);
Assert.throws(() => { storage.add({guid, deleted: true}); });
// same if the existing item is already a tombstone.
storage.add({guid: "test-guid-1", deleted: true});
Assert.throws(() => { storage.add({guid: "test-guid-1", deleted: true}); });
});
add_storage_task(async function test_update_tombstone(storage, record) {
do_print("Updating a tombstone should fail");
let guid = storage.add({guid: "test-guid-1", deleted: true});
Assert.throws(() => storage.update(guid, {}), /No matching record./);
});
add_storage_task(async function test_remove_existing_tombstone(storage, record) {
do_print("Removing a record that's already a tombstone should be a no-op");
let guid = storage.add({guid: "test-guid-1", deleted: true, timeLastModified: 1234});
storage.remove(guid);
let all = storage.getAll({includeDeleted: true});
Assert.equal(all.length, 1);
do_check_tombstone_record(all[0]);
equal(all[0].timeLastModified, 1234); // should not be updated to now().
});

Просмотреть файл

@ -35,4 +35,5 @@ support-files =
[test_profileAutocompleteResult.js]
[test_savedFieldNames.js]
[test_toOneLineAddress.js]
[test_storage_tombstones.js]
[test_transformFields.js]

Просмотреть файл

@ -13,7 +13,7 @@
bottom: 0;
/* Ensuring we can put the overlay over elements using
z-index on original page */
z-index: 999;
z-index: 20999;
color: #4d4d4d;
background: rgb(54, 57, 89, 0.8); /* #363959, 0.8 opacity */
display: none;
@ -338,7 +338,7 @@
/* Tour Notifications */
#onboarding-notification-bar {
position: fixed;
z-index: 998; /* We want this always under #onboarding-overlay */
z-index: 20998; /* We want this always under #onboarding-overlay */
left: 0;
bottom: 0;
width: 100%;

Просмотреть файл

@ -117,6 +117,25 @@ endif
@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR)
@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$*
chrome-%:
@$(MAKE) -C ../../toolkit/locales chrome-$*
@$(MAKE) -C ../../services/sync/locales chrome AB_CD=$*
@$(MAKE) -C ../../extensions/spellcheck/locales chrome AB_CD=$*
ifndef RELEASE_OR_BETA
@$(MAKE) -C ../extensions/formautofill/locale chrome AB_CD=$*
endif
@$(MAKE) -C ../extensions/pocket/locale chrome AB_CD=$*
ifndef RELEASE_OR_BETA
@$(MAKE) -C ../extensions/presentation/locale chrome AB_CD=$*
endif
@$(MAKE) -C ../../intl/locales chrome AB_CD=$*
@$(MAKE) -C ../../devtools/client/locales chrome AB_CD=$*
@$(MAKE) chrome AB_CD=$*
@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales chrome AB_CD=$*
ifdef NIGHTLY_BUILD
@$(MAKE) -C ../extensions/webcompat-reporter/locales chrome AB_CD=$*
endif
repackage-win32-installer: WIN32_INSTALLER_OUT=$(ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
repackage-win32-installer: $(call ESCAPE_WILDCARD,$(WIN32_INSTALLER_IN)) $(SUBMAKEFILES) libs-$(AB_CD)
@echo 'Repackaging $(WIN32_INSTALLER_IN) into $(WIN32_INSTALLER_OUT).'

Просмотреть файл

@ -248,6 +248,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY bookmarksMenuButton.mobile.label "Mobile Bookmarks">
<!ENTITY viewBookmarksSidebar2.label "View Bookmarks Sidebar">
<!ENTITY viewBookmarksToolbar.label "View Bookmarks Toolbar">
<!ENTITY searchBookmarks.label "Search Bookmarks">
<!ENTITY containersMenu.label "Containers">
@ -854,6 +855,7 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY customizeMode.lwthemes.menuManage.accessKey "M">
<!ENTITY customizeMode.lwthemes.menuGetMore "Get More Themes">
<!ENTITY customizeMode.lwthemes.menuGetMore.accessKey "G">
<!ENTITY customizeMode.emptyOverflowList.description "Drag and drop items here to keep them within reach but out of your toolbar…">
<!ENTITY getUserMedia.selectCamera.label "Camera to share:">
<!ENTITY getUserMedia.selectCamera.accesskey "C">

Просмотреть файл

@ -1181,6 +1181,7 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
%include ../shared/customizableui/customizeMode.inc.css
%ifndef MOZ_PHOTON_THEME
#main-window[customize-entered] > #tab-view-deck {
background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
linear-gradient(to bottom, #bcbcbc, #b5b5b5);
@ -1220,6 +1221,7 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
border-right: 3px solid transparent;
border-left: 3px solid transparent;
}
%endif
/* The :hover:active style from toolkit doesn't seem to work in this panel so just use :active. */
.customization-tipPanel-closeBox > .close-icon:active {
@ -1288,4 +1290,4 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
/* Prevent movement in the restore-tabs-button when it's clicked. */
.restore-tabs-button:hover:active:not([disabled="true"]) {
padding: 3px;
}
}

Просмотреть файл

@ -82,7 +82,7 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
}
.subviewbutton > .toolbarbutton-icon {
margin-inline-end: 5px !important;
margin-inline-end: 5px;
}
.subviewbutton > .menu-right,
@ -109,4 +109,14 @@ photonpanelmultiview .subviewbutton > .toolbarbutton-icon {
padding: 0;
}
photonpanelmultiview .subviewbutton:-moz-any([image],[targetURI],.cui-withicon,
.restoreallitem, .bookmark-item) > .toolbarbutton-text {
padding-inline-start: 8px;
}
photonpanelmultiview .subviewbutton:-moz-any([image],[targetURI],.cui-withicon,
.restoreallitem, .bookmark-item)[checked="true"] > .toolbarbutton-icon {
visibility: visible;
}
/* END photon adjustments */

Просмотреть файл

@ -32,9 +32,9 @@ browser.jar:
skin/classic/browser/Toolbar-small.png
skin/classic/browser/webRTC-indicator.css (../shared/webRTC-indicator.css)
* skin/classic/browser/controlcenter/panel.css (controlcenter/panel.css)
#ifndef MOZ_PHOTON_THEME
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
#ifndef MOZ_PHOTON_THEME
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
#endif

Просмотреть файл

@ -1374,6 +1374,7 @@ html|span.ac-emphasize-text-url {
/* system font size is a bit smaller in mac, so need more ems. */
font-size: 1.4545em;
border-bottom: 1px solid hsla(240, 5%, 5%, .1);
background-color: transparent;
}
.sidebar-splitter {
@ -2143,6 +2144,7 @@ html|*.addon-webext-perm-list {
%include ../shared/customizableui/customizeMode.inc.css
%ifndef MOZ_PHOTON_THEME
#main-window[customizing] {
background-color: rgb(178,178,178);
}
@ -2206,7 +2208,9 @@ html|*.addon-webext-perm-list {
border-right: 3px solid transparent;
border-left: 3px solid transparent;
}
%endif
%ifndef MOZ_PHOTON_THEME
@media (min-resolution: 2dppx) {
.customization-tipPanel-infoBox {
background-image: url(chrome://browser/skin/customizableui/info-icon-customizeTip@2x.png);
@ -2226,6 +2230,7 @@ html|*.addon-webext-perm-list {
list-style-image: url("chrome://browser/skin/customizableui/panelarrow-customizeTip@2x.png");
}
}
%endif
/* End customization mode */

Просмотреть файл

@ -50,9 +50,9 @@ browser.jar:
skin/classic/browser/webRTC-sharingScreen-menubar@2x.png
skin/classic/browser/webRTC-indicator.css
* skin/classic/browser/controlcenter/panel.css (controlcenter/panel.css)
#ifndef MOZ_PHOTON_THEME
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
#ifndef MOZ_PHOTON_THEME
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)
#endif

Просмотреть файл

@ -8,6 +8,7 @@
--drag-drop-transition-duration: .3s;
}
%ifndef MOZ_PHOTON_THEME
#main-window[customization-lwtheme] #tab-view-deck:-moz-lwtheme {
background-repeat: no-repeat;
background-position: right top;
@ -39,7 +40,6 @@
pointer-events: none;
}
%ifndef MOZ_PHOTON_THEME
#main-window[customize-entered] .customization-target:not(:-moz-any(#PanelUI-contents, #TabsToolbar, #toolbar-menubar))::before,
#PanelUI-contents > .panel-customization-placeholder {
-moz-outline-radius: 2.5px;
@ -570,4 +570,31 @@ toolbarpaletteitem[place="toolbar"]:not([mousedown="true"]):-moz-focusring {
margin-inline-start: 22.35em;
}
%ifdef MOZ_PHOTON_THEME
#customization-panelHolder > #widget-overflow-fixed-list:not(:empty) {
padding-bottom: 50px; /* Make sure there's always space to drop stuff. */
}
#customization-panelHolder > #widget-overflow-fixed-list:empty {
background-image: url("chrome://browser/skin/customizableui/empty-overflow-panel.png");
background-position: center top 10px;
background-size: 218px 134px;
background-repeat: no-repeat;
}
#customization-panelHolder > #widget-overflow-fixed-list:empty::after {
content: attr(emptylabel);
padding: 154px 10px 10px; /* 154 = 134 for the image, 10px space on either side. */
text-align: center;
display: block;
}
@media (min-resolution: 1.1dppx) {
#customization-panelHolder > #widget-overflow-fixed-list:empty {
background-image: url("chrome://browser/skin/customizableui/empty-overflow-panel@2x.png");
}
}
%else
%include customizeTip.inc.css
%endif

Двоичные данные
browser/themes/shared/customizableui/empty-overflow-panel.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 14 KiB

Двоичные данные
browser/themes/shared/customizableui/empty-overflow-panel@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 35 KiB

Просмотреть файл

@ -352,7 +352,7 @@ panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
photonpanelmultiview panelview {
background: var(--arrowpanel-background);
padding: 6px 0;
padding: 0;
}
#appMenu-popup panelview,
@ -361,8 +361,8 @@ photonpanelmultiview panelview {
max-width: 30em;
}
photonpanelmultiview panelview[title] {
padding-top: 0;
photonpanelmultiview .panel-subview-body {
margin: 4px 0;
}
/* END photonpanelview adjustments */
@ -1260,11 +1260,12 @@ panelview:not([mainView]) .subviewbutton.panel-subview-footer > .toolbarbutton-t
/* START photon adjustments */
photonpanelmultiview .PanelUI-subView .subviewbutton:not(.panel-subview-footer) {
photonpanelmultiview .PanelUI-subView .subviewbutton,
photonpanelmultiview .cui-widget-panelview .subviewbutton:not(.panel-subview-footer),
photonpanelmultiview .subview-subheader {
border-radius: 0;
border-width: 0;
margin-left: 0;
margin-right: 0;
margin: 0;
padding: 4px 12px;
}
@ -1277,7 +1278,7 @@ photonpanelmultiview .subviewbutton > .toolbarbutton-text {
padding-inline-start: 24px; /* This is 16px for the icon + 8px for the padding as defined above. */
}
photonpanelmultiview .subviewbutton-iconic:not(.subviewbutton-back) > .toolbarbutton-text,
photonpanelmultiview .subviewbutton-iconic > .toolbarbutton-text,
photonpanelmultiview .cui-withicon > .toolbarbutton-text,
photonpanelmultiview .subviewbutton[image] > .toolbarbutton-text,
photonpanelmultiview .subviewbutton[checked="true"] > .toolbarbutton-text {
@ -1290,10 +1291,6 @@ photonpanelmultiview .panel-banner-item > .toolbarbutton-multiline-text {
padding-inline-start: 8px; /* See '.subviewbutton-iconic > .toolbarbutton-text' rule above. */
}
photonpanelmultiview .PanelUI-subView .panel-subview-footer {
font-size: 1.2rem;
}
photonpanelmultiview .subviewbutton {
-moz-context-properties: fill;
fill: currentColor;
@ -1367,6 +1364,19 @@ photonpanelmultiview .panel-banner-item::after {
margin-inline-start: 10px;
}
photonpanelmultiview .subview-subheader {
color: GrayText;
}
photonpanelmultiview .subview-subheader,
photonpanelmultiview .panel-subview-footer {
font: menu;
}
photonpanelmultiview panelview:not([mainView]) .subviewbutton.panel-subview-footer > .toolbarbutton-text {
text-align: start;
}
/* END photon adjustments */
panelview .toolbarbutton-1,
@ -2075,7 +2085,6 @@ menuitem[checked="true"].subviewbutton > .menu-iconic-left {
display: flex;
flex: 1 auto;
height: 40px; /* fixed item height to prevent flex sizing; height + 2*4px padding */
margin-bottom: 6px;
padding: 4px;
}
@ -2121,4 +2130,8 @@ photonpanelmultiview .cui-widget-panelview {
overflow-y: visible;
}
photonpanelmultiview #panelMenu_pocket {
display: none;
}
/* END photon adjustments */

Просмотреть файл

@ -0,0 +1,24 @@
<!-- 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="16" height="16" viewBox="0 0 16 16">
<style>
:root > use:not(:target),
:root > g:not(:target) {
display: none;
}
</style>
<defs>
<path id="arrow-icon" d="M7.293 12.725a1 1 0 0 0 1.414 0l5-5a1 1 0 0 0-1.414-1.413L9 9.605V1.019a1 1 0 0 0-2 0v8.586L3.707 6.312a1 1 0 0 0-1.414 1.413l5 5z"/>
<path id="short-bar-icon" d="m 13,14 a 1,1 0 1 1 0,2 h -10 a 1,1 0 1 1 0,-2 z"/>
<path id="long-bar-icon" d="m 14,14 a 1,1 0 1 1 0,2 h -12 a 1,1 0 1 1 0,-2"/>
</defs>
<use id="arrow" fill="context-fill" href="#arrow-icon"/>
<g id="arrow-with-bar" fill="context-fill">
<use href="#arrow-icon"/>
<use href="#short-bar-icon"/>
</g>
<use id="default-bar" fill="context-fill" href="#short-bar-icon"/>
<use id="progress-bar-bg" fill="context-fill" fill-opacity="0.2" href="#long-bar-icon"/>
<use id="progress-bar-fg" fill="context-fill" href="#long-bar-icon"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -6,7 +6,7 @@
#downloads-button {
%ifdef MOZ_PHOTON_THEME
--downloads-indicator-image: url("chrome://browser/skin/download-arrow-with-bar.svg");
--downloads-indicator-image: url("chrome://browser/skin/downloads/download-icons.svg#arrow-with-bar");
%else
--downloads-indicator-image: url("chrome://browser/skin/download.svg");
%endif
@ -17,34 +17,63 @@
min-height: 16px;
}
#downloads-indicator-icon {
background: var(--downloads-indicator-image) center no-repeat;
-moz-context-properties: fill;
fill: var(--toolbarbutton-icon-fill);
#downloads-indicator-progress-outer {
width: 16px;
height: 16px;
background-size: 16px;
fill: var(--toolbarbutton-icon-fill);
-moz-context-properties: fill;
%ifdef MOZ_PHOTON_ANIMATIONS
background: url("chrome://browser/skin/downloads/download-icons.svg#default-bar") center no-repeat;
%else
background: var(--downloads-indicator-image) center no-repeat;
%endif
}
toolbar[brighttext] #downloads-button:not([attention="success"]) > #downloads-indicator-anchor > #downloads-indicator-icon {
%ifdef MOZ_PHOTON_ANIMATIONS
toolbar[brighttext] #downloads-button:not([attention="success"]) > #downloads-indicator-anchor > #downloads-indicator-icon,
%endif
toolbar[brighttext] #downloads-button:not([attention="success"]) > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
fill: var(--toolbarbutton-icon-fill-inverted);
}
#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-icon {
%ifdef MOZ_PHOTON_ANIMATIONS
#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-icon,
%endif
#downloads-button[attention="success"] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
fill: var(--toolbarbutton-icon-fill-attention);
}
%ifdef MOZ_PHOTON_ANIMATIONS
#downloads-button[progress] > #downloads-indicator-anchor > #downloads-indicator-progress-outer {
background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar-bg") center no-repeat;
}
%endif
#downloads-button[attention="success"] {
list-style-image: url("chrome://browser/skin/downloads/download-glow-menuPanel.png");
-moz-image-region: auto;
}
#downloads-indicator-progress-icon {
%ifdef MOZ_PHOTON_ANIMATIONS
#downloads-indicator-icon {
-moz-context-properties: fill;
background-image: url("chrome://browser/skin/downloads/download-icons.svg#arrow");
width: 16px;
height: 16px;
}
%endif
#downloads-indicator-progress-inner {
%ifdef MOZ_PHOTON_ANIMATIONS
background: url("chrome://browser/skin/downloads/download-icons.svg#progress-bar-fg") left no-repeat;
margin-right: 16px;
%else
background: var(--downloads-indicator-image) bottom no-repeat;
margin-top: 16px;
%endif
-moz-context-properties: fill;
fill: var(--toolbarbutton-icon-fill-attention);
background-size: 16px;
margin-top: 16px;
/* From javascript side we use animation delay from 0s to -100s to show
* corresponding frames needed for progress.
* animation-delay is set to a positive value to make nothing shown.
@ -56,21 +85,32 @@ toolbar[brighttext] #downloads-button:not([attention="success"]) > #downloads-in
animation-name: indicatorArrowProgress;
}
toolbar[brighttext] #downloads-indicator-progress-icon {
%ifndef MOZ_PHOTON_ANIMATIONS
toolbar[brighttext] #downloads-indicator-progress-inner {
animation-name: indicatorArrowProgressDark;
}
%endif
@keyframes indicatorArrowProgress {
0% {
%ifdef MOZ_PHOTON_ANIMATIONS
margin-right: 14px;
%else
margin-top: 12px;
filter: brightness(1.2);
%endif
}
100% {
%ifdef MOZ_PHOTON_ANIMATIONS
margin-right: 2px;
%else
margin-top: 2px;
filter: brightness(1);
%endif
}
}
%ifndef MOZ_PHOTON_ANIMATIONS
@keyframes indicatorArrowProgressDark {
0% {
margin-top: 12px;
@ -81,6 +121,7 @@ toolbar[brighttext] #downloads-indicator-progress-icon {
filter: brightness(1);
}
}
%endif
/*** Status badges ***/
@ -114,10 +155,14 @@ toolbar[brighttext] #downloads-indicator-progress-icon {
filter: none;
}
/*** Download notifications ***/
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-icon {
%ifdef MOZ_PHOTON_ANIMATIONS
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-icon
%else
#downloads-button[notification="start"] > #downloads-indicator-anchor > #downloads-indicator-progress-outer
%endif
{
animation-name: downloadsIndicatorStartJump;
/* Upon changing the overall duration below, please keep the delay time of
setTimeout() identical in indicator.js for this animation. */

Просмотреть файл

@ -1,6 +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="16" height="16" viewBox="0 0 16 16">
<path fill="context-fill" d="M13 14H3a1 1 0 0 0 0 2h10a1 1 0 0 0 0-2zm-5.707-1.275a1 1 0 0 0 1.414 0l5-5a1 1 0 0 0-1.414-1.413L9 9.605V1.019a1 1 0 0 0-2 0v8.586L3.707 6.312a1 1 0 0 0-1.414 1.413l5 5z"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 510 B

Просмотреть файл

@ -34,16 +34,21 @@
skin/classic/browser/controlcenter/warning-gray.svg (../shared/controlcenter/warning-gray.svg)
skin/classic/browser/controlcenter/warning-yellow.svg (../shared/controlcenter/warning-yellow.svg)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png (../shared/customizableui/menuPanel-customizeFinish@2x.png)
#ifdef MOZ_PHOTON_THEME
skin/classic/browser/customizableui/empty-overflow-panel.png (../shared/customizableui/empty-overflow-panel.png)
skin/classic/browser/customizableui/empty-overflow-panel@2x.png (../shared/customizableui/empty-overflow-panel@2x.png)
#else
skin/classic/browser/customizableui/customize-illustration.png (../shared/customizableui/customize-illustration.png)
skin/classic/browser/customizableui/customize-illustration@2x.png (../shared/customizableui/customize-illustration@2x.png)
skin/classic/browser/customizableui/customize-illustration-rtl.png (../shared/customizableui/customize-illustration-rtl.png)
skin/classic/browser/customizableui/customize-illustration-rtl@2x.png (../shared/customizableui/customize-illustration-rtl@2x.png)
skin/classic/browser/customizableui/info-icon-customizeTip.png (../shared/customizableui/info-icon-customizeTip.png)
skin/classic/browser/customizableui/info-icon-customizeTip@2x.png (../shared/customizableui/info-icon-customizeTip@2x.png)
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png (../shared/customizableui/menuPanel-customizeFinish@2x.png)
skin/classic/browser/customizableui/panelarrow-customizeTip.png (../shared/customizableui/panelarrow-customizeTip.png)
skin/classic/browser/customizableui/panelarrow-customizeTip@2x.png (../shared/customizableui/panelarrow-customizeTip@2x.png)
#endif
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted@2x.png (../shared/customizableui/subView-arrow-back-inverted@2x.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
@ -53,6 +58,9 @@
skin/classic/browser/downloads/contentAreaDownloadsView.css (../shared/downloads/contentAreaDownloadsView.css)
skin/classic/browser/downloads/download-blocked.svg (../shared/downloads/download-blocked.svg)
skin/classic/browser/downloads/download-summary.svg (../shared/downloads/download-summary.svg)
#ifdef MOZ_PHOTON_THEME
skin/classic/browser/downloads/download-icons.svg (../shared/downloads/download-icons.svg)
#endif
skin/classic/browser/drm-icon.svg (../shared/drm-icon.svg)
skin/classic/browser/fullscreen/insecure.svg (../shared/fullscreen/insecure.svg)
skin/classic/browser/fullscreen/secure.svg (../shared/fullscreen/secure.svg)
@ -122,9 +130,7 @@
skin/classic/browser/developer.svg (../shared/icons/developer.svg)
skin/classic/browser/device-mobile.svg (../shared/icons/device-mobile.svg)
skin/classic/browser/device-desktop.svg (../shared/icons/device-desktop.svg)
#ifdef MOZ_PHOTON_THEME
skin/classic/browser/download-arrow-with-bar.svg (../shared/icons/download-arrow-with-bar.svg)
#else
#ifndef MOZ_PHOTON_THEME
skin/classic/browser/download.svg (../shared/icons/download.svg)
#endif
skin/classic/browser/edit-copy.svg (../shared/icons/edit-copy.svg)

Просмотреть файл

@ -212,7 +212,8 @@ toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
list-style-image: url(chrome://browser/skin/customize.svg);
}
#appMenu-find-button {
#appMenu-find-button,
#panelMenu_searchBookmarks {
list-style-image: url(chrome://browser/skin/find.svg);
}
@ -269,10 +270,20 @@ toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
}
#appMenuViewHistorySidebar,
#PanelUI-remotetabs-view-sidebar {
#PanelUI-remotetabs-view-sidebar,
#panelMenu_viewBookmarksSidebar {
list-style-image: url("chrome://browser/skin/sidebars.svg");
}
#appMenu-library-bookmarks-button,
#panelMenuBookmarkThisPage {
list-style-image: url("chrome://browser/skin/bookmark-hollow.svg");
}
#panelMenuBookmarkThisPage[starred] {
list-style-image: url("chrome://browser/skin/bookmark.svg");
}
%ifdef MOZ_PHOTON_THEME
#bookmarks-menu-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #bookmarks-menu-button {

Просмотреть файл

@ -143,13 +143,13 @@
.tab-icon-overlay[soundplaying],
.tab-icon-overlay[muted]:not([crashed]),
.tab-icon-overlay[blocked]:not([crashed]) {
.tab-icon-overlay[activemedia-blocked]:not([crashed]) {
border-radius: 10px;
}
.tab-icon-overlay[soundplaying]:hover,
.tab-icon-overlay[muted]:not([crashed]):hover,
.tab-icon-overlay[blocked]:not([crashed]):hover {
.tab-icon-overlay[activemedia-blocked]:not([crashed]):hover {
background-color: white;
}
@ -161,7 +161,7 @@
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-muted");
}
.tab-icon-overlay[blocked]:not([crashed]) {
.tab-icon-overlay[activemedia-blocked]:not([crashed]) {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-blocked");
}
@ -175,8 +175,8 @@
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-muted");
}
#TabsToolbar[brighttext] .tab-icon-overlay[blocked]:not([crashed]):not([selected]):not(:hover),
.tab-icon-overlay[blocked][selected]:-moz-lwtheme-brighttext:not(:hover) {
#TabsToolbar[brighttext] .tab-icon-overlay[activemedia-blocked]:not([crashed]):not([selected]):not(:hover),
.tab-icon-overlay[activemedia-blocked][selected]:-moz-lwtheme-brighttext:not(:hover) {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-small.svg#tab-audio-white-blocked");
}
@ -208,7 +208,7 @@
.tab-icon-sound[soundplaying],
.tab-icon-sound[muted],
.tab-icon-sound[blocked] {
.tab-icon-sound[activemedia-blocked] {
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-playing.svg);
-moz-context-properties: fill;
fill: currentColor;
@ -218,25 +218,25 @@
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-muted.svg);
}
.tab-icon-sound[blocked] {
.tab-icon-sound[activemedia-blocked] {
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-blocked.svg);
}
.tab-icon-sound:-moz-lwtheme-darktext[soundplaying],
.tab-icon-sound:-moz-lwtheme-darktext[muted],
.tab-icon-sound:-moz-lwtheme-darktext[blocked] {
.tab-icon-sound:-moz-lwtheme-darktext[activemedia-blocked] {
filter: drop-shadow(1px 1px 1px white);
}
.tab-icon-sound:-moz-lwtheme-brighttext[soundplaying],
.tab-icon-sound:-moz-lwtheme-brighttext[muted],
.tab-icon-sound:-moz-lwtheme-brighttext[blocked] {
.tab-icon-sound:-moz-lwtheme-brighttext[activemedia-blocked] {
filter: drop-shadow(1px 1px 1px black);
}
.tab-icon-sound[soundplaying]:not(:hover),
.tab-icon-sound[muted]:not(:hover),
.tab-icon-sound[blocked]:not(:hover) {
.tab-icon-sound[activemedia-blocked]:not(:hover) {
opacity: .8;
}
@ -455,7 +455,7 @@
.tabs-newtab-button,
.tab-icon-overlay[soundplaying],
.tab-icon-overlay[muted]:not([crashed]),
.tab-icon-overlay[blocked]:not([crashed]),
.tab-icon-overlay[activemedia-blocked]:not([crashed]),
.tab-icon-sound,
.tab-close-button {
pointer-events: auto;
@ -591,7 +591,7 @@
.alltabs-endimage[soundplaying],
.alltabs-endimage[muted],
.alltabs-endimage[blocked] {
.alltabs-endimage[activemedia-blocked] {
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-playing.svg);
-moz-context-properties: fill;
fill: currentColor;
@ -601,7 +601,7 @@
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-muted.svg);
}
.alltabs-endimage[blocked] {
.alltabs-endimage[activemedia-blocked] {
list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-blocked.svg);
}

Просмотреть файл

@ -80,7 +80,7 @@ toolbar:not([brighttext]) #bookmarks-menu-button[cui-areatype="toolbar"][starred
#downloads-button[cui-areatype="toolbar"] {
%ifdef MOZ_PHOTON_THEME
list-style-image: url("chrome://browser/skin/download-arrow-with-bar.svg");
list-style-image: url("chrome://browser/skin/downloads/download-icons.svg#arrow-with-bar");
%else
list-style-image: url("chrome://browser/skin/download.svg");
%endif

Просмотреть файл

@ -473,7 +473,6 @@ toolbarbutton.bookmark-item:not(.subviewbutton) {
display: -moz-box !important;
}
.bookmark-item > .toolbarbutton-icon[label]:not([label=""]) {
#PlacesToolbarItems > .bookmark-item > .toolbarbutton-icon[label]:not([label=""]) {
margin-inline-end: 5px;
}

Просмотреть файл

@ -1838,6 +1838,7 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton {
transform: perspective(0.01px);
}
%ifndef MOZ_PHOTON_THEME
#main-window[customize-entered] > #tab-view-deck {
background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png");
background-attachment: fixed;
@ -1860,6 +1861,7 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton {
#main-window[customize-entered] #browser-bottombox {
border-bottom: 1px solid @toolbarShadowColor@;
}
%endif
#customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="left"] {
margin-right: -2px;

Просмотреть файл

@ -159,4 +159,14 @@ photonpanelmultiview .subviewbutton > .toolbarbutton-icon {
padding: 0;
}
photonpanelmultiview .subviewbutton:-moz-any([image],[targetURI],.cui-withicon,
.restoreallitem, .bookmark-item) > .toolbarbutton-text {
padding-inline-start: 8px;
}
photonpanelmultiview .subviewbutton:-moz-any([image],[targetURI],.cui-withicon,
.restoreallitem, .bookmark-item)[checked="true"] > .toolbarbutton-icon {
visibility: visible;
}
/* END photon adjustments */

Просмотреть файл

@ -54,8 +54,8 @@ browser.jar:
skin/classic/browser/urlbar-history-dropmarker-win7@2x.png
skin/classic/browser/webRTC-indicator.css (../shared/webRTC-indicator.css)
* skin/classic/browser/controlcenter/panel.css (controlcenter/panel.css)
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
#ifndef MOZ_PHOTON_THEME
skin/classic/browser/customizableui/customizeMode-gridTexture.png (customizableui/customizeMode-gridTexture.png)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png (customizableui/customizeMode-separatorHorizontal.png)
skin/classic/browser/customizableui/customizeMode-separatorVertical.png (customizableui/customizeMode-separatorVertical.png)

Просмотреть файл

@ -80,6 +80,28 @@ if test -n "$MOZ_TSAN"; then
fi
AC_SUBST(MOZ_TSAN)
dnl ========================================================
dnl = Use UndefinedBehavior Sanitizer to find integer overflows
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(ubsan-int-overflow,
[ --enable-ubsan-int-overflow Enable UndefinedBehavior Sanitizer (Integer Overflow Parts, default=no)],
MOZ_UBSAN_INT_OVERFLOW=1,
MOZ_UBSAN_INT_OVERFLOW= )
if test -n "$MOZ_UBSAN_INT_OVERFLOW"; then
MOZ_LLVM_HACKS=1
MOZ_UBSAN=1
CFLAGS="-fsanitize=integer -fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_blacklist_int.txt $CFLAGS"
CXXFLAGS="-fsanitize=integer -fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_blacklist_int.txt $CXXFLAGS"
if test -z "$CLANG_CL"; then
LDFLAGS="-fsanitize=integer $LDFLAGS"
fi
AC_DEFINE(MOZ_UBSAN_INT_OVERFLOW)
AC_DEFINE(MOZ_UBSAN)
MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
fi
AC_SUBST(MOZ_UBSAN_INT_OVERFLOW)
AC_SUBST(MOZ_UBSAN)
# The LLVM symbolizer is used by all sanitizers
AC_SUBST(LLVM_SYMBOLIZER)

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше