summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--application/palemoon/app/profile/palemoon.js2
-rw-r--r--application/palemoon/base/content/browser.css8
-rw-r--r--application/palemoon/base/content/tabbrowser.xml8
-rw-r--r--application/palemoon/branding/unstable/pref/palemoon-branding.js4
-rw-r--r--application/palemoon/installer/package-manifest.in2
-rw-r--r--browser/app/permissions8
-rw-r--r--browser/app/profile/firefox.js16
-rw-r--r--browser/base/content/baseMenuOverlay.xul4
-rw-r--r--browser/base/content/browser-trackingprotection.js62
-rw-r--r--browser/base/content/browser.css65
-rwxr-xr-xbrowser/base/content/browser.js8
-rw-r--r--browser/base/content/browser.xul36
-rw-r--r--browser/base/content/tab-content.js5
-rw-r--r--browser/base/content/utilityOverlay.js7
-rw-r--r--browser/components/customizableui/CustomizeMode.jsm44
-rw-r--r--browser/components/customizableui/content/panelUI.inc.xul19
-rw-r--r--browser/components/moz.build1
-rw-r--r--browser/components/nsBrowserGlue.js14
-rw-r--r--browser/components/preferences/blocklists.js2
-rw-r--r--browser/components/preferences/jar.mn2
-rw-r--r--browser/components/privatebrowsing/content/aboutPrivateBrowsing.js11
-rw-r--r--browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml3
-rw-r--r--browser/components/uitour/UITour-lib.js331
-rw-r--r--browser/components/uitour/UITour.jsm2111
-rw-r--r--browser/components/uitour/content-UITour.js103
-rw-r--r--browser/components/uitour/jar.mn6
-rw-r--r--browser/components/uitour/moz.build9
-rw-r--r--browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd3
-rw-r--r--browser/locales/en-US/chrome/browser/browser.dtd2
-rw-r--r--browser/locales/en-US/chrome/browser/browser.properties16
-rw-r--r--browser/modules/BrowserUITelemetry.jsm7
-rw-r--r--browser/modules/SelfSupportBackend.jsm331
-rw-r--r--browser/modules/moz.build1
-rw-r--r--browser/themes/linux/browser.css39
-rw-r--r--browser/themes/osx/browser.css36
-rw-r--r--browser/themes/shared/UITour.inc.css293
-rw-r--r--browser/themes/shared/customizableui/customizeMode.inc.css2
-rw-r--r--browser/themes/shared/customizableui/customizeTip.inc.css77
-rw-r--r--browser/themes/windows/browser.css20
-rw-r--r--browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm2
-rw-r--r--build/autoconf/compiler-opts.m44
-rw-r--r--build/moz.configure/old.configure1
-rw-r--r--parser/html/nsHtml5TreeOpExecutor.cpp7
-rw-r--r--python/mozbuild/mozbuild/mach_commands.py10
-rw-r--r--testing/profiles/prefs_general.js4
-rw-r--r--toolkit/components/reader/JSDOMParser.js21
-rw-r--r--toolkit/components/reader/Readability.js67
-rw-r--r--toolkit/components/reader/ReaderWorker.js2
-rw-r--r--toolkit/mozapps/installer/packager.py22
49 files changed, 93 insertions, 3765 deletions
diff --git a/application/palemoon/app/profile/palemoon.js b/application/palemoon/app/profile/palemoon.js
index 000113fe72..014550190f 100644
--- a/application/palemoon/app/profile/palemoon.js
+++ b/application/palemoon/app/profile/palemoon.js
@@ -433,8 +433,6 @@ pref("browser.tabs.loadDivertedInBackground", false);
pref("browser.tabs.loadBookmarksInBackground", false);
pref("browser.tabs.noWindowActivationOnExternal", false);
pref("browser.tabs.tabClipWidth", 140);
-pref("browser.tabs.tabMinWidth", 100);
-pref("browser.tabs.tabMaxWidth", 250);
pref("browser.tabs.animate", true);
pref("browser.tabs.onTop", true);
#ifdef XP_WIN
diff --git a/application/palemoon/base/content/browser.css b/application/palemoon/base/content/browser.css
index 76e49436c5..a2970aefc3 100644
--- a/application/palemoon/base/content/browser.css
+++ b/application/palemoon/base/content/browser.css
@@ -43,6 +43,8 @@ tabbrowser {
.tabbrowser-tab:not([pinned]) {
-moz-box-flex: 100;
+ max-width: 250px;
+ min-width: 100px;
width: 0;
transition: min-width 175ms ease-out,
max-width 200ms ease-out,
@@ -65,12 +67,6 @@ tabbrowser {
display: none;
}
-.tabbrowser-tab[pinned] {
- -moz-box-flex: 0;
- min-width: 0 !important;
- max-width: none !important;
-}
-
.tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
position: fixed !important;
display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
diff --git a/application/palemoon/base/content/tabbrowser.xml b/application/palemoon/base/content/tabbrowser.xml
index a0ee593502..12319a62b1 100644
--- a/application/palemoon/base/content/tabbrowser.xml
+++ b/application/palemoon/base/content/tabbrowser.xml
@@ -1445,9 +1445,6 @@
t.setAttribute("label", aURI);
t.setAttribute("crop", "end");
- t.style.maxWidth = this.tabContainer.mTabMaxWidth + "px";
- t.style.minWidth = this.tabContainer.mTabMinWidth + "px";
- t.width = 0;
t.setAttribute("validate", "never"); //PMed
t.setAttribute("onerror", "this.removeAttribute('image');");
t.className = "tabbrowser-tab";
@@ -3429,8 +3426,6 @@
<implementation implements="nsIDOMEventListener">
<constructor>
<![CDATA[
- this.mTabMinWidth = Services.prefs.getIntPref("browser.tabs.tabMinWidth");
- this.mTabMaxWidth = Services.prefs.getIntPref("browser.tabs.tabMaxWidth");
this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
this.mCloseButtons = Services.prefs.getIntPref("browser.tabs.closeButtons");
this._closeWindowWithLastTab = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab");
@@ -3438,9 +3433,6 @@
var tab = this.firstChild;
tab.setAttribute("label",
this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle"));
- tab.style.minWidth = this.mTabMinWidth + "px";
- tab.style.maxWidth = this.mTabMaxWidth + "px";
- tab.width = 0;
tab.setAttribute("crop", "end");
tab.setAttribute("onerror", "this.removeAttribute('image');");
this.adjustTabstrip();
diff --git a/application/palemoon/branding/unstable/pref/palemoon-branding.js b/application/palemoon/branding/unstable/pref/palemoon-branding.js
index dda6f86a5f..a95390cb67 100644
--- a/application/palemoon/branding/unstable/pref/palemoon-branding.js
+++ b/application/palemoon/branding/unstable/pref/palemoon-branding.js
@@ -12,7 +12,7 @@ pref("general.useragent.compatMode.gecko", true);
pref("general.useragent.compatMode.firefox", true);
// ========================= updates ========================
-#if defined(XP_WIN)
+#if defined(XP_WIN) || defined(XP_LINUX)
// Enable auto-updates for this channel
pref("app.update.auto", true);
@@ -32,7 +32,7 @@ pref("app.update.url.manual", "http://www.palemoon.org/unstable/");
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "http://www.palemoon.org/unstable/");
#else
-// Updates disabled (Linux, etc.)
+// Updates disabled (Mac, etc.)
pref("app.update.enabled", false);
pref("app.update.url", "");
#endif
diff --git a/application/palemoon/installer/package-manifest.in b/application/palemoon/installer/package-manifest.in
index fb54418326..26b4969d6c 100644
--- a/application/palemoon/installer/package-manifest.in
+++ b/application/palemoon/installer/package-manifest.in
@@ -56,7 +56,7 @@
@RESPATH@/hyphenation/*
@RESPATH@/browser/@PREF_DIR@/palemoon-l10n.js
@RESPATH@/browser/searchplugins/*
-#ifdef HAVE_MAKENSISU
+#ifdef XP_WIN32
@BINPATH@/uninstall/helper.exe
#endif
#ifdef MOZ_UPDATER
diff --git a/browser/app/permissions b/browser/app/permissions
index a2afdded2d..cf0aa22fbf 100644
--- a/browser/app/permissions
+++ b/browser/app/permissions
@@ -6,14 +6,6 @@
# * permission is an integer between 1 and 15
# See nsPermissionManager.cpp for more...
-# UITour
-origin uitour 1 https://www.mozilla.org
-origin uitour 1 https://self-repair.mozilla.org
-origin uitour 1 https://support.mozilla.org
-origin uitour 1 https://addons.mozilla.org
-origin uitour 1 https://discovery.addons.mozilla.org
-origin uitour 1 about:home
-
# XPInstall
origin install 1 https://addons.mozilla.org
origin install 1 https://testpilot.firefox.com
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index ede62fd5e1..2babde3b01 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -178,20 +178,6 @@ pref("browser.eme.ui.enabled", true);
pref("browser.eme.ui.enabled", false);
#endif
-// UI tour experience.
-pref("browser.uitour.enabled", true);
-pref("browser.uitour.loglevel", "Error");
-pref("browser.uitour.requireSecure", true);
-pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
-pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
-// This is used as a regexp match against the page's URL.
-pref("browser.uitour.readerViewTrigger", "^https:\\/\\/www\\.mozilla\\.org\\/[^\\/]+\\/firefox\\/reading\\/start");
-// How long to show a Hearbeat survey (two hours, in seconds)
-pref("browser.uitour.surveyDuration", 7200);
-
-pref("browser.customizemode.tip0.shown", false);
-pref("browser.customizemode.tip0.learnMoreUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/customize");
-
pref("keyword.enabled", true);
pref("browser.fixup.domainwhitelist.localhost", true);
@@ -1301,8 +1287,6 @@ pref("privacy.trackingprotection.ui.enabled", true);
#else
pref("privacy.trackingprotection.ui.enabled", false);
#endif
-pref("privacy.trackingprotection.introCount", 0);
-pref("privacy.trackingprotection.introURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tracking-protection/start/");
// Enable Contextual Identity Containers
#ifdef NIGHTLY_BUILD
diff --git a/browser/base/content/baseMenuOverlay.xul b/browser/base/content/baseMenuOverlay.xul
index da74ca077c..546103de10 100644
--- a/browser/base/content/baseMenuOverlay.xul
+++ b/browser/base/content/baseMenuOverlay.xul
@@ -52,10 +52,6 @@
#else
/>
#endif
- <menuitem id="menu_openTour"
- oncommand="openTourPage();"
- label="&helpShowTour2.label;"
- accesskey="&helpShowTour2.accesskey;"/>
<menuitem id="menu_keyboardShortcuts"
oncommand="openHelpLink('keyboard-shortcuts')"
onclick="checkForMiddleClick(this, event);"
diff --git a/browser/base/content/browser-trackingprotection.js b/browser/base/content/browser-trackingprotection.js
index cacb0522c0..20917a0831 100644
--- a/browser/base/content/browser-trackingprotection.js
+++ b/browser/base/content/browser-trackingprotection.js
@@ -4,7 +4,6 @@
var TrackingProtection = {
// If the user ignores the doorhanger, we stop showing it after some time.
- MAX_INTROS: 20,
PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
enabledGlobally: false,
@@ -106,16 +105,6 @@ var TrackingProtection = {
this.icon.setAttribute("state", "blocked-tracking-content");
this.content.setAttribute("state", "blocked-tracking-content");
- // Open the tracking protection introduction panel, if applicable.
- if (this.enabledGlobally) {
- let introCount = gPrefService.getIntPref("privacy.trackingprotection.introCount");
- if (introCount < TrackingProtection.MAX_INTROS) {
- gPrefService.setIntPref("privacy.trackingprotection.introCount", ++introCount);
- gPrefService.savePrefFile(null);
- this.showIntroPanel();
- }
- }
-
this.shieldHistogramAdd(2);
} else if (isAllowing) {
this.icon.setAttribute("tooltiptext", this.disabledTooltipText);
@@ -185,55 +174,4 @@ var TrackingProtection = {
BrowserReload();
},
-
- dontShowIntroPanelAgain() {
- // This function may be called in private windows, but it does not change
- // any preference unless Tracking Protection is enabled globally.
- if (this.enabledGlobally) {
- gPrefService.setIntPref("privacy.trackingprotection.introCount",
- this.MAX_INTROS);
- gPrefService.savePrefFile(null);
- }
- },
-
- showIntroPanel: Task.async(function*() {
- let brandBundle = document.getElementById("bundle_brand");
- let brandShortName = brandBundle.getString("brandShortName");
-
- let openStep2 = () => {
- // When the user proceeds in the tour, adjust the counter to indicate that
- // the user doesn't need to see the intro anymore.
- this.dontShowIntroPanelAgain();
-
- let nextURL = Services.urlFormatter.formatURLPref("privacy.trackingprotection.introURL") +
- "?step=2&newtab=true";
- switchToTabHavingURI(nextURL, true, {
- // Ignore the fragment in case the intro is shown on the tour page
- // (e.g. if the user manually visited the tour or clicked the link from
- // about:privatebrowsing) so we can avoid a reload.
- ignoreFragment: "whenComparingAndReplace",
- });
- };
-
- let buttons = [
- {
- label: gNavigatorBundle.getString("trackingProtection.intro.step1of3"),
- style: "text",
- },
- {
- callback: openStep2,
- label: gNavigatorBundle.getString("trackingProtection.intro.nextButton.label"),
- style: "primary",
- },
- ];
-
- let panelTarget = yield UITour.getTarget(window, "trackingProtection");
- UITour.initForBrowser(gBrowser.selectedBrowser, window);
- UITour.showInfo(window, panelTarget,
- gNavigatorBundle.getString("trackingProtection.intro.title"),
- gNavigatorBundle.getFormattedString("trackingProtection.intro.description2",
- [brandShortName]),
- undefined, buttons,
- { closeButtonCallback: () => this.dontShowIntroPanelAgain() });
- }),
};
diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
index ac5bf9e9b6..e951985dc1 100644
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1152,71 +1152,6 @@ toolbarpaletteitem[place="palette"][hidden] {
display: none;
}
-/* UI Tour */
-
-@keyframes uitour-wobble {
- from {
- transform: rotate(0deg) translateX(3px) rotate(0deg);
- }
- 50% {
- transform: rotate(360deg) translateX(3px) rotate(-360deg);
- }
- to {
- transform: rotate(720deg) translateX(0px) rotate(-720deg);
- }
-}
-
-@keyframes uitour-zoom {
- from {
- transform: scale(0.8);
- }
- 50% {
- transform: scale(1.0);
- }
- to {
- transform: scale(0.8);
- }
-}
-
-@keyframes uitour-color {
- from {
- border-color: #5B9CD9;
- }
- 50% {
- border-color: #FF0000;
- }
- to {
- border-color: #5B9CD9;
- }
-}
-
-#UITourHighlightContainer,
-#UITourHighlight {
- pointer-events: none;
-}
-
-#UITourHighlight[active] {
- animation-delay: 2s;
- animation-fill-mode: forwards;
- animation-iteration-count: infinite;
- animation-timing-function: linear;
-}
-
-#UITourHighlight[active="wobble"] {
- animation-name: uitour-wobble;
- animation-delay: 0s;
- animation-duration: 1.5s;
- animation-iteration-count: 1;
-}
-#UITourHighlight[active="zoom"] {
- animation-name: uitour-zoom;
- animation-duration: 1s;
-}
-#UITourHighlight[active="color"] {
- animation-name: uitour-color;
- animation-duration: 2s;
-}
-
/* Combined context-menu items */
#context-navigation > .menuitem-iconic > .menu-iconic-text,
#context-navigation > .menuitem-iconic > .menu-accel-container {
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 4b8ec864b9..64c0d86f52 100755
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -48,7 +48,6 @@ Cu.import("resource://gre/modules/NotificationDB.jsm");
["Task", "resource://gre/modules/Task.jsm"],
["TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm"],
["Translation", "resource:///modules/translation/Translation.jsm"],
- ["UITour", "resource:///modules/UITour.jsm"],
["UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"],
["Weave", "resource://services-sync/main.js"],
["fxAccounts", "resource://gre/modules/FxAccounts.jsm"],
@@ -984,7 +983,6 @@ var gBrowserInit = {
let mm = window.getGroupMessageManager("browsers");
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
mm.loadFrameScript("chrome://browser/content/content.js", true);
- mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
mm.loadFrameScript("chrome://global/content/manifestMessages.js", true);
// initialize observers and listeners
@@ -4474,7 +4472,6 @@ var XULBrowserWindow = {
gIdentityHandler.onLocationChange();
- UITour.onLocationChange(location);
gTabletModePageCounter.inc();
@@ -8085,11 +8082,6 @@ var AboutPrivateBrowsingListener = {
const PREF = "privacy.trackingprotection.pbmode.enabled";
Services.prefs.setBoolPref(PREF, !Services.prefs.getBoolPref(PREF));
});
- window.messageManager.addMessageListener(
- "AboutPrivateBrowsing:DontShowIntroPanelAgain",
- msg => {
- TrackingProtection.dontShowIntroPanelAgain();
- });
}
};
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 4f1b48349c..028df609f7 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -232,42 +232,6 @@
</hbox>
</panel>
- <!-- UI tour experience -->
- <panel id="UITourTooltip"
- type="arrow"
- hidden="true"
- noautofocus="true"
- noautohide="true"
- align="start"
- orient="vertical"
- role="alert">
- <vbox>
- <hbox id="UITourTooltipBody">
- <image id="UITourTooltipIcon"/>
- <vbox flex="1">
- <hbox id="UITourTooltipTitleContainer">
- <label id="UITourTooltipTitle" flex="1"/>
- <toolbarbutton id="UITourTooltipClose" class="close-icon"
- tooltiptext="&uiTour.infoPanel.close;"/>
- </hbox>
- <description id="UITourTooltipDescription" flex="1"/>
- </vbox>
- </hbox>
- <hbox id="UITourTooltipButtons" flex="1" align="center"/>
- </vbox>
- </panel>
- <!-- type="default" forces frames to be created so that the panel's size can be determined -->
- <panel id="UITourHighlightContainer"
- type="default"
- hidden="true"
- noautofocus="true"
- noautohide="true"
- flip="none"
- consumeoutsideclicks="false"
- mousethrough="always">
- <box id="UITourHighlight"></box>
- </panel>
-
<menupopup id="toolbar-context-menu"
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js
index a57dc66074..11a9fabcee 100644
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -226,8 +226,6 @@ var AboutPrivateBrowsingListener = {
false, true);
chromeGlobal.addEventListener("AboutPrivateBrowsingToggleTrackingProtection", this,
false, true);
- chromeGlobal.addEventListener("AboutPrivateBrowsingDontShowIntroPanelAgain", this,
- false, true);
},
get isAboutPrivateBrowsing() {
@@ -245,9 +243,6 @@ var AboutPrivateBrowsingListener = {
case "AboutPrivateBrowsingToggleTrackingProtection":
sendAsyncMessage("AboutPrivateBrowsing:ToggleTrackingProtection");
break;
- case "AboutPrivateBrowsingDontShowIntroPanelAgain":
- sendAsyncMessage("AboutPrivateBrowsing:DontShowIntroPanelAgain");
- break;
}
},
};
diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js
index 4ea6d8f900..38ca82f554 100644
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -809,13 +809,6 @@ function openFeedbackPage()
openUILinkIn(url, "tab");
}
-function openTourPage()
-{
- let scope = {}
- Components.utils.import("resource:///modules/UITour.jsm", scope);
- openUILinkIn(scope.UITour.url, "tab");
-}
-
function buildHelpMenu()
{
// Enable/disable the "Report Web Forgery" menu item.
diff --git a/browser/components/customizableui/CustomizeMode.jsm b/browser/components/customizableui/CustomizeMode.jsm
index 49868cdbd4..e63e25b0aa 100644
--- a/browser/components/customizableui/CustomizeMode.jsm
+++ b/browser/components/customizableui/CustomizeMode.jsm
@@ -90,7 +90,6 @@ function CustomizeMode(aWindow) {
// to the user when in customizing mode.
this.visiblePalette = this.document.getElementById(kPaletteId);
this.paletteEmptyNotice = this.document.getElementById("customization-empty");
- this.tipPanel = this.document.getElementById("customization-tipPanel");
if (Services.prefs.getCharPref("general.skins.selectedSkin") != "classic/1.0") {
let lwthemeButton = this.document.getElementById("customization-lwtheme-button");
lwthemeButton.setAttribute("hidden", "true");
@@ -355,7 +354,6 @@ CustomizeMode.prototype = {
this._updateEmptyPaletteNotice();
this._updateLWThemeButtonIcon();
- this.maybeShowTip(panelHolder);
this._handler.isEnteringCustomizeMode = false;
panelContents.removeAttribute("customize-transitioning");
@@ -400,8 +398,6 @@ CustomizeMode.prototype = {
return;
}
- this.hideTip();
-
this._handler.isExitingCustomizeMode = true;
if (this._enableOutlinesTimeout) {
@@ -675,46 +671,6 @@ CustomizeMode.prototype = {
return "url(\"" + aData.headerURL.replace(/"/g, '\\"') + "\")";
},
- maybeShowTip: function(aAnchor) {
- let shown = false;
- const kShownPref = "browser.customizemode.tip0.shown";
- try {
- shown = Services.prefs.getBoolPref(kShownPref);
- } catch (ex) {}
- if (shown)
- return;
-
- let anchorNode = aAnchor || this.document.getElementById("customization-panelHolder");
- let messageNode = this.tipPanel.querySelector(".customization-tipPanel-contentMessage");
- if (!messageNode.childElementCount) {
- // Put the tip contents in the popup.
- let bundle = this.document.getElementById("bundle_browser");
- const kLabelClass = "customization-tipPanel-link";
- messageNode.innerHTML = bundle.getFormattedString("customizeTips.tip0", [
- "<label class=\"customization-tipPanel-em\" value=\"" +
- bundle.getString("customizeTips.tip0.hint") + "\"/>",
- this.document.getElementById("bundle_brand").getString("brandShortName"),
- "<label class=\"" + kLabelClass + " text-link\" value=\"" +
- bundle.getString("customizeTips.tip0.learnMore") + "\"/>"
- ]);
-
- messageNode.querySelector("." + kLabelClass).addEventListener("click", () => {
- let url = Services.urlFormatter.formatURLPref("browser.customizemode.tip0.learnMoreUrl");
- let browser = this.browser;
- browser.selectedTab = browser.addTab(url);
- this.hideTip();
- });
- }
-
- this.tipPanel.hidden = false;
- this.tipPanel.openPopup(anchorNode);
- Services.prefs.setBoolPref(kShownPref, true);
- },
-
- hideTip: function() {
- this.tipPanel.hidePopup();
- },
-
_getCustomizableChildForNode: function(aNode) {
// NB: adjusted from _getCustomizableParent to keep that method fast
// (it's used during drags), and avoid multiple DOM loops
diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul
index 077d9c0149..e389b14bfb 100644
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -367,25 +367,6 @@
</vbox>
</panel>
-<panel id="customization-tipPanel"
- type="arrow"
- flip="none"
- side="left"
- position="leftcenter topright"
- noautohide="true"
- hidden="true">
- <hbox class="customization-tipPanel-wrapper">
- <vbox class="customization-tipPanel-infoBox"/>
- <vbox class="customization-tipPanel-content" flex="1">
- <description class="customization-tipPanel-contentMessage"/>
- <image class="customization-tipPanel-contentImage"/>
- </vbox>
- <vbox pack="start" align="end" class="customization-tipPanel-closeBox">
- <toolbarbutton oncommand="gCustomizeMode.hideTip()" class="close-icon"/>
- </vbox>
- </hbox>
-</panel>
-
<panel id="panic-button-success-notification"
type="arrow"
position="bottomcenter topright"
diff --git a/browser/components/moz.build b/browser/components/moz.build
index a495802009..07e79bc363 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -21,7 +21,6 @@ DIRS += [
'shell',
'selfsupport',
'syncedtabs',
- 'uitour',
'translation',
]
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js
index 448bb910dc..ae00e30cfb 100644
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -56,13 +56,11 @@ XPCOMUtils.defineLazyServiceGetter(this, "AlertsService", "@mozilla.org/alerts-s
["ReaderParent", "resource:///modules/ReaderParent.jsm"],
["RecentWindow", "resource:///modules/RecentWindow.jsm"],
["RemotePrompt", "resource:///modules/RemotePrompt.jsm"],
- ["SelfSupportBackend", "resource:///modules/SelfSupportBackend.jsm"],
["SessionStore", "resource:///modules/sessionstore/SessionStore.jsm"],
["ShellService", "resource:///modules/ShellService.jsm"],
["SimpleServiceDiscovery", "resource://gre/modules/SimpleServiceDiscovery.jsm"],
["TabCrashHandler", "resource:///modules/ContentCrashHandlers.jsm"],
["Task", "resource://gre/modules/Task.jsm"],
- ["UITour", "resource:///modules/UITour.jsm"],
["URLBarZoom", "resource:///modules/URLBarZoom.jsm"],
["UserAgentOverrides", "resource://gre/modules/UserAgentOverrides.jsm"],
["WebChannel", "resource://gre/modules/WebChannel.jsm"],
@@ -682,8 +680,6 @@ BrowserGlue.prototype = {
ReaderParent.init();
URLBarZoom.init();
- SelfSupportBackend.init();
-
// Ensure we keep track of places/pw-mananager undo by init'ing this early.
Cu.import("resource:///modules/AutoMigrate.jsm");
@@ -1031,7 +1027,6 @@ BrowserGlue.prototype = {
}
BrowserUsageTelemetry.uninit();
- SelfSupportBackend.uninit();
UserAgentOverrides.uninit();
PageThumbs.uninit();
NewTabMessages.uninit();
@@ -2847,12 +2842,3 @@ var E10SAccessibilityCheck = {
var components = [BrowserGlue, ContentPermissionPrompt];
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
-
-
-// Listen for UITour messages.
-// Do it here instead of the UITour module itself so that the UITour module is lazy loaded
-// when the first message is received.
-var globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
-globalMM.addMessageListener("UITour:onPageEvent", function(aMessage) {
- UITour.onPageEvent(aMessage, aMessage.data);
-});
diff --git a/browser/components/preferences/blocklists.js b/browser/components/preferences/blocklists.js
index c0ce5b6568..bc39eb6bd9 100644
--- a/browser/components/preferences/blocklists.js
+++ b/browser/components/preferences/blocklists.js
@@ -6,11 +6,9 @@ Components.utils.import("resource://gre/modules/Services.jsm");
const BASE_LIST_ID = "base";
const CONTENT_LIST_ID = "content";
const TRACK_SUFFIX = "-track-digest256";
-#ifdef MOZ_SAFE_BROWSING
const TRACKING_TABLE_PREF = "urlclassifier.trackingTable";
const LISTS_PREF_BRANCH = "browser.safebrowsing.provider.mozilla.lists.";
const UPDATE_TIME_PREF = "browser.safebrowsing.provider.mozilla.nextupdatetime";
-#endif
var gBlocklistManager = {
_type: "",
diff --git a/browser/components/preferences/jar.mn b/browser/components/preferences/jar.mn
index f83809b038..c0d34da7f4 100644
--- a/browser/components/preferences/jar.mn
+++ b/browser/components/preferences/jar.mn
@@ -6,7 +6,7 @@ browser.jar:
content/browser/preferences/applicationManager.xul
content/browser/preferences/applicationManager.js
content/browser/preferences/blocklists.xul
-* content/browser/preferences/blocklists.js
+ content/browser/preferences/blocklists.js
* content/browser/preferences/colors.xul
* content/browser/preferences/cookies.xul
content/browser/preferences/cookies.js
diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
index 31ce963470..4434f7b6ac 100644
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
@@ -63,13 +63,9 @@ document.addEventListener("DOMContentLoaded", function () {
document.getElementById("favicon")
.setAttribute("href", FAVICON_PRIVACY);
tpToggle.addEventListener("change", toggleTrackingProtection);
- document.getElementById("startTour")
- .addEventListener("click", dontShowIntroPanelAgain);
let formatURLPref = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
.getService(Ci.nsIURLFormatter).formatURLPref;
- document.getElementById("startTour").setAttribute("href",
- formatURLPref("privacy.trackingprotection.introURL"));
document.getElementById("learnMore").setAttribute("href",
formatURLPref("app.support.baseURL") + "private-browsing");
@@ -89,10 +85,3 @@ function toggleTrackingProtection() {
new CustomEvent("AboutPrivateBrowsingToggleTrackingProtection",
{bubbles: true}));
}
-
-function dontShowIntroPanelAgain() {
- // Ask chrome to disable the doorhanger
- document.dispatchEvent(
- new CustomEvent("AboutPrivateBrowsingDontShowIntroPanelAgain",
- {bubbles: true}));
-}
diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
index fb5c4ac8eb..36058efa56 100644
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
@@ -69,9 +69,6 @@
<section class="section-main">
<p>&trackingProtection.description2;</p>
- <p>
- <a id="startTour" class="button">&trackingProtection.startTour1;</a>
- </p>
</section>
<section class="section-main">
diff --git a/browser/components/uitour/UITour-lib.js b/browser/components/uitour/UITour-lib.js
deleted file mode 100644
index 7fe8201857..0000000000
--- a/browser/components/uitour/UITour-lib.js
+++ /dev/null
@@ -1,331 +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/. */
-
-// create namespace
-if (typeof Mozilla == 'undefined') {
- var Mozilla = {};
-}
-
-(function($) {
- 'use strict';
-
- // create namespace
- if (typeof Mozilla.UITour == 'undefined') {
- Mozilla.UITour = {};
- }
-
- var themeIntervalId = null;
- function _stopCyclingThemes() {
- if (themeIntervalId) {
- clearInterval(themeIntervalId);
- themeIntervalId = null;
- }
- }
-
- function _sendEvent(action, data) {
- var event = new CustomEvent('mozUITour', {
- bubbles: true,
- detail: {
- action: action,
- data: data || {}
- }
- });
-
- document.dispatchEvent(event);
- }
-
- function _generateCallbackID() {
- return Math.random().toString(36).replace(/[^a-z]+/g, '');
- }
-
- function _waitForCallback(callback) {
- var id = _generateCallbackID();
-
- function listener(event) {
- if (typeof event.detail != 'object')
- return;
- if (event.detail.callbackID != id)
- return;
-
- document.removeEventListener('mozUITourResponse', listener);
- callback(event.detail.data);
- }
- document.addEventListener('mozUITourResponse', listener);
-
- return id;
- }
-
- var notificationListener = null;
- function _notificationListener(event) {
- if (typeof event.detail != 'object')
- return;
- if (typeof notificationListener != 'function')
- return;
-
- notificationListener(event.detail.event, event.detail.params);
- }
-
- Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY = 10 * 1000;
-
- Mozilla.UITour.CONFIGNAME_SYNC = 'sync';
- Mozilla.UITour.CONFIGNAME_AVAILABLETARGETS = 'availableTargets';
-
- Mozilla.UITour.ping = function(callback) {
- var data = {};
- if (callback) {
- data.callbackID = _waitForCallback(callback);
- }
- _sendEvent('ping', data);
- };
-
- Mozilla.UITour.observe = function(listener, callback) {
- notificationListener = listener;
-
- if (listener) {
- document.addEventListener('mozUITourNotification',
- _notificationListener);
- Mozilla.UITour.ping(callback);
- } else {
- document.removeEventListener('mozUITourNotification',
- _notificationListener);
- }
- };
-
- Mozilla.UITour.registerPageID = function(pageID) {
- _sendEvent('registerPageID', {
- pageID: pageID
- });
- };
-
- Mozilla.UITour.showHeartbeat = function(message, thankyouMessage, flowId, engagementURL,
- learnMoreLabel, learnMoreURL, options) {
- var args = {
- message: message,
- thankyouMessage: thankyouMessage,
- flowId: flowId,
- engagementURL: engagementURL,
- learnMoreLabel: learnMoreLabel,
- learnMoreURL: learnMoreURL,
- };
-
- if (options) {
- for (var option in options) {
- if (!options.hasOwnProperty(option)) {
- continue;
- }
- args[option] = options[option];
- }
- }
-
- _sendEvent('showHeartbeat', args);
- };
-
- Mozilla.UITour.showHighlight = function(target, effect) {
- _sendEvent('showHighlight', {
- target: target,
- effect: effect
- });
- };
-
- Mozilla.UITour.hideHighlight = function() {
- _sendEvent('hideHighlight');
- };
-
- Mozilla.UITour.showInfo = function(target, title, text, icon, buttons, options) {
- var buttonData = [];
- if (Array.isArray(buttons)) {
- for (var i = 0; i < buttons.length; i++) {
- buttonData.push({
- label: buttons[i].label,
- icon: buttons[i].icon,
- style: buttons[i].style,
- callbackID: _waitForCallback(buttons[i].callback)
- });
- }
- }
-
- var closeButtonCallbackID, targetCallbackID;
- if (options && options.closeButtonCallback)
- closeButtonCallbackID = _waitForCallback(options.closeButtonCallback);
- if (options && options.targetCallback)
- targetCallbackID = _waitForCallback(options.targetCallback);
-
- _sendEvent('showInfo', {
- target: target,
- title: title,
- text: text,
- icon: icon,
- buttons: buttonData,
- closeButtonCallbackID: closeButtonCallbackID,
- targetCallbackID: targetCallbackID
- });
- };
-
- Mozilla.UITour.hideInfo = function() {
- _sendEvent('hideInfo');
- };
-
- Mozilla.UITour.previewTheme = function(theme) {
- _stopCyclingThemes();
-
- _sendEvent('previewTheme', {
- theme: JSON.stringify(theme)
- });
- };
-
- Mozilla.UITour.resetTheme = function() {
- _stopCyclingThemes();
-
- _sendEvent('resetTheme');
- };
-
- Mozilla.UITour.cycleThemes = function(themes, delay, callback) {
- _stopCyclingThemes();
-
- if (!delay) {
- delay = Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY;
- }
-
- function nextTheme() {
- var theme = themes.shift();
- themes.push(theme);
-
- _sendEvent('previewTheme', {
- theme: JSON.stringify(theme),
- state: true
- });
-
- callback(theme);
- }
-
- themeIntervalId = setInterval(nextTheme, delay);
- nextTheme();
- };
-
- Mozilla.UITour.showMenu = function(name, callback) {
- var showCallbackID;
- if (callback)
- showCallbackID = _waitForCallback(callback);
-
- _sendEvent('showMenu', {
- name: name,
- showCallbackID: showCallbackID,
- });
- };
-
- Mozilla.UITour.hideMenu = function(name) {
- _sendEvent('hideMenu', {
- name: name
- });
- };
-
- Mozilla.UITour.showNewTab = function() {
- _sendEvent('showNewTab');
- };
-
- Mozilla.UITour.getConfiguration = function(configName, callback) {
- _sendEvent('getConfiguration', {
- callbackID: _waitForCallback(callback),
- configuration: configName,
- });
- };
-
- Mozilla.UITour.setConfiguration = function(configName, configValue) {
- _sendEvent('setConfiguration', {
- configuration: configName,
- value: configValue,
- });
- };
-
- /**
- * Request the browser open the Firefox Accounts page.
- *
- * @param {Object} extraURLCampaignParams - An object containing additional
- * paramaters for the URL opened by the browser for reasons of promotional
- * campaign tracking. Each attribute of the object must have a name that
- * is a string, begins with "utm_" and contains only only alphanumeric
- * characters, dashes or underscores. The values may be any string and will
- * automatically be encoded.
- */
- Mozilla.UITour.showFirefoxAccounts = function(extraURLCampaignParams) {
- _sendEvent('showFirefoxAccounts', {
- extraURLCampaignParams: JSON.stringify(extraURLCampaignParams),
- });
- };
-
- Mozilla.UITour.resetFirefox = function() {
- _sendEvent('resetFirefox');
- };
-
- Mozilla.UITour.addNavBarWidget= function(name, callback) {
- _sendEvent('addNavBarWidget', {
- name: name,
- callbackID: _waitForCallback(callback),
- });
- };
-
- Mozilla.UITour.setDefaultSearchEngine = function(identifier) {
- _sendEvent('setDefaultSearchEngine', {
- identifier: identifier,
- });
- };
-
- Mozilla.UITour.setTreatmentTag = function(name, value) {
- _sendEvent('setTreatmentTag', {
- name: name,
- value: value
- });
- };
-
- Mozilla.UITour.getTreatmentTag = function(name, callback) {
- _sendEvent('getTreatmentTag', {
- name: name,
- callbackID: _waitForCallback(callback)
- });
- };
-
- Mozilla.UITour.setSearchTerm = function(term) {
- _sendEvent('setSearchTerm', {
- term: term
- });
- };
-
- Mozilla.UITour.openSearchPanel = function(callback) {
- _sendEvent('openSearchPanel', {
- callbackID: _waitForCallback(callback)
- });
- };
-
- Mozilla.UITour.forceShowReaderIcon = function() {
- _sendEvent('forceShowReaderIcon');
- };
-
- Mozilla.UITour.toggleReaderMode = function() {
- _sendEvent('toggleReaderMode');
- };
-
- Mozilla.UITour.openPreferences = function(pane) {
- _sendEvent('openPreferences', {
- pane: pane
- });
- };
-
- /**
- * Closes the tab where this code is running. As usual, if the tab is in the
- * foreground, the tab that was displayed before is selected.
- *
- * The last tab in the current window will never be closed, in which case
- * this call will have no effect. The calling code is expected to take an
- * action after a small timeout in order to handle this case, for example by
- * displaying a goodbye message or a button to restart the tour.
- */
- Mozilla.UITour.closeTab = function() {
- _sendEvent('closeTab');
- };
-})();
-
-// Make this library Require-able.
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = Mozilla.UITour;
-}
diff --git a/browser/components/uitour/UITour.jsm b/browser/components/uitour/UITour.jsm
deleted file mode 100644
index b927159630..0000000000
--- a/browser/components/uitour/UITour.jsm
+++ /dev/null
@@ -1,2111 +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/.
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["UITour"];
-
-const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource:///modules/RecentWindow.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/TelemetryController.jsm");
-Cu.import("resource://gre/modules/Timer.jsm");
-
-Cu.importGlobalProperties(["URL"]);
-
-XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
- "resource://gre/modules/LightweightThemeManager.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ResetProfile",
- "resource://gre/modules/ResetProfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
- "resource:///modules/CustomizableUI.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
- "resource://gre/modules/UITelemetry.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
- "resource:///modules/BrowserUITelemetry.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
- "resource://gre/modules/PrivateBrowsingUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
- "resource://gre/modules/ReaderMode.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent",
- "resource:///modules/ReaderParent.jsm");
-
-// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
-const PREF_LOG_LEVEL = "browser.uitour.loglevel";
-const PREF_SEENPAGEIDS = "browser.uitour.seenPageIDs";
-const PREF_READERVIEW_TRIGGER = "browser.uitour.readerViewTrigger";
-const PREF_SURVEY_DURATION = "browser.uitour.surveyDuration";
-
-const BACKGROUND_PAGE_ACTIONS_ALLOWED = new Set([
- "forceShowReaderIcon",
- "getConfiguration",
- "getTreatmentTag",
- "hideHighlight",
- "hideInfo",
- "hideMenu",
- "ping",
- "registerPageID",
- "setConfiguration",
- "setTreatmentTag",
-]);
-const MAX_BUTTONS = 4;
-
-const BUCKET_NAME = "UITour";
-const BUCKET_TIMESTEPS = [
- 1 * 60 * 1000, // Until 1 minute after tab is closed/inactive.
- 3 * 60 * 1000, // Until 3 minutes after tab is closed/inactive.
- 10 * 60 * 1000, // Until 10 minutes after tab is closed/inactive.
- 60 * 60 * 1000, // Until 1 hour after tab is closed/inactive.
-];
-
-// Time after which seen Page IDs expire.
-const SEENPAGEID_EXPIRY = 8 * 7 * 24 * 60 * 60 * 1000; // 8 weeks.
-
-// Prefix for any target matching a search engine.
-const TARGET_SEARCHENGINE_PREFIX = "searchEngine-";
-
-// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
-XPCOMUtils.defineLazyGetter(this, "log", () => {
- let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
- let consoleOptions = {
- maxLogLevelPref: PREF_LOG_LEVEL,
- prefix: "UITour",
- };
- return new ConsoleAPI(consoleOptions);
-});
-
-this.UITour = {
- url: null,
- seenPageIDs: null,
- // This map is not persisted and is used for
- // building the content source of a potential tour.
- pageIDsForSession: new Map(),
- pageIDSourceBrowsers: new WeakMap(),
- /* Map from browser chrome windows to a Set of <browser>s in which a tour is open (both visible and hidden) */
- tourBrowsersByWindow: new WeakMap(),
- appMenuOpenForAnnotation: new Set(),
- availableTargetsCache: new WeakMap(),
- clearAvailableTargetsCache() {
- this.availableTargetsCache = new WeakMap();
- },
-
- _annotationPanelMutationObservers: new WeakMap(),
-
- highlightEffects: ["random", "wobble", "zoom", "color"],
- targets: new Map([
- ["accountStatus", {
- query: (aDocument) => {
- // If the user is logged in, use the avatar element.
- let fxAFooter = aDocument.getElementById("PanelUI-footer-fxa");
- if (fxAFooter.getAttribute("fxastatus")) {
- return aDocument.getElementById("PanelUI-fxa-avatar");
- }
-
- // Otherwise use the sync setup icon.
- let statusButton = aDocument.getElementById("PanelUI-fxa-label");
- return aDocument.getAnonymousElementByAttribute(statusButton,
- "class",
- "toolbarbutton-icon");
- },
- // This is a fake widgetName starting with the "PanelUI-" prefix so we know
- // to automatically open the appMenu when annotating this target.
- widgetName: "PanelUI-fxa-label",
- }],
- ["addons", {query: "#add-ons-button"}],
- ["appMenu", {
- addTargetListener: (aDocument, aCallback) => {
- let panelPopup = aDocument.getElementById("PanelUI-popup");
- panelPopup.addEventListener("popupshown", aCallback);
- },
- query: "#PanelUI-button",
- removeTargetListener: (aDocument, aCallback) => {
- let panelPopup = aDocument.getElementById("PanelUI-popup");
- panelPopup.removeEventListener("popupshown", aCallback);
- },
- }],
- ["backForward", {
- query: "#back-button",
- widgetName: "urlbar-container",
- }],
- ["bookmarks", {query: "#bookmarks-menu-button"}],
- ["controlCenter-trackingUnblock", controlCenterTrackingToggleTarget(true)],
- ["controlCenter-trackingBlock", controlCenterTrackingToggleTarget(false)],
- ["customize", {
- query: (aDocument) => {
- let customizeButton = aDocument.getElementById("PanelUI-customize");
- return aDocument.getAnonymousElementByAttribute(customizeButton,
- "class",
- "toolbarbutton-icon");
- },
- widgetName: "PanelUI-customize",
- }],
- ["devtools", {query: "#developer-button"}],
- ["help", {query: "#PanelUI-help"}],
- ["home", {query: "#home-button"}],
- ["forget", {
- allowAdd: true,
- query: "#panic-button",
- widgetName: "panic-button",
- }],
- ["pocket", {
- allowAdd: true,
- query: "#pocket-button",
- widgetName: "pocket-button",
- }],
- ["privateWindow", {query: "#privatebrowsing-button"}],
- ["quit", {query: "#PanelUI-quit"}],
- ["readerMode-urlBar", {query: "#reader-mode-button"}],
- ["search", {
- infoPanelOffsetX: 18,
- infoPanelPosition: "after_start",
- query: "#searchbar",
- widgetName: "search-container",
- }],
- ["searchIcon", {
- query: (aDocument) => {
- let searchbar = aDocument.getElementById("searchbar");
- return aDocument.getAnonymousElementByAttribute(searchbar,
- "anonid",
- "searchbar-search-button");
- },
- widgetName: "search-container",
- }],
- ["searchPrefsLink", {
- query: (aDocument) => {
- let element = null;
- let popup = aDocument.getElementById("PopupSearchAutoComplete");
- if (popup.state != "open")
- return null;
- element = aDocument.getAnonymousElementByAttribute(popup,
- "anonid",
- "search-settings");
- if (!element || !UITour.isElementVisible(element)) {
- return null;
- }
- return element;
- },
- }],
- ["selectedTabIcon", {
- query: (aDocument) => {
- let selectedtab = aDocument.defaultView.gBrowser.selectedTab;
- let element = aDocument.getAnonymousElementByAttribute(selectedtab,
- "anonid",
- "tab-icon-image");
- if (!element || !UITour.isElementVisible(element)) {
- return null;
- }
- return element;
- },
- }],
- ["trackingProtection", {
- query: "#tracking-protection-icon",
- }],
- ["urlbar", {
- query: "#urlbar",
- widgetName: "urlbar-container",
- }],
- ["webide", {query: "#webide-button"}],
- ]),
-
- init: function() {
- log.debug("Initializing UITour");
- // Lazy getter is initialized here so it can be replicated any time
- // in a test.
- delete this.seenPageIDs;
- Object.defineProperty(this, "seenPageIDs", {
- get: this.restoreSeenPageIDs.bind(this),
- configurable: true,
- });
-
- delete this.url;
- XPCOMUtils.defineLazyGetter(this, "url", function () {
- return Services.urlFormatter.formatURLPref("browser.uitour.url");
- });
-
- // Clear the availableTargetsCache on widget changes.
- let listenerMethods = [
- "onWidgetAdded",
- "onWidgetMoved",
- "onWidgetRemoved",
- "onWidgetReset",
- "onAreaReset",
- ];
- CustomizableUI.addListener(listenerMethods.reduce((listener, method) => {
- listener[method] = () => this.clearAvailableTargetsCache();
- return listener;
- }, {}));
- },
-
- restoreSeenPageIDs: function() {
- delete this.seenPageIDs;
-
- if (UITelemetry.enabled) {
- let dateThreshold = Date.now() - SEENPAGEID_EXPIRY;
-
- try {
- let data = Services.prefs.getCharPref(PREF_SEENPAGEIDS);
- data = new Map(JSON.parse(data));
-
- for (let [pageID, details] of data) {
-
- if (typeof pageID != "string" ||
- typeof details != "object" ||
- typeof details.lastSeen != "number" ||
- details.lastSeen < dateThreshold) {
-
- data.delete(pageID);
- }
- }
-
- this.seenPageIDs = data;
- } catch (e) {}
- }
-
- if (!this.seenPageIDs)
- this.seenPageIDs = new Map();
-
- this.persistSeenIDs();
-
- return this.seenPageIDs;
- },
-
- addSeenPageID: function(aPageID) {
- if (!UITelemetry.enabled)
- return;
-
- this.seenPageIDs.set(aPageID, {
- lastSeen: Date.now(),
- });
-
- this.persistSeenIDs();
- },
-
- persistSeenIDs: function() {
- if (this.seenPageIDs.size === 0) {
- Services.prefs.clearUserPref(PREF_SEENPAGEIDS);
- return;
- }
-
- Services.prefs.setCharPref(PREF_SEENPAGEIDS,
- JSON.stringify([...this.seenPageIDs]));
- },
-
- get _readerViewTriggerRegEx() {
- delete this._readerViewTriggerRegEx;
- let readerViewUITourTrigger = Services.prefs.getCharPref(PREF_READERVIEW_TRIGGER);
- return this._readerViewTriggerRegEx = new RegExp(readerViewUITourTrigger, "i");
- },
-
- onLocationChange: function(aLocation) {
- // The ReaderView tour page is expected to run in Reader View,
- // which disables JavaScript on the page. To get around that, we
- // automatically start a pre-defined tour on page load (for hysterical
- // raisins the ReaderView tour is known as "readinglist")
- let originalUrl = ReaderMode.getOriginalUrl(aLocation);
- if (this._readerViewTriggerRegEx.test(originalUrl)) {
- this.startSubTour("readinglist");
- }
- },
-
- onPageEvent: function(aMessage, aEvent) {
- let browser = aMessage.target;
- let window = browser.ownerGlobal;
-
- // Does the window have tabs? We need to make sure since windowless browsers do
- // not have tabs.
- if (!window.gBrowser) {
- // When using windowless browsers we don't have a valid |window|. If that's the case,
- // use the most recent window as a target for UITour functions (see Bug 1111022).
- window = Services.wm.getMostRecentWindow("navigator:browser");
- }
-
- let messageManager = browser.messageManager;
-
- log.debug("onPageEvent:", aEvent.detail, aMessage);
-
- if (typeof aEvent.detail != "object") {
- log.warn("Malformed event - detail not an object");
- return false;
- }
-
- let action = aEvent.detail.action;
- if (typeof action != "string" || !action) {
- log.warn("Action not defined");
- return false;
- }
-
- let data = aEvent.detail.data;
- if (typeof data != "object") {
- log.warn("Malformed event - data not an object");
- return false;
- }
-
- if ((aEvent.pageVisibilityState == "hidden" ||
- aEvent.pageVisibilityState == "unloaded") &&
- !BACKGROUND_PAGE_ACTIONS_ALLOWED.has(action)) {
- log.warn("Ignoring disallowed action from a hidden page:", action);
- return false;
- }
-
- switch (action) {
- case "registerPageID": {
- if (typeof data.pageID != "string") {
- log.warn("registerPageID: pageID must be a string");
- break;
- }
-
- this.pageIDsForSession.set(data.pageID, {lastSeen: Date.now()});
-
- // The rest is only relevant if Telemetry is enabled.
- if (!UITelemetry.enabled) {
- log.debug("registerPageID: Telemetry disabled, not doing anything");
- break;
- }
-
- // We don't want to allow BrowserUITelemetry.BUCKET_SEPARATOR in the
- // pageID, as it could make parsing the telemetry bucket name difficult.
- if (data.pageID.includes(BrowserUITelemetry.BUCKET_SEPARATOR)) {
- log.warn("registerPageID: Invalid page ID specified");
- break;
- }
-
- this.addSeenPageID(data.pageID);
- this.pageIDSourceBrowsers.set(browser, data.pageID);
- this.setTelemetryBucket(data.pageID);
-
- break;
- }
-
- case "showHeartbeat": {
- // Validate the input parameters.
- if (typeof data.message !== "string" || data.message === "") {
- log.error("showHeartbeat: Invalid message specified.");
- return false;
- }
-
- if (typeof data.thankyouMessage !== "string" || data.thankyouMessage === "") {
- log.error("showHeartbeat: Invalid thank you message specified.");
- return false;
- }
-
- if (typeof data.flowId !== "string" || data.flowId === "") {
- log.error("showHeartbeat: Invalid flowId specified.");
- return false;
- }
-
- if (data.engagementButtonLabel && typeof data.engagementButtonLabel != "string") {
- log.error("showHeartbeat: Invalid engagementButtonLabel specified");
- return false;
- }
-
- let heartbeatWindow = window;
- if (data.privateWindowsOnly && !PrivateBrowsingUtils.isWindowPrivate(heartbeatWindow)) {
- heartbeatWindow = RecentWindow.getMostRecentBrowserWindow({ private: true });
- if (!heartbeatWindow) {
- log.debug("showHeartbeat: No private window found");
- return false;
- }
- }
-
- // Finally show the Heartbeat UI.
- this.showHeartbeat(heartbeatWindow, data);
- break;
- }
-
- case "showHighlight": {
- let targetPromise = this.getTarget(window, data.target);
- targetPromise.then(target => {
- if (!target.node) {
- log.error("UITour: Target could not be resolved: " + data.target);
- return;
- }
- let effect = undefined;
- if (this.highlightEffects.indexOf(data.effect) !== -1) {
- effect = data.effect;
- }
- this.showHighlight(window, target, effect);
- }).catch(log.error);
- break;
- }
-
- case "hideHighlight": {
- this.hideHighlight(window);
- break;
- }
-
- case "showInfo": {
- let targetPromise = this.getTarget(window, data.target, true);
- targetPromise.then(target => {
- if (!target.node) {
- log.error("UITour: Target could not be resolved: " + data.target);
- return;
- }
-
- let iconURL = null;
- if (typeof data.icon == "string")
- iconURL = this.resolveURL(browser, data.icon);
-
- let buttons = [];
- if (Array.isArray(data.buttons) && data.buttons.length > 0) {
- for (let buttonData of data.buttons) {
- if (typeof buttonData == "object" &&
- typeof buttonData.label == "string" &&
- typeof buttonData.callbackID == "string") {
- let callback = buttonData.callbackID;
- let button = {
- label: buttonData.label,
- callback: event => {
- this.sendPageCallback(messageManager, callback);
- },
- };
-
- if (typeof buttonData.icon == "string")
- button.iconURL = this.resolveURL(browser, buttonData.icon);
-
- if (typeof buttonData.style == "string")
- button.style = buttonData.style;
-
- buttons.push(button);
-
- if (buttons.length == MAX_BUTTONS) {
- log.warn("showInfo: Reached limit of allowed number of buttons");
- break;
- }
- }
- }
- }
-
- let infoOptions = {};
- if (typeof data.closeButtonCallbackID == "string") {
- infoOptions.closeButtonCallback = () => {
- this.sendPageCallback(messageManager, data.closeButtonCallbackID);
- };
- }
- if (typeof data.targetCallbackID == "string") {
- infoOptions.targetCallback = details => {
- this.sendPageCallback(messageManager, data.targetCallbackID, details);
- };
- }
-
- this.showInfo(window, target, data.title, data.text, iconURL, buttons, infoOptions);
- }).catch(log.error);
- break;
- }
-
- case "hideInfo": {
- this.hideInfo(window);
- break;
- }
-
- case "previewTheme": {
- this.previewTheme(data.theme);
- break;
- }
-
- case "resetTheme": {
- this.resetTheme();
- break;
- }
-
- case "showMenu": {
- this.showMenu(window, data.name, () => {
- if (typeof data.showCallbackID == "string")
- this.sendPageCallback(messageManager, data.showCallbackID);
- });
- break;
- }
-
- case "hideMenu": {
- this.hideMenu(window, data.name);
- break;
- }
-
- case "showNewTab": {
- this.showNewTab(window, browser);
- break;
- }
-
- case "getConfiguration": {
- if (typeof data.configuration != "string") {
- log.warn("getConfiguration: No configuration option specified");
- return false;
- }
-
- this.getConfiguration(messageManager, window, data.configuration, data.callbackID);
- break;
- }
-
- case "setConfiguration": {
- if (typeof data.configuration != "string") {
- log.warn("setConfiguration: No configuration option specified");
- return false;
- }
-
- this.setConfiguration(window, data.configuration, data.value);
- break;
- }
-
- case "openPreferences": {
- if (typeof data.pane != "string" && typeof data.pane != "undefined") {
- log.warn("openPreferences: Invalid pane specified");
- return false;
- }
-
- window.openPreferences(data.pane);
- break;
- }
-
- case "showFirefoxAccounts": {
- // 'signup' is the only action that makes sense currently, so we don't
- // accept arbitrary actions just to be safe...
- let p = new URLSearchParams("action=signup&entrypoint=uitour");
- // Call our helper to validate extraURLCampaignParams and populate URLSearchParams
- if (!this._populateCampaignParams(p, data.extraURLCampaignParams)) {
- log.warn("showFirefoxAccounts: invalid campaign args specified");
- return false;
- }
-
- // We want to replace the current tab.
- browser.loadURI("about:accounts?" + p.toString());
- break;
- }
-
- case "resetFirefox": {
- // Open a reset profile dialog window.
- if (ResetProfile.resetSupported()) {
- ResetProfile.openConfirmationDialog(window);
- }
- break;
- }
-
- case "addNavBarWidget": {
- // Add a widget to the toolbar
- let targetPromise = this.getTarget(window, data.name);
- targetPromise.then(target => {
- this.addNavBarWidget(target, messageManager, data.callbackID);
- }).catch(log.error);
- break;
- }
-
- case "setDefaultSearchEngine": {
- let enginePromise = this.selectSearchEngine(data.identifier);
- enginePromise.catch(Cu.reportError);
- break;
- }
-
- case "setTreatmentTag": {
- let name = data.name;
- let value = data.value;
- let string = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
- string.data = value;
- Services.prefs.setComplexValue("browser.uitour.treatment." + name,
- Ci.nsISupportsString, string);
- // The notification is only meant to be used in tests.
- UITourHealthReport.recordTreatmentTag(name, value)
- .then(() => this.notify("TreatmentTag:TelemetrySent"));
- break;
- }
-
- case "getTreatmentTag": {
- let name = data.name;
- let value;
- try {
- value = Services.prefs.getComplexValue("browser.uitour.treatment." + name,
- Ci.nsISupportsString).data;
- } catch (ex) {}
- this.sendPageCallback(messageManager, data.callbackID, { value: value });
- break;
- }
-
- case "setSearchTerm": {
- let targetPromise = this.getTarget(window, "search");
- targetPromise.then(target => {
- let searchbar = target.node;
- searchbar.value = data.term;
- searchbar.updateGoButtonVisibility();
- });
- break;
- }
-
- case "openSearchPanel": {
- let targetPromise = this.getTarget(window, "search");
- targetPromise.then(target => {
- let searchbar = target.node;
-
- if (searchbar.textbox.open) {
- this.sendPageCallback(messageManager, data.callbackID);
- } else {
- let onPopupShown = () => {
- searchbar.textbox.popup.removeEventListener("popupshown", onPopupShown);
- this.sendPageCallback(messageManager, data.callbackID);
- };
-
- searchbar.textbox.popup.addEventListener("popupshown", onPopupShown);
- searchbar.openSuggestionsPanel();
- }
- }).then(null, Cu.reportError);
- break;
- }
-
- case "ping": {
- if (typeof data.callbackID == "string")
- this.sendPageCallback(messageManager, data.callbackID);
- break;
- }
-
- case "forceShowReaderIcon": {
- ReaderParent.forceShowReaderIcon(browser);
- break;
- }
-
- case "toggleReaderMode": {
- let targetPromise = this.getTarget(window, "readerMode-urlBar");
- targetPromise.then(target => {
- ReaderParent.toggleReaderMode({target: target.node});
- });
- break;
- }
-
- case "closeTab": {
- // Find the <tabbrowser> element of the <browser> for which the event
- // was generated originally. If the browser where the UI tour is loaded
- // is windowless, just ignore the request to close the tab. The request
- // is also ignored if this is the only tab in the window.
- let tabBrowser = browser.ownerGlobal.gBrowser;
- if (tabBrowser && tabBrowser.browsers.length > 1) {
- tabBrowser.removeTab(tabBrowser.getTabForBrowser(browser));
- }
- break;
- }
- }
-
- this.initForBrowser(browser, window);
-
- return true;
- },
-
- initForBrowser(aBrowser, window) {
- let gBrowser = window.gBrowser;
-
- if (gBrowser) {
- gBrowser.tabContainer.addEventListener("TabSelect", this);
- }
-
- if (!this.tourBrowsersByWindow.has(window)) {
- this.tourBrowsersByWindow.set(window, new Set());
- }
- this.tourBrowsersByWindow.get(window).add(aBrowser);
-
- Services.obs.addObserver(this, "message-manager-close", false);
-
- window.addEventListener("SSWindowClosing", this);
- },
-
- handleEvent: function(aEvent) {
- log.debug("handleEvent: type =", aEvent.type, "event =", aEvent);
- switch (aEvent.type) {
- case "TabSelect": {
- let window = aEvent.target.ownerGlobal;
-
- // Teardown the browser of the tab we just switched away from.
- if (aEvent.detail && aEvent.detail.previousTab) {
- let previousTab = aEvent.detail.previousTab;
- let openTourWindows = this.tourBrowsersByWindow.get(window);
- if (openTourWindows.has(previousTab.linkedBrowser)) {
- this.teardownTourForBrowser(window, previousTab.linkedBrowser, false);
- }
- }
-
- break;
- }
-
- case "SSWindowClosing": {
- let window = aEvent.target;
- this.teardownTourForWindow(window);
- break;
- }
- }
- },
-
- observe: function(aSubject, aTopic, aData) {
- log.debug("observe: aTopic =", aTopic);
- switch (aTopic) {
- // The browser message manager is disconnected when the <browser> is
- // destroyed and we want to teardown at that point.
- case "message-manager-close": {
- let winEnum = Services.wm.getEnumerator("navigator:browser");
- while (winEnum.hasMoreElements()) {
- let window = winEnum.getNext();
- if (window.closed)
- continue;
-
- let tourBrowsers = this.tourBrowsersByWindow.get(window);
- if (!tourBrowsers)
- continue;
-
- for (let browser of tourBrowsers) {
- let messageManager = browser.messageManager;
- if (aSubject != messageManager) {
- continue;
- }
-
- this.teardownTourForBrowser(window, browser, true);
- return;
- }
- }
- break;
- }
- }
- },
-
- // Given a string that is a JSONified represenation of an object with
- // additional utm_* URL params that should be appended, validate and append
- // them to the passed URLSearchParams object. Returns true if the params
- // were validated and appended, and false if the request should be ignored.
- _populateCampaignParams: function(urlSearchParams, extraURLCampaignParams) {
- // We are extra paranoid about what params we allow to be appended.
- if (typeof extraURLCampaignParams == "undefined") {
- // no params, so it's all good.
- return true;
- }
- if (typeof extraURLCampaignParams != "string") {
- log.warn("_populateCampaignParams: extraURLCampaignParams is not a string");
- return false;
- }
- let campaignParams;
- try {
- if (extraURLCampaignParams) {
- campaignParams = JSON.parse(extraURLCampaignParams);
- if (typeof campaignParams != "object") {
- log.warn("_populateCampaignParams: extraURLCampaignParams is not a stringified object");
- return false;
- }
- }
- } catch (ex) {
- log.warn("_populateCampaignParams: extraURLCampaignParams is not a JSON object");
- return false;
- }
- if (campaignParams) {
- // The regex that the name of each param must match - there's no
- // character restriction on the value - they will be escaped as necessary.
- let reSimpleString = /^[-_a-zA-Z0-9]*$/;
- for (let name in campaignParams) {
- let value = campaignParams[name];
- if (typeof name != "string" || typeof value != "string" ||
- !name.startsWith("utm_") ||
- value.length == 0 ||
- !reSimpleString.test(name)) {
- log.warn("_populateCampaignParams: invalid campaign param specified");
- return false;
- }
- urlSearchParams.append(name, value);
- }
- }
- return true;
- },
-
- setTelemetryBucket: function(aPageID) {
- let bucket = BUCKET_NAME + BrowserUITelemetry.BUCKET_SEPARATOR + aPageID;
- BrowserUITelemetry.setBucket(bucket);
- },
-
- setExpiringTelemetryBucket: function(aPageID, aType) {
- let bucket = BUCKET_NAME + BrowserUITelemetry.BUCKET_SEPARATOR + aPageID +
- BrowserUITelemetry.BUCKET_SEPARATOR + aType;
-
- BrowserUITelemetry.setExpiringBucket(bucket,
- BUCKET_TIMESTEPS);
- },
-
- // This is registered with UITelemetry by BrowserUITelemetry, so that UITour
- // can remain lazy-loaded on-demand.
- getTelemetry: function() {
- return {
- seenPageIDs: [...this.seenPageIDs.keys()],
- };
- },
-
- /**
- * Tear down a tour from a tab e.g. upon switching/closing tabs.
- */
- teardownTourForBrowser: function(aWindow, aBrowser, aTourPageClosing = false) {
- log.debug("teardownTourForBrowser: aBrowser = ", aBrowser, aTourPageClosing);
-
- if (this.pageIDSourceBrowsers.has(aBrowser)) {
- let pageID = this.pageIDSourceBrowsers.get(aBrowser);
- this.setExpiringTelemetryBucket(pageID, aTourPageClosing ? "closed" : "inactive");
- }
-
- let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
- if (aTourPageClosing && openTourBrowsers) {
- openTourBrowsers.delete(aBrowser);
- }
-
- this.hideHighlight(aWindow);
- this.hideInfo(aWindow);
- // Ensure the menu panel is hidden before calling recreatePopup so popup events occur.
- this.hideMenu(aWindow, "appMenu");
- this.hideMenu(aWindow, "controlCenter");
-
- // Clean up panel listeners after calling hideMenu above.
- aWindow.PanelUI.panel.removeEventListener("popuphiding", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.removeEventListener("ViewShowing", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.removeEventListener("popuphidden", this.onPanelHidden);
- let controlCenterPanel = aWindow.gIdentityHandler._identityPopup;
- controlCenterPanel.removeEventListener("popuphidden", this.onPanelHidden);
- controlCenterPanel.removeEventListener("popuphiding", this.hideControlCenterAnnotations);
-
- this.resetTheme();
-
- // If there are no more tour tabs left in the window, teardown the tour for the whole window.
- if (!openTourBrowsers || openTourBrowsers.size == 0) {
- this.teardownTourForWindow(aWindow);
- }
- },
-
- /**
- * Tear down all tours for a ChromeWindow.
- */
- teardownTourForWindow: function(aWindow) {
- log.debug("teardownTourForWindow");
- aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
- aWindow.removeEventListener("SSWindowClosing", this);
-
- let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
- if (openTourBrowsers) {
- for (let browser of openTourBrowsers) {
- if (this.pageIDSourceBrowsers.has(browser)) {
- let pageID = this.pageIDSourceBrowsers.get(browser);
- this.setExpiringTelemetryBucket(pageID, "closed");
- }
- }
- }
-
- this.tourBrowsersByWindow.delete(aWindow);
- },
-
- // This function is copied to UITourListener.
- isSafeScheme: function(aURI) {
- let allowedSchemes = new Set(["https", "about"]);
- if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
- allowedSchemes.add("http");
-
- if (!allowedSchemes.has(aURI.scheme)) {
- log.error("Unsafe scheme:", aURI.scheme);
- return false;
- }
-
- return true;
- },
-
- resolveURL: function(aBrowser, aURL) {
- try {
- let uri = Services.io.newURI(aURL, null, aBrowser.currentURI);
-
- if (!this.isSafeScheme(uri))
- return null;
-
- return uri.spec;
- } catch (e) {}
-
- return null;
- },
-
- sendPageCallback: function(aMessageManager, aCallbackID, aData = {}) {
- let detail = {data: aData, callbackID: aCallbackID};
- log.debug("sendPageCallback", detail);
- aMessageManager.sendAsyncMessage("UITour:SendPageCallback", detail);
- },
-
- isElementVisible: function(aElement) {
- let targetStyle = aElement.ownerGlobal.getComputedStyle(aElement);
- return !aElement.ownerDocument.hidden &&
- targetStyle.display != "none" &&
- targetStyle.visibility == "visible";
- },
-
- getTarget: function(aWindow, aTargetName, aSticky = false) {
- log.debug("getTarget:", aTargetName);
- let deferred = Promise.defer();
- if (typeof aTargetName != "string" || !aTargetName) {
- log.warn("getTarget: Invalid target name specified");
- deferred.reject("Invalid target name specified");
- return deferred.promise;
- }
-
- let targetObject = this.targets.get(aTargetName);
- if (!targetObject) {
- log.warn("getTarget: The specified target name is not in the allowed set");
- deferred.reject("The specified target name is not in the allowed set");
- return deferred.promise;
- }
-
- let targetQuery = targetObject.query;
- aWindow.PanelUI.ensureReady().then(() => {
- let node;
- if (typeof targetQuery == "function") {
- try {
- node = targetQuery(aWindow.document);
- } catch (ex) {
- log.warn("getTarget: Error running target query:", ex);
- node = null;
- }
- } else {
- node = aWindow.document.querySelector(targetQuery);
- }
-
- deferred.resolve({
- addTargetListener: targetObject.addTargetListener,
- infoPanelOffsetX: targetObject.infoPanelOffsetX,
- infoPanelOffsetY: targetObject.infoPanelOffsetY,
- infoPanelPosition: targetObject.infoPanelPosition,
- node: node,
- removeTargetListener: targetObject.removeTargetListener,
- targetName: aTargetName,
- widgetName: targetObject.widgetName,
- allowAdd: targetObject.allowAdd,
- });
- }).catch(log.error);
- return deferred.promise;
- },
-
- targetIsInAppMenu: function(aTarget) {
- let placement = CustomizableUI.getPlacementOfWidget(aTarget.widgetName || aTarget.node.id);
- if (placement && placement.area == CustomizableUI.AREA_PANEL) {
- return true;
- }
-
- let targetElement = aTarget.node;
- // Use the widget for filtering if it exists since the target may be the icon inside.
- if (aTarget.widgetName) {
- targetElement = aTarget.node.ownerDocument.getElementById(aTarget.widgetName);
- }
-
- // Handle the non-customizable buttons at the bottom of the menu which aren't proper widgets.
- return targetElement.id.startsWith("PanelUI-")
- && targetElement.id != "PanelUI-button";
- },
-
- /**
- * Called before opening or after closing a highlight or info panel to see if
- * we need to open or close the appMenu to see the annotation's anchor.
- */
- _setAppMenuStateForAnnotation: function(aWindow, aAnnotationType, aShouldOpenForHighlight, aCallback = null) {
- log.debug("_setAppMenuStateForAnnotation:", aAnnotationType);
- log.debug("_setAppMenuStateForAnnotation: Menu is expected to be:", aShouldOpenForHighlight ? "open" : "closed");
-
- // If the panel is in the desired state, we're done.
- let panelIsOpen = aWindow.PanelUI.panel.state != "closed";
- if (aShouldOpenForHighlight == panelIsOpen) {
- log.debug("_setAppMenuStateForAnnotation: Panel already in expected state");
- if (aCallback)
- aCallback();
- return;
- }
-
- // Don't close the menu if it wasn't opened by us (e.g. via showmenu instead).
- if (!aShouldOpenForHighlight && !this.appMenuOpenForAnnotation.has(aAnnotationType)) {
- log.debug("_setAppMenuStateForAnnotation: Menu not opened by us, not closing");
- if (aCallback)
- aCallback();
- return;
- }
-
- if (aShouldOpenForHighlight) {
- this.appMenuOpenForAnnotation.add(aAnnotationType);
- } else {
- this.appMenuOpenForAnnotation.delete(aAnnotationType);
- }
-
- // Actually show or hide the menu
- if (this.appMenuOpenForAnnotation.size) {
- log.debug("_setAppMenuStateForAnnotation: Opening the menu");
- this.showMenu(aWindow, "appMenu", aCallback);
- } else {
- log.debug("_setAppMenuStateForAnnotation: Closing the menu");
- this.hideMenu(aWindow, "appMenu");
- if (aCallback)
- aCallback();
- }
-
- },
-
- previewTheme: function(aTheme) {
- let origin = Services.prefs.getCharPref("browser.uitour.themeOrigin");
- let data = LightweightThemeManager.parseTheme(aTheme, origin);
- if (data)
- LightweightThemeManager.previewTheme(data);
- },
-
- resetTheme: function() {
- LightweightThemeManager.resetPreview();
- },
-
- /**
- * Show the Heartbeat UI to request user feedback. This function reports back to the
- * caller using |notify|. The notification event name reflects the current status the UI
- * is in (either "Heartbeat:NotificationOffered", "Heartbeat:NotificationClosed",
- * "Heartbeat:LearnMore", "Heartbeat:Engaged", "Heartbeat:Voted",
- * "Heartbeat:SurveyExpired" or "Heartbeat:WindowClosed").
- * When a "Heartbeat:Voted" event is notified
- * the data payload contains a |score| field which holds the rating picked by the user.
- * Please note that input parameters are already validated by the caller.
- *
- * @param aChromeWindow
- * The chrome window that the heartbeat notification is displayed in.
- * @param {Object} aOptions Options object.
- * @param {String} aOptions.message
- * The message, or question, to display on the notification.
- * @param {String} aOptions.thankyouMessage
- * The thank you message to display after user votes.
- * @param {String} aOptions.flowId
- * An identifier for this rating flow. Please note that this is only used to
- * identify the notification box.
- * @param {String} [aOptions.engagementButtonLabel=null]
- * The text of the engagement button to use instad of stars. If this is null
- * or invalid, rating stars are used.
- * @param {String} [aOptions.engagementURL=null]
- * The engagement URL to open in a new tab once user has engaged. If this is null
- * or invalid, no new tab is opened.
- * @param {String} [aOptions.learnMoreLabel=null]
- * The label of the learn more link. No link will be shown if this is null.
- * @param {String} [aOptions.learnMoreURL=null]
- * The learn more URL to open when clicking on the learn more link. No learn more
- * will be shown if this is an invalid URL.
- * @param {boolean} [aOptions.privateWindowsOnly=false]
- * Whether the heartbeat UI should only be targeted at a private window (if one exists).
- * No notifications should be fired when this is true.
- * @param {String} [aOptions.surveyId]
- * An ID for the survey, reflected in the Telemetry ping.
- * @param {Number} [aOptions.surveyVersion]
- * Survey's version number, reflected in the Telemetry ping.
- * @param {boolean} [aOptions.testing]
- * Whether this is a test survey, reflected in the Telemetry ping.
- */
- showHeartbeat(aChromeWindow, aOptions) {
- // Initialize survey state
- let pingSent = false;
- let surveyResults = {};
- let surveyEndTimer = null;
-
- /**
- * Accumulates survey events and submits to Telemetry after the survey ends.
- *
- * @param {String} aEventName
- * Heartbeat event name
- * @param {Object} aParams
- * Additional parameters and their values
- */
- let maybeNotifyHeartbeat = (aEventName, aParams = {}) => {
- // Return if event occurred after the ping was sent
- if (pingSent) {
- log.warn("maybeNotifyHeartbeat: event occurred after ping sent:", aEventName, aParams);
- return;
- }
-
- // No Telemetry from private-window-only Heartbeats
- if (aOptions.privateWindowsOnly) {
- return;
- }
-
- let ts = Date.now();
- let sendPing = false;
- switch (aEventName) {
- case "Heartbeat:NotificationOffered":
- surveyResults.flowId = aOptions.flowId;
- surveyResults.offeredTS = ts;
- break;
- case "Heartbeat:LearnMore":
- // record only the first click
- if (!surveyResults.learnMoreTS) {
- surveyResults.learnMoreTS = ts;
- }
- break;
- case "Heartbeat:Engaged":
- surveyResults.engagedTS = ts;
- break;
- case "Heartbeat:Voted":
- surveyResults.votedTS = ts;
- surveyResults.score = aParams.score;
- break;
- case "Heartbeat:SurveyExpired":
- surveyResults.expiredTS = ts;
- break;
- case "Heartbeat:NotificationClosed":
- // this is the final event in most surveys
- surveyResults.closedTS = ts;
- sendPing = true;
- break;
- case "Heartbeat:WindowClosed":
- surveyResults.windowClosedTS = ts;
- sendPing = true;
- break;
- default:
- log.error("maybeNotifyHeartbeat: unrecognized event:", aEventName);
- break;
- }
-
- aParams.timestamp = ts;
- aParams.flowId = aOptions.flowId;
- this.notify(aEventName, aParams);
-
- if (!sendPing) {
- return;
- }
-
- // Send the ping to Telemetry
- let payload = Object.assign({}, surveyResults);
- payload.version = 1;
- for (let meta of ["surveyId", "surveyVersion", "testing"]) {
- if (aOptions.hasOwnProperty(meta)) {
- payload[meta] = aOptions[meta];
- }
- }
-
- log.debug("Sending payload to Telemetry: aEventName:", aEventName,
- "payload:", payload);
-
- TelemetryController.submitExternalPing("heartbeat", payload, {
- addClientId: true,
- addEnvironment: true,
- });
-
- // only for testing
- this.notify("Heartbeat:TelemetrySent", payload);
-
- // Survey is complete, clear out the expiry timer & survey configuration
- if (surveyEndTimer) {
- clearTimeout(surveyEndTimer);
- surveyEndTimer = null;
- }
-
- pingSent = true;
- surveyResults = {};
- };
-
- let nb = aChromeWindow.document.getElementById("high-priority-global-notificationbox");
- let buttons = null;
-
- if (aOptions.engagementButtonLabel) {
- buttons = [{
- label: aOptions.engagementButtonLabel,
- callback: () => {
- // Let the consumer know user engaged.
- maybeNotifyHeartbeat("Heartbeat:Engaged");
-
- userEngaged(new Map([
- ["type", "button"],
- ["flowid", aOptions.flowId]
- ]));
-
- // Return true so that the notification bar doesn't close itself since
- // we have a thank you message to show.
- return true;
- },
- }];
- }
-
- let defaultIcon = "chrome://browser/skin/heartbeat-icon.svg";
- let iconURL = defaultIcon;
- try {
- // Take the optional icon URL if specified
- if (aOptions.iconURL) {
- iconURL = new URL(aOptions.iconURL);
- // For now, only allow chrome URIs.
- if (iconURL.protocol != "chrome:") {
- iconURL = defaultIcon;
- throw new Error("Invalid protocol");
- }
- }
- } catch (error) {
- log.error("showHeartbeat: Invalid icon URL specified.");
- }
-
- // Create the notification. Prefix its ID to decrease the chances of collisions.
- let notice = nb.appendNotification(aOptions.message, "heartbeat-" + aOptions.flowId,
- iconURL,
- nb.PRIORITY_INFO_HIGH, buttons,
- (aEventType) => {
- if (aEventType != "removed") {
- return;
- }
- // Let the consumer know the notification bar was closed.
- // This also happens after voting.
- maybeNotifyHeartbeat("Heartbeat:NotificationClosed");
- });
-
- // Get the elements we need to style.
- let messageImage =
- aChromeWindow.document.getAnonymousElementByAttribute(notice, "anonid", "messageImage");
- let messageText =
- aChromeWindow.document.getAnonymousElementByAttribute(notice, "anonid", "messageText");
-
- function userEngaged(aEngagementParams) {
- // Make the heartbeat icon pulse twice.
- notice.label = aOptions.thankyouMessage;
- messageImage.classList.remove("pulse-onshow");
- messageImage.classList.add("pulse-twice");
-
- // Remove all the children of the notice (rating container
- // and the flex).
- while (notice.firstChild) {
- notice.removeChild(notice.firstChild);
- }
-
- // Make sure that we have a valid URL. If we haven't, do not open the engagement page.
- let engagementURL = null;
- try {
- engagementURL = new URL(aOptions.engagementURL);
- } catch (error) {
- log.error("showHeartbeat: Invalid URL specified.");
- }
-
- // Just open the engagement tab if we have a valid engagement URL.
- if (engagementURL) {
- for (let [param, value] of aEngagementParams) {
- engagementURL.searchParams.append(param, value);
- }
-
- // Open the engagement URL in a new tab.
- aChromeWindow.gBrowser.selectedTab =
- aChromeWindow.gBrowser.addTab(engagementURL.toString(), {
- owner: aChromeWindow.gBrowser.selectedTab,
- relatedToCurrent: true
- });
- }
-
- // Remove the notification bar after 3 seconds.
- aChromeWindow.setTimeout(() => {
- nb.removeNotification(notice);
- }, 3000);
- }
-
- // Create the fragment holding the rating UI.
- let frag = aChromeWindow.document.createDocumentFragment();
-
- // Build the Heartbeat star rating.
- const numStars = aOptions.engagementButtonLabel ? 0 : 5;
- let ratingContainer = aChromeWindow.document.createElement("hbox");
- ratingContainer.id = "star-rating-container";
-
- for (let i = 0; i < numStars; i++) {
- // Create a star rating element.
- let ratingElement = aChromeWindow.document.createElement("toolbarbutton");
-
- // Style it.
- let starIndex = numStars - i;
- ratingElement.className = "plain star-x";
- ratingElement.id = "star" + starIndex;
- ratingElement.setAttribute("data-score", starIndex);
-
- // Add the click handler.
- ratingElement.addEventListener("click", function (evt) {
- let rating = Number(evt.target.getAttribute("data-score"), 10);
-
- // Let the consumer know user voted.
- maybeNotifyHeartbeat("Heartbeat:Voted", { score: rating });
-
- // Append the score data to the engagement URL.
- userEngaged(new Map([
- ["type", "stars"],
- ["score", rating],
- ["flowid", aOptions.flowId]
- ]));
- }.bind(this));
-
- // Add it to the container.
- ratingContainer.appendChild(ratingElement);
- }
-
- frag.appendChild(ratingContainer);
-
- // Make sure the stars are not pushed to the right by the spacer.
- let rightSpacer = aChromeWindow.document.createElement("spacer");
- rightSpacer.flex = 20;
- frag.appendChild(rightSpacer);
-
- messageText.flex = 0; // Collapse the space before the stars.
- let leftSpacer = messageText.nextSibling;
- leftSpacer.flex = 0;
-
- // Make sure that we have a valid learn more URL.
- let learnMoreURL = null;
- try {
- learnMoreURL = new URL(aOptions.learnMoreURL);
- } catch (error) {
- log.error("showHeartbeat: Invalid learnMore URL specified.");
- }
-
- // Add the learn more link.
- if (aOptions.learnMoreLabel && learnMoreURL) {
- let learnMore = aChromeWindow.document.createElement("label");
- learnMore.className = "text-link";
- learnMore.href = learnMoreURL.toString();
- learnMore.setAttribute("value", aOptions.learnMoreLabel);
- learnMore.addEventListener("click", () => maybeNotifyHeartbeat("Heartbeat:LearnMore"));
- frag.appendChild(learnMore);
- }
-
- // Append the fragment and apply the styling.
- notice.appendChild(frag);
- notice.classList.add("heartbeat");
- messageImage.classList.add("heartbeat", "pulse-onshow");
- messageText.classList.add("heartbeat");
-
- // Let the consumer know the notification was shown.
- maybeNotifyHeartbeat("Heartbeat:NotificationOffered");
-
- // End the survey if the user quits, closes the window, or
- // hasn't responded before expiration.
- if (!aOptions.privateWindowsOnly) {
- function handleWindowClosed(aTopic) {
- maybeNotifyHeartbeat("Heartbeat:WindowClosed");
- aChromeWindow.removeEventListener("SSWindowClosing", handleWindowClosed);
- }
- aChromeWindow.addEventListener("SSWindowClosing", handleWindowClosed);
-
- let surveyDuration = Services.prefs.getIntPref(PREF_SURVEY_DURATION) * 1000;
- surveyEndTimer = setTimeout(() => {
- maybeNotifyHeartbeat("Heartbeat:SurveyExpired");
- nb.removeNotification(notice);
- }, surveyDuration);
- }
- },
-
- /**
- * The node to which a highlight or notification(-popup) is anchored is sometimes
- * obscured because it may be inside an overflow menu. This function should figure
- * that out and offer the overflow chevron as an alternative.
- *
- * @param {Node} aAnchor The element that's supposed to be the anchor
- * @type {Node}
- */
- _correctAnchor: function(aAnchor) {
- // If the target is in the overflow panel, just return the overflow button.
- if (aAnchor.getAttribute("overflowedItem")) {
- let doc = aAnchor.ownerDocument;
- let placement = CustomizableUI.getPlacementOfWidget(aAnchor.id);
- let areaNode = doc.getElementById(placement.area);
- return areaNode.overflowable._chevron;
- }
-
- return aAnchor;
- },
-
- /**
- * @param aChromeWindow The chrome window that the highlight is in. Necessary since some targets
- * are in a sub-frame so the defaultView is not the same as the chrome
- * window.
- * @param aTarget The element to highlight.
- * @param aEffect (optional) The effect to use from UITour.highlightEffects or "none".
- * @see UITour.highlightEffects
- */
- showHighlight: function(aChromeWindow, aTarget, aEffect = "none") {
- function showHighlightPanel() {
- let highlighter = aChromeWindow.document.getElementById("UITourHighlight");
-
- let effect = aEffect;
- if (effect == "random") {
- // Exclude "random" from the randomly selected effects.
- let randomEffect = 1 + Math.floor(Math.random() * (this.highlightEffects.length - 1));
- if (randomEffect == this.highlightEffects.length)
- randomEffect--; // On the order of 1 in 2^62 chance of this happening.
- effect = this.highlightEffects[randomEffect];
- }
- // Toggle the effect attribute to "none" and flush layout before setting it so the effect plays.
- highlighter.setAttribute("active", "none");
- aChromeWindow.getComputedStyle(highlighter).animationName;
- highlighter.setAttribute("active", effect);
- highlighter.parentElement.setAttribute("targetName", aTarget.targetName);
- highlighter.parentElement.hidden = false;
-
- let highlightAnchor = this._correctAnchor(aTarget.node);
- let targetRect = highlightAnchor.getBoundingClientRect();
- let highlightHeight = targetRect.height;
- let highlightWidth = targetRect.width;
- let minDimension = Math.min(highlightHeight, highlightWidth);
- let maxDimension = Math.max(highlightHeight, highlightWidth);
-
- // If the dimensions are within 200% of each other (to include the bookmarks button),
- // make the highlight a circle with the largest dimension as the diameter.
- if (maxDimension / minDimension <= 3.0) {
- highlightHeight = highlightWidth = maxDimension;
- highlighter.style.borderRadius = "100%";
- } else {
- highlighter.style.borderRadius = "";
- }
-
- highlighter.style.height = highlightHeight + "px";
- highlighter.style.width = highlightWidth + "px";
-
- // Close a previous highlight so we can relocate the panel.
- if (highlighter.parentElement.state == "showing" || highlighter.parentElement.state == "open") {
- log.debug("showHighlight: Closing previous highlight first");
- highlighter.parentElement.hidePopup();
- }
- /* The "overlap" position anchors from the top-left but we want to centre highlights at their
- minimum size. */
- let highlightWindow = aChromeWindow;
- let containerStyle = highlightWindow.getComputedStyle(highlighter.parentElement);
- let paddingTopPx = 0 - parseFloat(containerStyle.paddingTop);
- let paddingLeftPx = 0 - parseFloat(containerStyle.paddingLeft);
- let highlightStyle = highlightWindow.getComputedStyle(highlighter);
- let highlightHeightWithMin = Math.max(highlightHeight, parseFloat(highlightStyle.minHeight));
- let highlightWidthWithMin = Math.max(highlightWidth, parseFloat(highlightStyle.minWidth));
- let offsetX = paddingTopPx
- - (Math.max(0, highlightWidthWithMin - targetRect.width) / 2);
- let offsetY = paddingLeftPx
- - (Math.max(0, highlightHeightWithMin - targetRect.height) / 2);
- this._addAnnotationPanelMutationObserver(highlighter.parentElement);
- highlighter.parentElement.openPopup(highlightAnchor, "overlap", offsetX, offsetY);
- }
-
- // Prevent showing a panel at an undefined position.
- if (!this.isElementVisible(aTarget.node)) {
- log.warn("showHighlight: Not showing a highlight since the target isn't visible", aTarget);
- return;
- }
-
- this._setAppMenuStateForAnnotation(aChromeWindow, "highlight",
- this.targetIsInAppMenu(aTarget),
- showHighlightPanel.bind(this));
- },
-
- hideHighlight: function(aWindow) {
- let highlighter = aWindow.document.getElementById("UITourHighlight");
- this._removeAnnotationPanelMutationObserver(highlighter.parentElement);
- highlighter.parentElement.hidePopup();
- highlighter.removeAttribute("active");
-
- this._setAppMenuStateForAnnotation(aWindow, "highlight", false);
- },
-
- /**
- * Show an info panel.
- *
- * @param {ChromeWindow} aChromeWindow
- * @param {Node} aAnchor
- * @param {String} [aTitle=""]
- * @param {String} [aDescription=""]
- * @param {String} [aIconURL=""]
- * @param {Object[]} [aButtons=[]]
- * @param {Object} [aOptions={}]
- * @param {String} [aOptions.closeButtonCallback]
- * @param {String} [aOptions.targetCallback]
- */
- showInfo(aChromeWindow, aAnchor, aTitle = "", aDescription = "",
- aIconURL = "", aButtons = [], aOptions = {}) {
- function showInfoPanel(aAnchorEl) {
- aAnchorEl.focus();
-
- let document = aChromeWindow.document;
- let tooltip = document.getElementById("UITourTooltip");
- let tooltipTitle = document.getElementById("UITourTooltipTitle");
- let tooltipDesc = document.getElementById("UITourTooltipDescription");
- let tooltipIcon = document.getElementById("UITourTooltipIcon");
- let tooltipButtons = document.getElementById("UITourTooltipButtons");
-
- if (tooltip.state == "showing" || tooltip.state == "open") {
- tooltip.hidePopup();
- }
-
- tooltipTitle.textContent = aTitle || "";
- tooltipDesc.textContent = aDescription || "";
- tooltipIcon.src = aIconURL || "";
- tooltipIcon.hidden = !aIconURL;
-
- while (tooltipButtons.firstChild)
- tooltipButtons.firstChild.remove();
-
- for (let button of aButtons) {
- let isButton = button.style != "text";
- let el = document.createElement(isButton ? "button" : "label");
- el.setAttribute(isButton ? "label" : "value", button.label);
-
- if (isButton) {
- if (button.iconURL)
- el.setAttribute("image", button.iconURL);
-
- if (button.style == "link")
- el.setAttribute("class", "button-link");
-
- if (button.style == "primary")
- el.setAttribute("class", "button-primary");
-
- // Don't close the popup or call the callback for style=text as they
- // aren't links/buttons.
- let callback = button.callback;
- el.addEventListener("command", event => {
- tooltip.hidePopup();
- callback(event);
- });
- }
-
- tooltipButtons.appendChild(el);
- }
-
- tooltipButtons.hidden = !aButtons.length;
-
- let tooltipClose = document.getElementById("UITourTooltipClose");
- let closeButtonCallback = (event) => {
- this.hideInfo(document.defaultView);
- if (aOptions && aOptions.closeButtonCallback) {
- aOptions.closeButtonCallback();
- }
- };
- tooltipClose.addEventListener("command", closeButtonCallback);
-
- let targetCallback = (event) => {
- let details = {
- target: aAnchor.targetName,
- type: event.type,
- };
- aOptions.targetCallback(details);
- };
- if (aOptions.targetCallback && aAnchor.addTargetListener) {
- aAnchor.addTargetListener(document, targetCallback);
- }
-
- tooltip.addEventListener("popuphiding", function tooltipHiding(event) {
- tooltip.removeEventListener("popuphiding", tooltipHiding);
- tooltipClose.removeEventListener("command", closeButtonCallback);
- if (aOptions.targetCallback && aAnchor.removeTargetListener) {
- aAnchor.removeTargetListener(document, targetCallback);
- }
- });
-
- tooltip.setAttribute("targetName", aAnchor.targetName);
- tooltip.hidden = false;
- let alignment = "bottomcenter topright";
- if (aAnchor.infoPanelPosition) {
- alignment = aAnchor.infoPanelPosition;
- }
-
- let { infoPanelOffsetX: xOffset, infoPanelOffsetY: yOffset } = aAnchor;
-
- this._addAnnotationPanelMutationObserver(tooltip);
- tooltip.openPopup(aAnchorEl, alignment, xOffset || 0, yOffset || 0);
- if (tooltip.state == "closed") {
- document.defaultView.addEventListener("endmodalstate", function endModalStateHandler() {
- document.defaultView.removeEventListener("endmodalstate", endModalStateHandler);
- tooltip.openPopup(aAnchorEl, alignment);
- }, false);
- }
- }
-
- // Prevent showing a panel at an undefined position.
- if (!this.isElementVisible(aAnchor.node)) {
- log.warn("showInfo: Not showing since the target isn't visible", aAnchor);
- return;
- }
-
- this._setAppMenuStateForAnnotation(aChromeWindow, "info",
- this.targetIsInAppMenu(aAnchor),
- showInfoPanel.bind(this, this._correctAnchor(aAnchor.node)));
- },
-
- isInfoOnTarget(aChromeWindow, aTargetName) {
- let document = aChromeWindow.document;
- let tooltip = document.getElementById("UITourTooltip");
- return tooltip.getAttribute("targetName") == aTargetName && tooltip.state != "closed";
- },
-
- hideInfo: function(aWindow) {
- let document = aWindow.document;
-
- let tooltip = document.getElementById("UITourTooltip");
- this._removeAnnotationPanelMutationObserver(tooltip);
- tooltip.hidePopup();
- this._setAppMenuStateForAnnotation(aWindow, "info", false);
-
- let tooltipButtons = document.getElementById("UITourTooltipButtons");
- while (tooltipButtons.firstChild)
- tooltipButtons.firstChild.remove();
- },
-
- showMenu: function(aWindow, aMenuName, aOpenCallback = null) {
- log.debug("showMenu:", aMenuName);
- function openMenuButton(aMenuBtn) {
- if (!aMenuBtn || !aMenuBtn.boxObject || aMenuBtn.open) {
- if (aOpenCallback)
- aOpenCallback();
- return;
- }
- if (aOpenCallback)
- aMenuBtn.addEventListener("popupshown", onPopupShown);
- aMenuBtn.boxObject.openMenu(true);
- }
- function onPopupShown(event) {
- this.removeEventListener("popupshown", onPopupShown);
- aOpenCallback(event);
- }
-
- if (aMenuName == "appMenu") {
- aWindow.PanelUI.panel.setAttribute("noautohide", "true");
- // If the popup is already opened, don't recreate the widget as it may cause a flicker.
- if (aWindow.PanelUI.panel.state != "open") {
- this.recreatePopup(aWindow.PanelUI.panel);
- }
- aWindow.PanelUI.panel.addEventListener("popuphiding", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.addEventListener("ViewShowing", this.hideAppMenuAnnotations);
- aWindow.PanelUI.panel.addEventListener("popuphidden", this.onPanelHidden);
- if (aOpenCallback) {
- aWindow.PanelUI.panel.addEventListener("popupshown", onPopupShown);
- }
- aWindow.PanelUI.show();
- } else if (aMenuName == "bookmarks") {
- let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
- openMenuButton(menuBtn);
- } else if (aMenuName == "controlCenter") {
- let popup = aWindow.gIdentityHandler._identityPopup;
-
- // Add the listener even if the panel is already open since it will still
- // only get registered once even if it was UITour that opened it.
- popup.addEventListener("popuphiding", this.hideControlCenterAnnotations);
- popup.addEventListener("popuphidden", this.onPanelHidden);
-
- popup.setAttribute("noautohide", true);
- this.clearAvailableTargetsCache();
-
- if (popup.state == "open") {
- if (aOpenCallback) {
- aOpenCallback();
- }
- return;
- }
-
- this.recreatePopup(popup);
-
- // Open the control center
- if (aOpenCallback) {
- popup.addEventListener("popupshown", onPopupShown);
- }
- aWindow.document.getElementById("identity-box").click();
- } else if (aMenuName == "pocket") {
- this.getTarget(aWindow, "pocket").then(Task.async(function* onPocketTarget(target) {
- let widgetGroupWrapper = CustomizableUI.getWidget(target.widgetName);
- if (widgetGroupWrapper.type != "view" || !widgetGroupWrapper.viewId) {
- log.error("Can't open the pocket menu without a view");
- return;
- }
- let placement = CustomizableUI.getPlacementOfWidget(target.widgetName);
- if (!placement || !placement.area) {
- log.error("Can't open the pocket menu without a placement");
- return;
- }
-
- if (placement.area == CustomizableUI.AREA_PANEL) {
- // Open the appMenu and wait for it if it's not already opened or showing a subview.
- yield new Promise((resolve, reject) => {
- if (aWindow.PanelUI.panel.state != "closed") {
- if (aWindow.PanelUI.multiView.showingSubView) {
- reject("A subview is already showing");
- return;
- }
-
- resolve();
- return;
- }
-
- aWindow.PanelUI.panel.addEventListener("popupshown", function onShown() {
- aWindow.PanelUI.panel.removeEventListener("popupshown", onShown);
- resolve();
- });
-
- aWindow.PanelUI.show();
- });
- }
-
- let widgetWrapper = widgetGroupWrapper.forWindow(aWindow);
- aWindow.PanelUI.showSubView(widgetGroupWrapper.viewId,
- widgetWrapper.anchor,
- placement.area);
- })).catch(log.error);
- }
- },
-
- hideMenu: function(aWindow, aMenuName) {
- log.debug("hideMenu:", aMenuName);
- function closeMenuButton(aMenuBtn) {
- if (aMenuBtn && aMenuBtn.boxObject)
- aMenuBtn.boxObject.openMenu(false);
- }
-
- if (aMenuName == "appMenu") {
- aWindow.PanelUI.hide();
- } else if (aMenuName == "bookmarks") {
- let menuBtn = aWindow.document.getElementById("bookmarks-menu-button");
- closeMenuButton(menuBtn);
- } else if (aMenuName == "controlCenter") {
- let panel = aWindow.gIdentityHandler._identityPopup;
- panel.hidePopup();
- }
- },
-
- showNewTab: function(aWindow, aBrowser) {
- aWindow.openLinkIn("about:newtab", "current", {targetBrowser: aBrowser});
- },
-
- hideAnnotationsForPanel: function(aEvent, aTargetPositionCallback) {
- let win = aEvent.target.ownerGlobal;
- let annotationElements = new Map([
- // [annotationElement (panel), method to hide the annotation]
- [win.document.getElementById("UITourHighlightContainer"), UITour.hideHighlight.bind(UITour)],
- [win.document.getElementById("UITourTooltip"), UITour.hideInfo.bind(UITour)],
- ]);
- annotationElements.forEach((hideMethod, annotationElement) => {
- if (annotationElement.state != "closed") {
- let targetName = annotationElement.getAttribute("targetName");
- UITour.getTarget(win, targetName).then((aTarget) => {
- // Since getTarget is async, we need to make sure that the target hasn't
- // changed since it may have just moved to somewhere outside of the app menu.
- if (annotationElement.getAttribute("targetName") != aTarget.targetName ||
- annotationElement.state == "closed" ||
- !aTargetPositionCallback(aTarget)) {
- return;
- }
- hideMethod(win);
- }).catch(log.error);
- }
- });
- UITour.appMenuOpenForAnnotation.clear();
- },
-
- hideAppMenuAnnotations: function(aEvent) {
- UITour.hideAnnotationsForPanel(aEvent, UITour.targetIsInAppMenu);
- },
-
- hideControlCenterAnnotations(aEvent) {
- UITour.hideAnnotationsForPanel(aEvent, (aTarget) => {
- return aTarget.targetName.startsWith("controlCenter-");
- });
- },
-
- onPanelHidden: function(aEvent) {
- aEvent.target.removeAttribute("noautohide");
- UITour.recreatePopup(aEvent.target);
- UITour.clearAvailableTargetsCache();
- },
-
- recreatePopup: function(aPanel) {
- // After changing popup attributes that relate to how the native widget is created
- // (e.g. @noautohide) we need to re-create the frame/widget for it to take effect.
- if (aPanel.hidden) {
- // If the panel is already hidden, we don't need to recreate it but flush
- // in case someone just hid it.
- aPanel.clientWidth; // flush
- return;
- }
- aPanel.hidden = true;
- aPanel.clientWidth; // flush
- aPanel.hidden = false;
- },
-
- getConfiguration: function(aMessageManager, aWindow, aConfiguration, aCallbackID) {
- switch (aConfiguration) {
- case "appinfo":
- let props = ["defaultUpdateChannel", "version"];
- let appinfo = {};
- props.forEach(property => appinfo[property] = Services.appinfo[property]);
-
- // Identifier of the partner repack, as stored in preference "distribution.id"
- // and included in Firefox and other update pings. Note this is not the same as
- // Services.appinfo.distributionID (value of MOZ_DISTRIBUTION_ID is set at build time).
- let distribution = "default";
- try {
- distribution = Services.prefs.getDefaultBranch("distribution.").getCharPref("id");
- } catch (e) {}
- appinfo["distribution"] = distribution;
-
- let isDefaultBrowser = null;
- try {
- let shell = aWindow.getShellService();
- if (shell) {
- isDefaultBrowser = shell.isDefaultBrowser(false);
- }
- } catch (e) {}
- appinfo["defaultBrowser"] = isDefaultBrowser;
-
- let canSetDefaultBrowserInBackground = true;
- if (AppConstants.isPlatformAndVersionAtLeast("win", "6.2") ||
- AppConstants.isPlatformAndVersionAtLeast("macosx", "10.10")) {
- canSetDefaultBrowserInBackground = false;
- } else if (AppConstants.platform == "linux") {
- // The ShellService may not exist on some versions of Linux.
- try {
- aWindow.getShellService();
- } catch (e) {
- canSetDefaultBrowserInBackground = null;
- }
- }
-
- appinfo["canSetDefaultBrowserInBackground"] =
- canSetDefaultBrowserInBackground;
-
- this.sendPageCallback(aMessageManager, aCallbackID, appinfo);
- break;
- case "availableTargets":
- this.getAvailableTargets(aMessageManager, aWindow, aCallbackID);
- break;
- case "search":
- case "selectedSearchEngine":
- Services.search.init(rv => {
- let data;
- if (Components.isSuccessCode(rv)) {
- let engines = Services.search.getVisibleEngines();
- data = {
- searchEngineIdentifier: Services.search.defaultEngine.identifier,
- engines: engines.filter((engine) => engine.identifier)
- .map((engine) => TARGET_SEARCHENGINE_PREFIX + engine.identifier)
- };
- } else {
- data = {engines: [], searchEngineIdentifier: ""};
- }
- this.sendPageCallback(aMessageManager, aCallbackID, data);
- });
- break;
- case "sync":
- this.sendPageCallback(aMessageManager, aCallbackID, {
- setup: Services.prefs.prefHasUserValue("services.sync.username"),
- desktopDevices: Preferences.get("services.sync.clients.devices.desktop", 0),
- mobileDevices: Preferences.get("services.sync.clients.devices.mobile", 0),
- totalDevices: Preferences.get("services.sync.numClients", 0),
- });
- break;
- case "canReset":
- this.sendPageCallback(aMessageManager, aCallbackID, ResetProfile.resetSupported());
- break;
- default:
- log.error("getConfiguration: Unknown configuration requested: " + aConfiguration);
- break;
- }
- },
-
- setConfiguration: function(aWindow, aConfiguration, aValue) {
- switch (aConfiguration) {
- case "defaultBrowser":
- // Ignore aValue in this case because the default browser can only
- // be set, not unset.
- try {
- let shell = aWindow.getShellService();
- if (shell) {
- shell.setDefaultBrowser(true, false);
- }
- } catch (e) {}
- break;
- default:
- log.error("setConfiguration: Unknown configuration requested: " + aConfiguration);
- break;
- }
- },
-
- getAvailableTargets: function(aMessageManager, aChromeWindow, aCallbackID) {
- Task.spawn(function*() {
- let window = aChromeWindow;
- let data = this.availableTargetsCache.get(window);
- if (data) {
- log.debug("getAvailableTargets: Using cached targets list", data.targets.join(","));
- this.sendPageCallback(aMessageManager, aCallbackID, data);
- return;
- }
-
- let promises = [];
- for (let targetName of this.targets.keys()) {
- promises.push(this.getTarget(window, targetName));
- }
- let targetObjects = yield Promise.all(promises);
-
- let targetNames = [];
- for (let targetObject of targetObjects) {
- if (targetObject.node)
- targetNames.push(targetObject.targetName);
- }
-
- data = {
- targets: targetNames,
- };
- this.availableTargetsCache.set(window, data);
- this.sendPageCallback(aMessageManager, aCallbackID, data);
- }.bind(this)).catch(err => {
- log.error(err);
- this.sendPageCallback(aMessageManager, aCallbackID, {
- targets: [],
- });
- });
- },
-
- startSubTour: function (aFeature) {
- if (aFeature != "string") {
- log.error("startSubTour: No feature option specified");
- return;
- }
-
- if (aFeature == "readinglist") {
- ReaderParent.showReaderModeInfoPanel(browser);
- } else {
- log.error("startSubTour: Unknown feature option specified");
- return;
- }
- },
-
- addNavBarWidget: function (aTarget, aMessageManager, aCallbackID) {
- if (aTarget.node) {
- log.error("addNavBarWidget: can't add a widget already present:", aTarget);
- return;
- }
- if (!aTarget.allowAdd) {
- log.error("addNavBarWidget: not allowed to add this widget:", aTarget);
- return;
- }
- if (!aTarget.widgetName) {
- log.error("addNavBarWidget: can't add a widget without a widgetName property:", aTarget);
- return;
- }
-
- CustomizableUI.addWidgetToArea(aTarget.widgetName, CustomizableUI.AREA_NAVBAR);
- this.sendPageCallback(aMessageManager, aCallbackID);
- },
-
- _addAnnotationPanelMutationObserver: function(aPanelEl) {
- if (AppConstants.platform == "linux") {
- let observer = this._annotationPanelMutationObservers.get(aPanelEl);
- if (observer) {
- return;
- }
- let win = aPanelEl.ownerGlobal;
- observer = new win.MutationObserver(this._annotationMutationCallback);
- this._annotationPanelMutationObservers.set(aPanelEl, observer);
- let observerOptions = {
- attributeFilter: ["height", "width"],
- attributes: true,
- };
- observer.observe(aPanelEl, observerOptions);
- }
- },
-
- _removeAnnotationPanelMutationObserver: function(aPanelEl) {
- if (AppConstants.platform == "linux") {
- let observer = this._annotationPanelMutationObservers.get(aPanelEl);
- if (observer) {
- observer.disconnect();
- this._annotationPanelMutationObservers.delete(aPanelEl);
- }
- }
- },
-
-/**
- * Workaround for Ubuntu panel craziness in bug 970788 where incorrect sizes get passed to
- * nsXULPopupManager::PopupResized and lead to incorrect width and height attributes getting
- * set on the panel.
- */
- _annotationMutationCallback: function(aMutations) {
- for (let mutation of aMutations) {
- // Remove both attributes at once and ignore remaining mutations to be proccessed.
- mutation.target.removeAttribute("width");
- mutation.target.removeAttribute("height");
- return;
- }
- },
-
- selectSearchEngine(aID) {
- return new Promise((resolve, reject) => {
- Services.search.init((rv) => {
- if (!Components.isSuccessCode(rv)) {
- reject("selectSearchEngine: search service init failed: " + rv);
- return;
- }
-
- let engines = Services.search.getVisibleEngines();
- for (let engine of engines) {
- if (engine.identifier == aID) {
- Services.search.defaultEngine = engine;
- resolve();
- return;
- }
- }
- reject("selectSearchEngine could not find engine with given ID");
- return;
- });
- });
- },
-
- notify(eventName, params) {
- let winEnum = Services.wm.getEnumerator("navigator:browser");
- while (winEnum.hasMoreElements()) {
- let window = winEnum.getNext();
- if (window.closed)
- continue;
-
- let openTourBrowsers = this.tourBrowsersByWindow.get(window);
- if (!openTourBrowsers)
- continue;
-
- for (let browser of openTourBrowsers) {
- let messageManager = browser.messageManager;
- if (!messageManager) {
- log.error("notify: Trying to notify a browser without a messageManager", browser);
- continue;
- }
- let detail = {
- event: eventName,
- params: params,
- };
- messageManager.sendAsyncMessage("UITour:SendPageNotification", detail);
- }
- }
- },
-};
-
-function controlCenterTrackingToggleTarget(aUnblock) {
- return {
- infoPanelPosition: "rightcenter topleft",
- query(aDocument) {
- let popup = aDocument.defaultView.gIdentityHandler._identityPopup;
- if (popup.state != "open") {
- return null;
- }
- let buttonId = null;
- if (aUnblock) {
- if (PrivateBrowsingUtils.isWindowPrivate(aDocument.defaultView)) {
- buttonId = "tracking-action-unblock-private";
- } else {
- buttonId = "tracking-action-unblock";
- }
- } else {
- buttonId = "tracking-action-block";
- }
- let element = aDocument.getElementById(buttonId);
- return UITour.isElementVisible(element) ? element : null;
- },
- };
-}
-
-this.UITour.init();
-
-/**
- * UITour Health Report
- */
-/**
- * Public API to be called by the UITour code
- */
-const UITourHealthReport = {
- recordTreatmentTag: function(tag, value) {
- return TelemetryController.submitExternalPing("uitour-tag",
- {
- version: 1,
- tagName: tag,
- tagValue: value,
- },
- {
- addClientId: true,
- addEnvironment: true,
- });
- }
-};
diff --git a/browser/components/uitour/content-UITour.js b/browser/components/uitour/content-UITour.js
deleted file mode 100644
index c33d687e8b..0000000000
--- a/browser/components/uitour/content-UITour.js
+++ /dev/null
@@ -1,103 +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/. */
-
-var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
-
-const PREF_TEST_WHITELIST = "browser.uitour.testingOrigins";
-const UITOUR_PERMISSION = "uitour";
-
-var UITourListener = {
- handleEvent: function (event) {
- if (!Services.prefs.getBoolPref("browser.uitour.enabled")) {
- return;
- }
- if (!this.ensureTrustedOrigin()) {
- return;
- }
- addMessageListener("UITour:SendPageCallback", this);
- addMessageListener("UITour:SendPageNotification", this);
- sendAsyncMessage("UITour:onPageEvent", {
- detail: event.detail,
- type: event.type,
- pageVisibilityState: content.document.visibilityState,
- });
- },
-
- isTestingOrigin: function(aURI) {
- if (Services.prefs.getPrefType(PREF_TEST_WHITELIST) != Services.prefs.PREF_STRING) {
- return false;
- }
-
- // Add any testing origins (comma-seperated) to the whitelist for the session.
- for (let origin of Services.prefs.getCharPref(PREF_TEST_WHITELIST).split(",")) {
- try {
- let testingURI = Services.io.newURI(origin, null, null);
- if (aURI.prePath == testingURI.prePath) {
- return true;
- }
- } catch (ex) {
- Cu.reportError(ex);
- }
- }
- return false;
- },
-
- // This function is copied from UITour.jsm.
- isSafeScheme: function(aURI) {
- let allowedSchemes = new Set(["https", "about"]);
- if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
- allowedSchemes.add("http");
-
- if (!allowedSchemes.has(aURI.scheme))
- return false;
-
- return true;
- },
-
- ensureTrustedOrigin: function() {
- if (content.top != content)
- return false;
-
- let uri = content.document.documentURIObject;
-
- if (uri.schemeIs("chrome"))
- return true;
-
- if (!this.isSafeScheme(uri))
- return false;
-
- let permission = Services.perms.testPermission(uri, UITOUR_PERMISSION);
- if (permission == Services.perms.ALLOW_ACTION)
- return true;
-
- return this.isTestingOrigin(uri);
- },
-
- receiveMessage: function(aMessage) {
- switch (aMessage.name) {
- case "UITour:SendPageCallback":
- this.sendPageEvent("Response", aMessage.data);
- break;
- case "UITour:SendPageNotification":
- this.sendPageEvent("Notification", aMessage.data);
- break;
- }
- },
-
- sendPageEvent: function (type, detail) {
- if (!this.ensureTrustedOrigin()) {
- return;
- }
-
- let doc = content.document;
- let eventName = "mozUITour" + type;
- let event = new doc.defaultView.CustomEvent(eventName, {
- bubbles: true,
- detail: Cu.cloneInto(detail, doc.defaultView)
- });
- doc.dispatchEvent(event);
- }
-};
-
-addEventListener("mozUITour", UITourListener, false, true);
diff --git a/browser/components/uitour/jar.mn b/browser/components/uitour/jar.mn
deleted file mode 100644
index 966a69c966..0000000000
--- a/browser/components/uitour/jar.mn
+++ /dev/null
@@ -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/.
-
-browser.jar:
- content/browser/content-UITour.js
diff --git a/browser/components/uitour/moz.build b/browser/components/uitour/moz.build
deleted file mode 100644
index c8b1450b99..0000000000
--- a/browser/components/uitour/moz.build
+++ /dev/null
@@ -1,9 +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/.
-
-EXTRA_JS_MODULES += [
- 'UITour.jsm',
-]
-
-JAR_MANIFESTS += ['jar.mn']
diff --git a/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd b/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd
index de92ad3aab..1079c3cef3 100644
--- a/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd
+++ b/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd
@@ -37,9 +37,6 @@
<!ENTITY helpFeedbackPage.label "Submit Feedback…">
<!ENTITY helpFeedbackPage.accesskey "S">
-<!ENTITY helpShowTour2.label "&brandShorterName; Tour">
-<!ENTITY helpShowTour2.accesskey "o">
-
<!ENTITY preferencesCmdMac.label "Preferences…">
<!ENTITY preferencesCmdMac.commandkey ",">
diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd
index 1045977e87..0b2e41612f 100644
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -828,8 +828,6 @@ you can use these alternative items. Otherwise, their values should be empty. -
a CSS length value. -->
<!ENTITY pluginNotification.width "28em">
-<!ENTITY uiTour.infoPanel.close "Close">
-
<!ENTITY appMenuSidebars.label "Sidebars">
<!-- LOCALIZATION NOTE: (panicButton.view.mainTimeframeDesc, panicButton.view.5min, panicButton.view.2hr, panicButton.view.day):
diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties
index 46b8aabc70..8f4036dcd4 100644
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -336,15 +336,6 @@ identity.identified.state_and_country=%S, %S
identity.icon.tooltip=Show site information
-trackingProtection.intro.title=How Tracking Protection works
-# LOCALIZATION NOTE (trackingProtection.intro.description2):
-# %S is brandShortName. This string should match the one from Step 1 of the tour
-# when it starts from the button shown when a new private window is opened.
-trackingProtection.intro.description2=When you see the shield, %S is blocking some parts of the page that could track your browsing activity.
-# LOCALIZATION NOTE (trackingProtection.intro.step1of3): Indicates that the intro panel is step one of three in a tour.
-trackingProtection.intro.step1of3=1 of 3
-trackingProtection.intro.nextButton.label=Next
-
trackingProtection.icon.activeTooltip=Tracking attempts blocked
trackingProtection.icon.disabledTooltip=Tracking content detected
@@ -606,13 +597,6 @@ flashHang.message = %S changed some Adobe Flash settings to improve performance.
flashHang.helpButton.label = Learn More…
flashHang.helpButton.accesskey = L
-# LOCALIZATION NOTE(customizeTips.tip0): %1$S will be replaced with the text defined
-# in customizeTips.tip0.hint, %2$S will be replaced with brandShortName, %3$S will
-# be replaced with a hyperlink containing the text defined in customizeTips.tip0.learnMore.
-customizeTips.tip0 = %1$S: You can customize %2$S to work the way you do. Simply drag any of the above to the menu or toolbar. %3$S about customizing %2$S.
-customizeTips.tip0.hint = Hint
-customizeTips.tip0.learnMore = Learn more
-
# LOCALIZATION NOTE (customizeMode.tabTitle): %S is brandShortName
customizeMode.tabTitle = Customize %S
diff --git a/browser/modules/BrowserUITelemetry.jsm b/browser/modules/BrowserUITelemetry.jsm
index 2ad319f1a4..2b7cc8c204 100644
--- a/browser/modules/BrowserUITelemetry.jsm
+++ b/browser/modules/BrowserUITelemetry.jsm
@@ -17,8 +17,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "UITour",
- "resource:///modules/UITour.jsm");
XPCOMUtils.defineLazyGetter(this, "Timer", function() {
let timer = {};
Cu.import("resource://gre/modules/Timer.jsm", timer);
@@ -174,11 +172,6 @@ this.BrowserUITelemetry = {
this.getToolbarMeasures.bind(this));
UITelemetry.addSimpleMeasureFunction("contextmenu",
this.getContextMenuInfo.bind(this));
- // Ensure that UITour.jsm remains lazy-loaded, yet always registers its
- // simple measure function with UITelemetry.
- UITelemetry.addSimpleMeasureFunction("UITour",
- () => UITour.getTelemetry());
-
UITelemetry.addSimpleMeasureFunction("syncstate",
this.getSyncState.bind(this));
diff --git a/browser/modules/SelfSupportBackend.jsm b/browser/modules/SelfSupportBackend.jsm
deleted file mode 100644
index 3a3f8cb8bd..0000000000
--- a/browser/modules/SelfSupportBackend.jsm
+++ /dev/null
@@ -1,331 +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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["SelfSupportBackend"];
-
-const Cu = Components.utils;
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Cu.import("resource://gre/modules/Log.jsm");
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Timer.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HiddenFrame",
- "resource:///modules/HiddenFrame.jsm");
-
-// Enables or disables the Self Support.
-const PREF_ENABLED = "browser.selfsupport.enabled";
-// Url to open in the Self Support browser, in the urlFormatter service format.
-const PREF_URL = "browser.selfsupport.url";
-// Unified Telemetry status.
-const PREF_TELEMETRY_UNIFIED = "toolkit.telemetry.unified";
-// UITour status.
-const PREF_UITOUR_ENABLED = "browser.uitour.enabled";
-
-// Controls the interval at which the self support page tries to reload in case of
-// errors.
-const RETRY_INTERVAL_MS = 30000;
-// Maximum number of SelfSupport page load attempts in case of failure.
-const MAX_RETRIES = 5;
-// The delay after which to load the self-support, at startup.
-const STARTUP_DELAY_MS = 5000;
-
-const LOGGER_NAME = "Browser.SelfSupportBackend";
-const PREF_BRANCH_LOG = "browser.selfsupport.log.";
-const PREF_LOG_LEVEL = PREF_BRANCH_LOG + "level";
-const PREF_LOG_DUMP = PREF_BRANCH_LOG + "dump";
-
-const HTML_NS = "http://www.w3.org/1999/xhtml";
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-const UITOUR_FRAME_SCRIPT = "chrome://browser/content/content-UITour.js";
-
-// Whether the FHR/Telemetry unification features are enabled.
-// Changing this pref requires a restart.
-const IS_UNIFIED_TELEMETRY = Preferences.get(PREF_TELEMETRY_UNIFIED, false);
-
-var gLogAppenderDump = null;
-
-this.SelfSupportBackend = Object.freeze({
- init: function () {
- SelfSupportBackendInternal.init();
- },
-
- uninit: function () {
- SelfSupportBackendInternal.uninit();
- },
-});
-
-var SelfSupportBackendInternal = {
- // The browser element that will load the SelfSupport page.
- _browser: null,
- // The Id of the timer triggering delayed SelfSupport page load.
- _delayedLoadTimerId: null,
- // The HiddenFrame holding the _browser element.
- _frame: null,
- _log: null,
- _progressListener: null,
-
- /**
- * Initializes the self support backend.
- */
- init: function () {
- this._configureLogging();
-
- this._log.trace("init");
-
- Preferences.observe(PREF_BRANCH_LOG, this._configureLogging, this);
-
- // Only allow to use SelfSupport if Unified Telemetry is enabled.
- let reportingEnabled = IS_UNIFIED_TELEMETRY;
- if (!reportingEnabled) {
- this._log.config("init - Disabling SelfSupport because FHR and Unified Telemetry are disabled.");
- return;
- }
-
- // Make sure UITour is enabled.
- let uiTourEnabled = Preferences.get(PREF_UITOUR_ENABLED, false);
- if (!uiTourEnabled) {
- this._log.config("init - Disabling SelfSupport because UITour is disabled.");
- return;
- }
-
- // Check the preferences to see if we want this to be active.
- if (!Preferences.get(PREF_ENABLED, true)) {
- this._log.config("init - SelfSupport is disabled.");
- return;
- }
-
- Services.obs.addObserver(this, "sessionstore-windows-restored", false);
- },
-
- /**
- * Shut down the self support backend, if active.
- */
- uninit: function () {
- this._log.trace("uninit");
-
- Preferences.ignore(PREF_BRANCH_LOG, this._configureLogging, this);
-
- // Cancel delayed loading, if still active, when shutting down.
- clearTimeout(this._delayedLoadTimerId);
-
- // Dispose of the hidden browser.
- if (this._browser !== null) {
- if (this._browser.contentWindow) {
- this._browser.contentWindow.removeEventListener("DOMWindowClose", this, true);
- }
-
- if (this._progressListener) {
- this._browser.removeProgressListener(this._progressListener);
- this._progressListener.destroy();
- this._progressListener = null;
- }
-
- this._browser.remove();
- this._browser = null;
- }
-
- if (this._frame) {
- this._frame.destroy();
- this._frame = null;
- }
- },
-
- /**
- * Handle notifications. Once all windows are created, we wait a little bit more
- * since tabs might still be loading. Then, we open the self support.
- */
- observe: function (aSubject, aTopic, aData) {
- this._log.trace("observe - Topic " + aTopic);
-
- if (aTopic === "sessionstore-windows-restored") {
- Services.obs.removeObserver(this, "sessionstore-windows-restored");
- this._delayedLoadTimerId = setTimeout(this._loadSelfSupport.bind(this), STARTUP_DELAY_MS);
- }
- },
-
- /**
- * Configure the logger based on the preferences.
- */
- _configureLogging: function() {
- if (!this._log) {
- this._log = Log.repository.getLogger(LOGGER_NAME);
-
- // Log messages need to go to the browser console.
- let consoleAppender = new Log.ConsoleAppender(new Log.BasicFormatter());
- this._log.addAppender(consoleAppender);
- }
-
- // Make sure the logger keeps up with the logging level preference.
- this._log.level = Log.Level[Preferences.get(PREF_LOG_LEVEL, "Warn")];
-
- // If enabled in the preferences, add a dump appender.
- let logDumping = Preferences.get(PREF_LOG_DUMP, false);
- if (logDumping != !!gLogAppenderDump) {
- if (logDumping) {
- gLogAppenderDump = new Log.DumpAppender(new Log.BasicFormatter());
- this._log.addAppender(gLogAppenderDump);
- } else {
- this._log.removeAppender(gLogAppenderDump);
- gLogAppenderDump = null;
- }
- }
- },
-
- /**
- * Create an hidden frame to host our |browser|, then load the SelfSupport page in it.
- * @param aURL The URL to load in the browser.
- */
- _makeHiddenBrowser: function(aURL) {
- this._frame = new HiddenFrame();
- return this._frame.get().then(aFrame => {
- let doc = aFrame.document;
-
- this._browser = doc.createElementNS(XUL_NS, "browser");
- this._browser.setAttribute("type", "content");
- this._browser.setAttribute("disableglobalhistory", "true");
- this._browser.setAttribute("src", aURL);
-
- doc.documentElement.appendChild(this._browser);
- });
- },
-
- handleEvent: function(aEvent) {
- this._log.trace("handleEvent - aEvent.type " + aEvent.type + ", Trusted " + aEvent.isTrusted);
-
- if (aEvent.type === "DOMWindowClose") {
- let window = this._browser.contentDocument.defaultView;
- let target = aEvent.target;
-
- if (target == window) {
- // preventDefault stops the default window.close(). We need to do that to prevent
- // Services.appShell.hiddenDOMWindow from being destroyed.
- aEvent.preventDefault();
-
- this.uninit();
- }
- }
- },
-
- /**
- * Called when the self support page correctly loads.
- */
- _pageSuccessCallback: function() {
- this._log.debug("_pageSuccessCallback - Page correctly loaded.");
- this._browser.removeProgressListener(this._progressListener);
- this._progressListener.destroy();
- this._progressListener = null;
-
- // Allow SelfSupportBackend to catch |window.close()| issued by the content.
- this._browser.contentWindow.addEventListener("DOMWindowClose", this, true);
- },
-
- /**
- * Called when the self support page fails to load.
- */
- _pageLoadErrorCallback: function() {
- this._log.info("_pageLoadErrorCallback - Too many failed load attempts. Giving up.");
- this.uninit();
- },
-
- /**
- * Create a browser and attach it to an hidden window. The browser will contain the
- * self support page and attempt to load the page content. If loading fails, try again
- * after an interval.
- */
- _loadSelfSupport: function() {
- // Fetch the Self Support URL from the preferences.
- let unformattedURL = Preferences.get(PREF_URL, null);
- let url = Services.urlFormatter.formatURL(unformattedURL);
- if (!url.startsWith("https:")) {
- this._log.error("_loadSelfSupport - Non HTTPS URL provided: " + url);
- return;
- }
-
- this._log.config("_loadSelfSupport - URL " + url);
-
- // Create the hidden browser.
- this._makeHiddenBrowser(url).then(() => {
- // Load UITour frame script.
- this._browser.messageManager.loadFrameScript(UITOUR_FRAME_SCRIPT, true);
-
- // We need to watch for load errors as well and, in case, try to reload
- // the self support page.
- const webFlags = Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
- Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
- Ci.nsIWebProgress.NOTIFY_LOCATION;
-
- this._progressListener = new ProgressListener(() => this._pageLoadErrorCallback(),
- () => this._pageSuccessCallback());
-
- this._browser.addProgressListener(this._progressListener, webFlags);
- });
- }
-};
-
-/**
- * A progress listener object which notifies of page load error and load success
- * through callbacks. When the page fails to load, the progress listener tries to
- * reload it up to MAX_RETRIES times. The page is not loaded again immediately, but
- * after a timeout.
- *
- * @param aLoadErrorCallback Called when a page failed to load MAX_RETRIES times.
- * @param aLoadSuccessCallback Called when a page correctly loads.
- */
-function ProgressListener(aLoadErrorCallback, aLoadSuccessCallback) {
- this._loadErrorCallback = aLoadErrorCallback;
- this._loadSuccessCallback = aLoadSuccessCallback;
- // The number of page loads attempted.
- this._loadAttempts = 0;
- this._log = Log.repository.getLogger(LOGGER_NAME);
- // The Id of the timer which triggers page load again in case of errors.
- this._reloadTimerId = null;
-}
-
-ProgressListener.prototype = {
- onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
- if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
- this._log.warn("onLocationChange - There was a problem fetching the SelfSupport URL (attempt " +
- this._loadAttempts + ").");
-
- // Increase the number of attempts and bail out if we failed too many times.
- this._loadAttempts++;
- if (this._loadAttempts > MAX_RETRIES) {
- this._loadErrorCallback();
- return;
- }
-
- // Reload the page after the retry interval expires. The interval is multiplied
- // by the number of attempted loads, so that it takes a bit more to try to reload
- // when frequently failing.
- this._reloadTimerId = setTimeout(() => {
- this._log.debug("onLocationChange - Reloading SelfSupport URL in the hidden browser.");
- aWebProgress.DOMWindow.location.reload();
- }, RETRY_INTERVAL_MS * this._loadAttempts);
- }
- },
-
- onStateChange: function (aWebProgress, aRequest, aFlags, aStatus) {
- if (aFlags & Ci.nsIWebProgressListener.STATE_STOP &&
- aFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
- aFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
- Components.isSuccessCode(aStatus)) {
- this._loadSuccessCallback();
- }
- },
-
- destroy: function () {
- // Make sure we don't try to reload self support when shutting down.
- clearTimeout(this._reloadTimerId);
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
- Ci.nsISupportsWeakReference]),
-};
diff --git a/browser/modules/moz.build b/browser/modules/moz.build
index a7bbbc258f..684f662d79 100644
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -33,7 +33,6 @@ EXTRA_JS_MODULES += [
'RecentWindow.jsm',
'RemotePrompt.jsm',
'Sanitizer.jsm',
- 'SelfSupportBackend.jsm',
'SitePermissions.jsm',
'TransientPrefs.jsm',
'URLBarZoom.jsm',
diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css
index 3e6b81512d..534d148340 100644
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1543,11 +1543,6 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
border-left: 3px solid transparent;
}
-/* The :hover:active style from toolkit doesn't seem to work in this panel so just use :active. */
-.customization-tipPanel-closeBox > .close-icon:active {
- background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 48, 16, 32);
-}
-
/* End customization mode */
@@ -1556,40 +1551,6 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton:not(:h
width: 40px;
}
-%include ../shared/UITour.inc.css
-
-#UITourHighlight {
- /* Below are some fixes for people without an X compositor on Linux.
- This is why we can't have nice things: */
- /* Animations don't repaint properly without an X compositor. */
- animation-name: none !important;
- /* Opacity rounds to 0 or 1 on Linux without an X compositor so make the
- background be transparent in that case by having all alpha values < 0.5 */
- background-image: radial-gradient(50% 100%, rgba(0,149,220,0.3) 50%, rgba(0,149,220,0.49) 100%);
- /* The highlight isn't anti-aliased without an X compositor so make it thicker.
- Make it a darker color since we don't have the box-shadow in this case. */
- border: 4px solid rgb(0,149,220);
-}
-
-#UITourTooltipDescription {
- font-size: 1.05rem;
-}
-
-#UITourTooltipClose {
- margin-inline-end: -4px;
- height: 16px;
- width: 16px;
-}
-
-/**
- * Override the --arrowpanel-padding so the background extends
- * to the sides and bottom of the panel.
- */
-#UITourTooltipButtons {
- margin-left: -10px;
- margin-bottom: -10px;
-}
-
%include ../shared/contextmenu.inc.css
#context-navigation > .menuitem-iconic > .menu-iconic-left {
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
index 5a83c74b2a..b8d567a598 100644
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -3192,24 +3192,6 @@ menulist.translate-infobar-element > .menulist-dropmarker {
}
@media (min-resolution: 2dppx) {
- .customization-tipPanel-infoBox {
- background-image: url(chrome://browser/skin/customizableui/info-icon-customizeTip@2x.png);
- background-size: 25px 25px;
- }
-
- .customization-tipPanel-contentImage {
- list-style-image: url(chrome://browser/skin/customizableui/customize-illustration@2x.png);
- }
-
- .customization-tipPanel-contentImage:-moz-locale-dir(rtl) {
- list-style-image: url(chrome://browser/skin/customizableui/customize-illustration-rtl@2x.png);
- }
-
- #customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="left"],
- #customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="right"] {
- list-style-image: url("chrome://browser/skin/customizableui/panelarrow-customizeTip@2x.png");
- }
-
.customization-lwtheme-menu-theme[defaulttheme] {
list-style-image: url(chrome://browser/skin/theme-switcher-icon@2x.png);
}
@@ -3279,24 +3261,6 @@ menulist.translate-infobar-element > .menulist-dropmarker {
-moz-box-ordinal-group: 0;
}
-%include ../shared/UITour.inc.css
-
-#UITourTooltipDescription {
- font-size: 1.18rem;
- line-height: 2rem;
-}
-
-#UITourTooltipClose {
- margin-inline-end: -10px;
- margin-top: -14px;
-}
-
-@media (min-resolution: 2dppx) {
- #UITourTooltipClose > .toolbarbutton-icon {
- width: 16px;
- }
-}
-
%include ../shared/contextmenu.inc.css
#context-navigation > .menuitem-iconic {
diff --git a/browser/themes/shared/UITour.inc.css b/browser/themes/shared/UITour.inc.css
deleted file mode 100644
index bc89ade76f..0000000000
--- a/browser/themes/shared/UITour.inc.css
+++ /dev/null
@@ -1,293 +0,0 @@
-%if 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/. */
-%endif
-
-/* UI Tour */
-
-#UITourHighlightContainer {
- -moz-appearance: none;
- -moz-window-shadow: none;
- border: none;
- background-color: transparent;
- /* This is a buffer to compensate for the movement in the "wobble" effect,
- and for the box-shadow of #UITourHighlight. */
- padding: 4px;
-}
-
-#UITourHighlight {
- background-image: radial-gradient(50% 100%, rgba(0,149,220,0.4) 50%, rgba(0,149,220,0.6) 100%);
- border-radius: 40px;
- border: 1px solid white;
- /* The box-shadow opacity needs to be < 0.5 so it doesn't appear at 100% opacity
- on Linux without an X compositor where opacity is either 0 or 1. */
- box-shadow: 0 0 3px 0 rgba(0,0,0,0.49);
- min-height: 32px;
- min-width: 32px;
-}
-
-#UITourTooltipBody {
- -moz-box-align: start;
-}
-
-#UITourTooltipTitleContainer {
- -moz-box-align: start;
- margin-bottom: 10px;
-}
-
-#UITourTooltipIcon {
- width: 48px;
- height: 48px;
- margin-inline-end: 10px;
-}
-
-#UITourTooltipTitle,
-#UITourTooltipDescription {
- max-width: 20rem;
-}
-
-#UITourTooltipTitle {
- font-size: 1.45rem;
- font-weight: bold;
- margin: 0;
-}
-
-#UITourTooltipDescription {
- margin-inline-start: 0;
- margin-inline-end: 0;
- font-size: 1.15rem;
- line-height: 1.8rem;
- margin-bottom: 0; /* Override global.css */
-}
-
-#UITourTooltipClose {
- position: relative;
- -moz-appearance: none;
- border: none;
- background-color: transparent;
- min-width: 0;
- margin-inline-start: 4px;
- margin-top: -2px;
-}
-
-#UITourTooltipClose > .toolbarbutton-text {
- display: none;
-}
-
-#UITourTooltipButtons {
- -moz-box-pack: end;
- background-color: hsla(210,4%,10%,.07);
- border-top: 1px solid hsla(210,4%,10%,.14);
- margin: 10px -16px -16px;
- padding: 16px;
-}
-
-#UITourTooltipButtons > label,
-#UITourTooltipButtons > button {
- margin: 0 15px;
-}
-
-#UITourTooltipButtons > label:first-child,
-#UITourTooltipButtons > button:first-child {
- margin-inline-start: 0;
-}
-
-#UITourTooltipButtons > label:last-child,
-#UITourTooltipButtons > button:last-child {
- margin-inline-end: 0;
-}
-
-#UITourTooltipButtons > button[image] > .button-box > .button-icon {
- width: 16px;
- height: 16px;
- margin-inline-end: 5px;
-}
-
-#UITourTooltipButtons > label,
-#UITourTooltipButtons > button .button-text {
- font-size: 1.15rem;
-}
-
-#UITourTooltipButtons > button:not(.button-link) {
- -moz-appearance: none;
- background-color: rgb(251,251,251);
- border-radius: 3px;
- border: 1px solid;
- border-color: rgb(192,192,192);
- color: rgb(71,71,71);
- padding: 4px 30px;
- transition-property: background-color, border-color;
- transition-duration: 150ms;
-}
-
-#UITourTooltipButtons > button:not(.button-link):not(:active):hover {
- background-color: hsla(210,4%,10%,.15);
- border-color: hsla(210,4%,10%,.15);
- box-shadow: 0 1px 0 0 hsla(210,4%,10%,.05) inset;
-}
-
-#UITourTooltipButtons > label,
-#UITourTooltipButtons > button.button-link {
- -moz-appearance: none;
- background: transparent;
- border: none;
- box-shadow: none;
- color: rgba(0,0,0,0.35);
- padding-left: 10px;
- padding-right: 10px;
-}
-
-#UITourTooltipButtons > button.button-link:hover {
- color: black;
-}
-
-/* The primary button gets the same color as the customize button. */
-#UITourTooltipButtons > button.button-primary {
- background-color: rgb(116,191,67);
- color: white;
- padding-left: 30px;
- padding-right: 30px;
-}
-
-#UITourTooltipButtons > button.button-primary:not(:active):hover {
- background-color: rgb(105,173,61);
-}
-
-/* Notification overrides for Heartbeat UI */
-
-notification.heartbeat {
-%ifdef XP_MACOSX
- background-image: linear-gradient(-179deg, #FBFBFB 0%, #EBEBEB 100%);
-%else
- background-color: #F1F1F1;
-%endif
- border-bottom: 1px solid #C1C1C1;
- height: 40px;
-}
-
-/* In themes/osx/global/notification.css the close icon is inverted because notifications
- on OSX are usually dark. Heartbeat is light, so override that behaviour. */
-
-%ifdef XP_MACOSX
-notification.heartbeat[type="info"] .close-icon:not(:hover) {
- -moz-image-region: rect(0, 16px, 16px, 0px) !important;
-}
-@media (min-resolution: 2dppx) {
- notification.heartbeat[type="info"] .close-icon:not(:hover) {
- -moz-image-region: rect(0, 32px, 32px, 0px) !important;
- }
-}
-%endif
-
-@keyframes pulse-onshow {
- 0% {
- opacity: 0;
- transform: scale(1.0);
- }
- 25% {
- opacity: 1;
- transform: scale(1.1);
- }
- 50% {
- transform: scale(1.0);
- }
- 75% {
- transform: scale(1.1);
- }
- 100% {
- transform: scale(1.0);
- }
-}
-
-@keyframes pulse-twice {
- 0% {
- transform: scale(1.1);
- }
- 50% {
- transform: scale(0.8);
- }
- 100% {
- transform: scale(1);
- }
-}
-
-.messageText.heartbeat {
- color: #333333;
- text-shadow: none;
- margin-inline-start: 0px;
- /* The !important is required to override OSX default style. */
- margin-inline-end: 12px !important;
-}
-
-.messageImage.heartbeat {
- width: 24px;
- height: 24px;
- margin-inline-start: 8px;
- margin-inline-end: 8px;
-}
-
-.messageImage.heartbeat.pulse-onshow {
- animation-name: pulse-onshow;
- animation-duration: 1.5s;
- animation-iteration-count: 1;
- animation-timing-function: cubic-bezier(.7,1.8,.9,1.1);
-}
-
-.messageImage.heartbeat.pulse-twice {
- animation-name: pulse-twice;
- animation-duration: 1s;
- animation-iteration-count: 2;
- animation-timing-function: linear;
-}
-
-/* Learn More link styles */
-.heartbeat > .text-link {
- color: #0095DD;
- margin-inline-start: 0px;
-}
-
-.heartbeat > .text-link:hover {
- color: #008ACB;
- text-decoration: none;
-}
-
-.heartbeat > .text-link:hover:active {
- color: #006B9D;
-}
-
-/* Heartbeat UI Rating Star Classes */
-.heartbeat > #star-rating-container {
- display: -moz-box;
- margin-bottom: 4px;
-}
-
-.heartbeat > #star-rating-container > #star5 {
- -moz-box-ordinal-group: 5;
-}
-
-.heartbeat > #star-rating-container > #star4 {
- -moz-box-ordinal-group: 4;
-}
-
-.heartbeat > #star-rating-container > #star3 {
- -moz-box-ordinal-group: 3;
-}
-
-.heartbeat > #star-rating-container > #star2 {
- -moz-box-ordinal-group: 2;
-}
-
-.heartbeat > #star-rating-container > .star-x {
- background: url("chrome://browser/skin/heartbeat-star-off.svg");
- cursor: pointer;
- /* Overrides the margin-inline-end for all platforms defined in the .plain class */
- margin-inline-end: 4px !important;
- width: 16px;
- height: 16px;
-}
-
-.heartbeat > #star-rating-container > .star-x:hover,
-.heartbeat > #star-rating-container > .star-x:hover ~ .star-x {
- background: url("chrome://browser/skin/heartbeat-star-lit.svg");
-}
diff --git a/browser/themes/shared/customizableui/customizeMode.inc.css b/browser/themes/shared/customizableui/customizeMode.inc.css
index 48681d9f3c..d99933388e 100644
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -457,5 +457,3 @@ toolbarpaletteitem[place="toolbar"]:not([mousedown="true"]):-moz-focusring {
.customization-lwtheme-menu-footeritem:first-child {
border-inline-end: 1px solid var(--panel-separator-color);
}
-
-%include customizeTip.inc.css
diff --git a/browser/themes/shared/customizableui/customizeTip.inc.css b/browser/themes/shared/customizableui/customizeTip.inc.css
deleted file mode 100644
index 26c6ee1ea0..0000000000
--- a/browser/themes/shared/customizableui/customizeTip.inc.css
+++ /dev/null
@@ -1,77 +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/. */
-
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowcontent {
- padding: 0;
- margin: 0;
- min-width: 400px;
- max-width: 1000px;
- min-height: 200px;
- border-radius: 3px;
- background-image: linear-gradient(90deg, #a0dfff 0%, #ceeeff 100%);
- border: 0px solid rgba(0,148,221,.5);
- box-shadow: 0 1px 5px 0 rgba(0,0,0,.5), inset 0 1px 1px 0 #fff;
- color: rgb(51,51,51);
-}
-
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowcontent:-moz-locale-dir(rtl) {
- background-image: linear-gradient(90deg, #ceeeff 0%, #a0dfff 100%);
-}
-
-.customization-tipPanel-infoBox {
- margin: 20px 25px 25px;
- width: 25px;
- background-image: url(chrome://browser/skin/customizableui/info-icon-customizeTip.png);
- background-repeat: no-repeat;
-}
-
-.customization-tipPanel-content {
- margin: 25px 0;
- font-size: 12px;
- line-height: 18px;
-}
-
-.customization-tipPanel-em {
- margin: 0;
- font-weight: bold;
-}
-
-.customization-tipPanel-contentImage {
- margin-top: 25px;
- list-style-image: url(chrome://browser/skin/customizableui/customize-illustration.png);
- min-width: 300px;
- max-width: 300px;
- min-height: 190px;
- max-height: 190px;
- display: -moz-box;
-}
-
-.customization-tipPanel-contentImage:-moz-locale-dir(rtl) {
- list-style-image: url(chrome://browser/skin/customizableui/customize-illustration-rtl.png);
-}
-
-.customization-tipPanel-link {
- -moz-appearance: none;
- background: transparent;
- border: none;
- box-shadow: none;
- color: rgb(25,82,171);
- margin: 0;
- cursor: pointer;
-}
-
-.customization-tipPanel-link > .button-box > .button-text {
- margin: 0 !important;
-}
-
-.customization-tipPanel-closeBox > .close-icon {
- -moz-appearance: none;
- border: 0;
- margin-inline-end: -25px;
-}
-
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="left"],
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="right"] {
- list-style-image: url("chrome://browser/skin/customizableui/panelarrow-customizeTip.png");
-}
diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css
index b364dbc36b..47584a6549 100644
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2328,14 +2328,6 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton {
border-bottom: 1px solid @toolbarShadowColor@;
}
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="left"] {
- margin-right: -2px;
-}
-
-#customization-tipPanel > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="right"] {
- margin-left: -2px;
-}
-
/* End customization mode */
/* Private browsing indicators */
@@ -2422,18 +2414,6 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton {
/* End private browsing indicators */
-%include ../shared/UITour.inc.css
-
-#UITourTooltipButtons {
- /**
- * Override the --arrowpanel-padding so the background extends
- * to the sides and bottom of the panel.
- */
- margin-left: -10px;
- margin-right: -10px;
- margin-bottom: -10px;
-}
-
%include ../shared/contextmenu.inc.css
#context-navigation {
diff --git a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
index ed4d92b4f9..1201ed6923 100644
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/ControlCenter.jsm
@@ -195,7 +195,6 @@ this.ControlCenter = {
trackingProtectionEnabled: {
applyConfig: Task.async(function* () {
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
- Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
yield UrlClassifierTestUtils.addTestTrackers();
yield loadPage(TRACKING_PAGE);
@@ -208,7 +207,6 @@ this.ControlCenter = {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
- Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
yield UrlClassifierTestUtils.addTestTrackers();
yield loadPage(TRACKING_PAGE);
diff --git a/build/autoconf/compiler-opts.m4 b/build/autoconf/compiler-opts.m4
index c47d792f41..82d0b43fc6 100644
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -176,8 +176,8 @@ if test "$GNU_CC"; then
CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
fi
- CFLAGS="$CFLAGS -fno-math-errno"
- CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-math-errno"
+ CFLAGS="$CFLAGS -fno-math-errno -msse2 -mfpmath=sse"
+ CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-math-errno -msse2 -mfpmath=sse"
if test -z "$CLANG_CC"; then
case "$CC_VERSION" in
diff --git a/build/moz.configure/old.configure b/build/moz.configure/old.configure
index c1ad71d5fd..20bde1eee6 100644
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -213,6 +213,7 @@ def old_configure_options(*options):
'--enable-pie',
'--enable-png-arm-neon-support',
'--enable-posix-nspr-emulation',
+ '--enable-precompiled-startupcache',
'--enable-pref-extensions',
'--enable-private-build',
'--enable-pulseaudio',
diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
index b0eabb13d6..4684496985 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -1041,12 +1041,17 @@ nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP)
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
- nsIPrincipal* principal = mDocument->NodePrincipal();
+ nsCOMPtr<nsIPrincipal> principal = mDocument->NodePrincipal();
nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
nsresult rv = principal->EnsurePreloadCSP(domDoc, getter_AddRefs(preloadCsp));
NS_ENSURE_SUCCESS_VOID(rv);
+ if (!preloadCsp) {
+ // XXX: System principals can't preload CSP. We're done here.
+ return;
+ }
+
// please note that meta CSPs and CSPs delivered through a header need
// to be joined together.
rv = preloadCsp->AppendPolicy(aCSP,
diff --git a/python/mozbuild/mozbuild/mach_commands.py b/python/mozbuild/mozbuild/mach_commands.py
index f654db7697..1bd5b8d340 100644
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -541,6 +541,16 @@ class Build(MachCommandBase):
# as when doing OSX Universal builds)
pass
+ # Check if there are any unpreprocessed files in '@MOZ_OBJDIR@/dist/bin'
+ # See python/mozbuild/mozbuild/preprocessor.py#L293-L309 for the list of directives
+ # We skip if, ifdef, ifndef, else, elif, elifdef and elifndef, because they are never used alone
+ grepcmd = 'grep -E -r "^(#|%)(define|endif|error|expand|filter|include|literal|undef|unfilter)" '\
+ + '--include=\*.{css,dtd,html,js,jsm,xhtml,xml,xul,manifest,properties,rdf} '\
+ + self.topobjdir + '/dist/bin | grep -v ".css:#"'
+ grepresult = subprocess.Popen(grepcmd, stdout=subprocess.PIPE, shell=True).communicate()[0]
+ if grepresult:
+ print('\nERROR: preprocessor was not applied to the following files:\n\n' + grepresult)
+
return status
@Command('configure', category='build',
diff --git a/testing/profiles/prefs_general.js b/testing/profiles/prefs_general.js
index d30ae89f5d..515828d298 100644
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -297,10 +297,6 @@ user_pref("browser.aboutHomeSnippets.updateUrl", "nonexistent://test");
user_pref("browser.newtabpage.directory.source", 'data:application/json,{"testing":1}');
user_pref("browser.newtabpage.directory.ping", "");
-// Ensure UITour won't hit the network
-user_pref("browser.uitour.pinnedTabUrl", "http://%(server)s/uitour-dummy/pinnedTab");
-user_pref("browser.uitour.url", "http://%(server)s/uitour-dummy/tour");
-
// Tell the search service we are running in the US. This also has the desired
// side-effect of preventing our geoip lookup.
user_pref("browser.search.isUS", true);
diff --git a/toolkit/components/reader/JSDOMParser.js b/toolkit/components/reader/JSDOMParser.js
index 38f59c4ea4..dd9d372308 100644
--- a/toolkit/components/reader/JSDOMParser.js
+++ b/toolkit/components/reader/JSDOMParser.js
@@ -560,7 +560,8 @@
},
};
- var Document = function () {
+ var Document = function (url) {
+ this.documentURI = url;
this.styleSheets = [];
this.childNodes = [];
this.children = [];
@@ -600,6 +601,20 @@
node.textContent = text;
return node;
},
+
+ get baseURI() {
+ if (!this.hasOwnProperty("_baseURI")) {
+ this._baseURI = this.documentURI;
+ var baseElements = this.getElementsByTagName("base");
+ var href = baseElements[0] && baseElements[0].getAttribute("href");
+ if (href) {
+ try {
+ this._baseURI = (new URL(href, this._baseURI)).href;
+ } catch (ex) {/* Just fall back to documentURI */}
+ }
+ }
+ return this._baseURI;
+ },
};
var Element = function (tag) {
@@ -1118,9 +1133,9 @@
/**
* Parses an HTML string and returns a JS implementation of the Document.
*/
- parse: function (html) {
+ parse: function (html, url) {
this.html = html;
- var doc = this.doc = new Document();
+ var doc = this.doc = new Document(url);
this.readChildren(doc);
// If this is an HTML document, remove root-level children except for the
diff --git a/toolkit/components/reader/Readability.js b/toolkit/components/reader/Readability.js
index 04949dc617..064d2ae88c 100644
--- a/toolkit/components/reader/Readability.js
+++ b/toolkit/components/reader/Readability.js
@@ -41,6 +41,7 @@ function Readability(uri, doc, options) {
this._articleTitle = null;
this._articleByline = null;
this._articleDir = null;
+ this._attempts = [];
// Configurable options
this._debug = !!options.debug;
@@ -275,34 +276,20 @@ Readability.prototype = {
* @return void
*/
_fixRelativeUris: function(articleContent) {
- var scheme = this._uri.scheme;
- var prePath = this._uri.prePath;
- var pathBase = this._uri.pathBase;
-
+ var baseURI = this._doc.baseURI;
+ var documentURI = this._doc.documentURI;
function toAbsoluteURI(uri) {
- // If this is already an absolute URI, return it.
- if (/^[a-zA-Z][a-zA-Z0-9\+\-\.]*:/.test(uri))
- return uri;
-
- // Scheme-rooted relative URI.
- if (uri.substr(0, 2) == "//")
- return scheme + "://" + uri.substr(2);
-
- // Prepath-rooted relative URI.
- if (uri[0] == "/")
- return prePath + uri;
-
- // Dotslash relative URI.
- if (uri.indexOf("./") === 0)
- return pathBase + uri.slice(2);
-
- // Ignore hash URIs:
- if (uri[0] == "#")
+ // Leave hash links alone if the base URI matches the document URI:
+ if (baseURI == documentURI && uri.charAt(0) == "#") {
return uri;
-
- // Standard relative URI; add entire path. pathBase already includes a
- // trailing "/".
- return pathBase + uri;
+ }
+ // Otherwise, resolve against base URI:
+ try {
+ return new URL(uri, baseURI).href;
+ } catch (ex) {
+ // Something went wrong, just return the original:
+ }
+ return uri;
}
var links = articleContent.getElementsByTagName("a");
@@ -535,6 +522,7 @@ Readability.prototype = {
this._clean(articleContent, "embed");
this._clean(articleContent, "h1");
this._clean(articleContent, "footer");
+ this._clean(articleContent, "link");
// Clean out elements have "share" in their id/class combinations from final top candidates,
// which means we don't remove the top candidates even they have "share".
@@ -1089,24 +1077,45 @@ Readability.prototype = {
if (this._debug)
this.log("Article content after paging: " + articleContent.innerHTML);
+ var parseSuccessful = true;
+
// Now that we've gone through the full algorithm, check to see if
// we got any meaningful content. If we didn't, we may need to re-run
// grabArticle with different flags set. This gives us a higher likelihood of
// finding the content, and the sieve approach gives us a higher likelihood of
// finding the -right- content.
- if (this._getInnerText(articleContent, true).length < this._wordThreshold) {
+ var textLength = this._getInnerText(articleContent, true).length;
+ if (textLength < this._wordThreshold) {
+ parseSuccessful = false;
page.innerHTML = pageCacheHtml;
if (this._flagIsActive(this.FLAG_STRIP_UNLIKELYS)) {
this._removeFlag(this.FLAG_STRIP_UNLIKELYS);
+ this._attempts.push({articleContent: articleContent, textLength: textLength});
} else if (this._flagIsActive(this.FLAG_WEIGHT_CLASSES)) {
this._removeFlag(this.FLAG_WEIGHT_CLASSES);
+ this._attempts.push({articleContent: articleContent, textLength: textLength});
} else if (this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)) {
this._removeFlag(this.FLAG_CLEAN_CONDITIONALLY);
+ this._attempts.push({articleContent: articleContent, textLength: textLength});
} else {
- return null;
+ this._attempts.push({articleContent: articleContent, textLength: textLength});
+ // No luck after removing flags, just return the longest text we found during the different loops
+ this._attempts.sort(function (a, b) {
+ return a.textLength < b.textLength;
+ });
+
+ // But first check if we actually have something
+ if (!this._attempts[0].textLength) {
+ return null;
+ }
+
+ articleContent = this._attempts[0].articleContent;
+ parseSuccessful = true;
}
- } else {
+ }
+
+ if (parseSuccessful) {
// Find out text direction from ancestors of final top candidate.
var ancestors = [parentOfTopCandidate, topCandidate].concat(this._getNodeAncestors(parentOfTopCandidate));
this._someNode(ancestors, function(ancestor) {
diff --git a/toolkit/components/reader/ReaderWorker.js b/toolkit/components/reader/ReaderWorker.js
index 9ae589d7d1..69426788ba 100644
--- a/toolkit/components/reader/ReaderWorker.js
+++ b/toolkit/components/reader/ReaderWorker.js
@@ -47,7 +47,7 @@ var Agent = {
* @return {object} Article object returned from Readability.
*/
parseDocument(uri, serializedDoc, options) {
- let doc = new JSDOMParser().parse(serializedDoc);
+ let doc = new JSDOMParser().parse(serializedDoc, uri.spec);
return new Readability(uri, doc, options).parse();
},
};
diff --git a/toolkit/mozapps/installer/packager.py b/toolkit/mozapps/installer/packager.py
index 40f31646ad..1a144823ca 100644
--- a/toolkit/mozapps/installer/packager.py
+++ b/toolkit/mozapps/installer/packager.py
@@ -156,16 +156,15 @@ def precompile_cache(registry, source_path, gre_path, app_path):
extra_env['TSAN_OPTIONS'] = 'report_bugs=0'
if buildconfig.substs.get('MOZ_ASAN'):
extra_env['ASAN_OPTIONS'] = 'detect_leaks=0'
- if buildconfig.substs.get('MOZ_DISABLE_PRECOMPILED_STARTUPCACHE') != '1':
- if launcher.launch(['xpcshell', '-g', gre_path, '-a', app_path,
- '-f', os.path.join(os.path.dirname(__file__),
- 'precompile_cache.js'),
- '-e', 'precompile_startupcache("resource://%s/");'
- % resource],
- extra_linker_path=gre_path,
- extra_env=extra_env):
- errors.fatal('Error while running startup cache precompilation')
- return
+ if launcher.launch(['xpcshell', '-g', gre_path, '-a', app_path,
+ '-f', os.path.join(os.path.dirname(__file__),
+ 'precompile_cache.js'),
+ '-e', 'precompile_startupcache("resource://%s/");'
+ % resource],
+ extra_linker_path=gre_path,
+ extra_env=extra_env):
+ errors.fatal('Error while running startup cache precompilation')
+ return
from mozpack.mozjar import JarReader
jar = JarReader(cache)
resource = '/resource/%s/' % resource
@@ -392,7 +391,8 @@ def main():
# Fill startup cache
if isinstance(formatter, OmniJarFormatter) and launcher.can_launch() \
- and buildconfig.substs['MOZ_DISABLE_STARTUPCACHE'] != '1':
+ and buildconfig.substs['MOZ_DISABLE_STARTUPCACHE'] != '1' \
+ and buildconfig.substs['MOZ_DISABLE_PRECOMPILED_STARTUPCACHE'] != '1':
gre_path = None
def get_bases():
for b in sink.packager.get_bases(addons=False):