The current behavior is that if there is no user pref, it is set to true or false depending on the value of privacy.donottrackheader.enabled, but completely ignoring the global default. This patch changes the behavior such that: - browser.newtabpage.enhanced's default value is set as a global default - it is also set as sticky, so that even when the same value as the default is set, prefHasUserValue is true. - The introduction is not shown when the default for browser.newtabpage.enhanced is false. It is however shown when the pref is flipped for the first time.
247 lines
8.0 KiB
JavaScript
247 lines
8.0 KiB
JavaScript
#ifdef 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
|
|
|
|
const PREF_INTRO_SHOWN = "browser.newtabpage.introShown";
|
|
const PREF_UPDATE_INTRO_SHOWN = "browser.newtabpage.updateIntroShown";
|
|
const PREF_NEWTAB_ENHANCED = "browser.newtabpage.enhanced";
|
|
|
|
// These consts indicate the type of intro/onboarding we show.
|
|
const WELCOME = "welcome";
|
|
const UPDATE = "update";
|
|
|
|
// The maximum paragraph ID listed for 'newtab.intro.paragraph'
|
|
// strings in newTab.properties
|
|
const MAX_PARAGRAPH_ID = 9;
|
|
|
|
const NUM_INTRO_PAGES = 3;
|
|
|
|
let gIntro = {
|
|
_nodeIDSuffixes: [
|
|
"mask",
|
|
"modal",
|
|
"numerical-progress",
|
|
"text",
|
|
"buttons",
|
|
"image",
|
|
"header",
|
|
"footer"
|
|
],
|
|
|
|
_imageTypes: {
|
|
COG : "cog",
|
|
PIN_REMOVE : "pin-remove",
|
|
SUGGESTED : "suggested"
|
|
},
|
|
|
|
|
|
/**
|
|
* The paragraphs & buttons to show on each page in the intros.
|
|
*
|
|
* _introPages.welcome and _introPages.update contain an array of
|
|
* indices of paragraphs to be used to lookup text in _paragraphs
|
|
* for each page of the intro.
|
|
*
|
|
* Similarly, _introPages.buttons is used to lookup text for buttons
|
|
* on each page of the intro.
|
|
*/
|
|
_introPages: {
|
|
"welcome": [[0,1],[2,5],[4,3]],
|
|
"update": [[6,5],[4,3],[0,1]],
|
|
"buttons": [["skip", "continue"],["back", "next"],["back", "gotit"]],
|
|
"welcome-images": ["cog", "suggested", "pin-remove"],
|
|
"update-images": ["suggested", "pin-remove", "cog"]
|
|
},
|
|
|
|
_paragraphs: [],
|
|
|
|
_nodes: {},
|
|
|
|
_images: {},
|
|
|
|
init: function() {
|
|
for (let idSuffix of this._nodeIDSuffixes) {
|
|
this._nodes[idSuffix] = document.getElementById("newtab-intro-" + idSuffix);
|
|
}
|
|
|
|
let brand = Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
|
this._brandShortName = brand.GetStringFromName("brandShortName");
|
|
},
|
|
|
|
_setImage: function(imageType) {
|
|
// Remove previously existing images, if any.
|
|
let currImageHolder = this._nodes.image;
|
|
while (currImageHolder.firstChild) {
|
|
currImageHolder.removeChild(currImageHolder.firstChild);
|
|
}
|
|
|
|
this._nodes.image.appendChild(this._images[imageType]);
|
|
},
|
|
|
|
_goToPage: function(pageNum) {
|
|
this._currPage = pageNum;
|
|
|
|
this._nodes["numerical-progress"].innerHTML = `${this._bold(pageNum + 1)} / ${NUM_INTRO_PAGES}`;
|
|
this._nodes["numerical-progress"].setAttribute("page", pageNum);
|
|
|
|
// Set the page's image
|
|
let imageType = this._introPages[this._onboardingType + "-images"][pageNum];
|
|
this._setImage(imageType);
|
|
|
|
// Set the paragraphs
|
|
let paragraphNodes = this._nodes.text.getElementsByTagName("p");
|
|
let paragraphIDs = this._introPages[this._onboardingType][pageNum];
|
|
paragraphIDs.forEach((arg, index) => {
|
|
paragraphNodes[index].innerHTML = this._paragraphs[arg];
|
|
});
|
|
|
|
// Set the buttons
|
|
let buttonNodes = this._nodes.buttons.getElementsByTagName("input");
|
|
let buttonIDs = this._introPages.buttons[pageNum];
|
|
buttonIDs.forEach((arg, index) => {
|
|
buttonNodes[index].setAttribute("value", newTabString("intro." + arg));
|
|
});
|
|
},
|
|
|
|
_bold: function(str) {
|
|
return `<strong>${str}</strong>`
|
|
},
|
|
|
|
_link: function(url, text) {
|
|
return `<a href="${url}" target="_blank">${text}</a>`;
|
|
},
|
|
|
|
_span: function(text, className) {
|
|
return `<span class="${className}">${text}</span>`;
|
|
},
|
|
|
|
_exitIntro: function() {
|
|
this._nodes.mask.style.opacity = 0;
|
|
this._nodes.mask.addEventListener("transitionend", () => {
|
|
this._nodes.mask.style.display = "none";
|
|
});
|
|
},
|
|
|
|
_back: function() {
|
|
if (this._currPage == 0) {
|
|
// We're on the first page so 'back' means exit.
|
|
this._exitIntro();
|
|
return;
|
|
}
|
|
this._goToPage(this._currPage - 1);
|
|
},
|
|
|
|
_next: function() {
|
|
if (this._currPage == (NUM_INTRO_PAGES - 1)) {
|
|
// We're on the last page so 'next' means exit.
|
|
this._exitIntro();
|
|
return;
|
|
}
|
|
this._goToPage(this._currPage + 1);
|
|
},
|
|
|
|
_generateImages: function() {
|
|
Object.keys(this._imageTypes).forEach(type => {
|
|
let image = "";
|
|
let imageClass = "";
|
|
switch (this._imageTypes[type]) {
|
|
case this._imageTypes.COG:
|
|
// Copy the customize panel's subnodes over so that it can be styled
|
|
// appropriately for the intro.
|
|
image = document.createElementNS(HTML_NAMESPACE, "div");
|
|
image.classList.add("newtab-intro-image-customize");
|
|
let imageToCopy = document.getElementById("newtab-customize-panel").cloneNode(true);
|
|
while (imageToCopy.firstChild) {
|
|
image.appendChild(imageToCopy.firstChild);
|
|
}
|
|
break;
|
|
case this._imageTypes.PIN_REMOVE:
|
|
imageClass = "-hover";
|
|
// fall-through
|
|
case this._imageTypes.SUGGESTED:
|
|
image = document.createElementNS(HTML_NAMESPACE, "div");
|
|
image.classList.add("newtab-intro-cell-wrapper");
|
|
|
|
// Create the cell's inner HTML code.
|
|
image.innerHTML =
|
|
'<div class="newtab-intro-cell' + imageClass + '">' +
|
|
' <div class="newtab-site newtab-intro-image-tile" type="sponsored" suggested="' + (imageClass ? "false" : "true") + '">' +
|
|
' <span class="newtab-sponsored">' +
|
|
newTabString(imageClass ? "sponsored.button" : "suggested.tag") + '</span>' +
|
|
' <a class="newtab-link">' +
|
|
' <span class="newtab-thumbnail"/>' +
|
|
' <span class="newtab-title">mozilla.org</span>' +
|
|
' </a>' +
|
|
' <input type="button" class="newtab-control newtab-control-pin"/>' +
|
|
' <input type="button" class="newtab-control newtab-control-block"/>' +
|
|
' </div>' +
|
|
'</div>';
|
|
break;
|
|
}
|
|
this._images[this._imageTypes[type]] = image;
|
|
});
|
|
},
|
|
|
|
_generateParagraphs: function() {
|
|
let customizeIcon = '<input type="button" class="newtab-control newtab-customize"/>';
|
|
|
|
let substringMappings = {
|
|
"2": [this._link(TILES_PRIVACY_LINK, newTabString("privacy.link"))],
|
|
"4": [customizeIcon, this._bold(newTabString("intro.controls"))],
|
|
"6": [this._bold(newTabString("intro.paragraph6.remove")), this._bold(newTabString("intro.paragraph6.pin"))],
|
|
"7": [this._link(TILES_INTRO_LINK, newTabString("learn.link"))],
|
|
"8": [this._brandShortName, this._link(TILES_INTRO_LINK, newTabString("learn.link"))]
|
|
}
|
|
|
|
for (let i = 1; i <= MAX_PARAGRAPH_ID; i++) {
|
|
try {
|
|
let name = "intro.paragraph" + i + (i == 4 ? ".2" : "");
|
|
this._paragraphs.push(newTabString(name, substringMappings[i]));
|
|
} catch (ex) {
|
|
// Paragraph with this ID doesn't exist so continue
|
|
}
|
|
}
|
|
},
|
|
|
|
showIfNecessary: function() {
|
|
if (!Services.prefs.getBoolPref(PREF_NEWTAB_ENHANCED)) {
|
|
return;
|
|
}
|
|
if (!Services.prefs.getBoolPref(PREF_INTRO_SHOWN)) {
|
|
this._onboardingType = WELCOME;
|
|
this.showPanel();
|
|
} else if (!Services.prefs.getBoolPref(PREF_UPDATE_INTRO_SHOWN)) {
|
|
this._onboardingType = UPDATE;
|
|
this.showPanel();
|
|
}
|
|
Services.prefs.setBoolPref(PREF_INTRO_SHOWN, true);
|
|
Services.prefs.setBoolPref(PREF_UPDATE_INTRO_SHOWN, true);
|
|
},
|
|
|
|
showPanel: function() {
|
|
this._nodes.mask.style.display = "block";
|
|
this._nodes.mask.style.opacity = 1;
|
|
|
|
if (!this._paragraphs.length) {
|
|
// It's our first time showing the panel. Do some initial setup
|
|
this._generateParagraphs();
|
|
this._generateImages();
|
|
}
|
|
this._goToPage(0);
|
|
|
|
// Header text
|
|
let boldSubstr = this._onboardingType == WELCOME ? this._span(this._brandShortName, "bold") : "";
|
|
this._nodes.header.innerHTML = newTabString("intro.header." + this._onboardingType, [boldSubstr]);
|
|
|
|
// Footer links
|
|
let footerLinkNodes = this._nodes.footer.getElementsByTagName("li");
|
|
[this._link(TILES_INTRO_LINK, newTabString("learn.link2")),
|
|
this._link(TILES_PRIVACY_LINK, newTabString("privacy.link2")),
|
|
].forEach((arg, index) => {
|
|
footerLinkNodes[index].innerHTML = arg;
|
|
});
|
|
},
|
|
};
|