зеркало из https://github.com/mozilla/gecko-dev.git
merge autoland to mozilla-central a=merge
This commit is contained in:
Коммит
95e5b4e67b
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 14 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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)
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче