403 lines
12 KiB
JavaScript
403 lines
12 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
import {
|
|
actionTypes as at,
|
|
actionCreators as ac,
|
|
} from "resource://newtab/common/Actions.mjs";
|
|
|
|
export const PREFERENCES_LOADED_EVENT = "home-pane-loaded";
|
|
|
|
// These "section" objects are formatted in a way to be similar to the ones from
|
|
// SectionsManager to construct the preferences view.
|
|
const PREFS_FOR_SETTINGS = () => [
|
|
{
|
|
id: "search",
|
|
pref: {
|
|
feed: "showSearch",
|
|
titleString: "home-prefs-search-header",
|
|
},
|
|
},
|
|
{
|
|
id: "weather",
|
|
pref: {
|
|
feed: "showWeather",
|
|
titleString: "home-prefs-weather-header",
|
|
descString: "home-prefs-weather-description",
|
|
learnMore: {
|
|
link: {
|
|
href: "https://support.mozilla.org/kb/customize-items-on-firefox-new-tab-page",
|
|
id: "home-prefs-weather-learn-more-link",
|
|
},
|
|
},
|
|
},
|
|
eventSource: "WEATHER",
|
|
shouldHidePref: !Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.system.showWeather",
|
|
false
|
|
),
|
|
},
|
|
{
|
|
id: "topsites",
|
|
pref: {
|
|
feed: "feeds.topsites",
|
|
titleString: "home-prefs-shortcuts-header",
|
|
descString: "home-prefs-shortcuts-description",
|
|
nestedPrefs: [
|
|
{
|
|
name: "showSponsoredTopSites",
|
|
titleString: "home-prefs-shortcuts-by-option-sponsored",
|
|
eventSource: "SPONSORED_TOP_SITES",
|
|
// Hide this nested pref if "Support Firefox" checkbox is enabled
|
|
shouldHidePref: Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.system.showSponsoredCheckboxes",
|
|
false
|
|
),
|
|
},
|
|
],
|
|
},
|
|
maxRows: 4,
|
|
rowsPref: "topSitesRows",
|
|
eventSource: "TOP_SITES",
|
|
},
|
|
{
|
|
id: "topstories",
|
|
pref: {
|
|
feed: "feeds.section.topstories",
|
|
titleString: {
|
|
id: "home-prefs-recommended-by-header-generic",
|
|
},
|
|
descString: {
|
|
id: "home-prefs-recommended-by-description-generic",
|
|
},
|
|
nestedPrefs: [
|
|
...(Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.system.showSponsored",
|
|
true
|
|
) && // Hide this nested pref if "Support Firefox" checkbox is enabled
|
|
!Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.system.showSponsoredCheckboxes",
|
|
false
|
|
)
|
|
? [
|
|
{
|
|
name: "showSponsored",
|
|
titleString:
|
|
"home-prefs-recommended-by-option-sponsored-stories",
|
|
icon: "icon-info",
|
|
eventSource: "POCKET_SPOCS",
|
|
},
|
|
]
|
|
: []),
|
|
],
|
|
},
|
|
shouldHidePref: !Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.feeds.system.topstories",
|
|
true
|
|
),
|
|
eventSource: "TOP_STORIES",
|
|
},
|
|
{
|
|
id: "support-firefox",
|
|
pref: {
|
|
feed: "showSponsoredCheckboxes",
|
|
titleString: "home-prefs-support-firefox-header",
|
|
nestedPrefs: [
|
|
{
|
|
name: "showSponsoredTopSites",
|
|
titleString: "home-prefs-shortcuts-by-option-sponsored",
|
|
eventSource: "SPONSORED_TOP_SITES",
|
|
},
|
|
{
|
|
name: "showSponsored",
|
|
titleString: "home-prefs-recommended-by-option-sponsored-stories",
|
|
eventSource: "POCKET_SPOCS",
|
|
shouldHidePref: !Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.feeds.system.topstories",
|
|
true
|
|
),
|
|
shouldDisablePref: !Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.feeds.section.topstories",
|
|
true
|
|
),
|
|
},
|
|
],
|
|
},
|
|
shouldHidePref: !Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.system.showSponsoredCheckboxes",
|
|
false
|
|
),
|
|
},
|
|
];
|
|
|
|
export class AboutPreferences {
|
|
init() {
|
|
Services.obs.addObserver(this, PREFERENCES_LOADED_EVENT);
|
|
}
|
|
|
|
uninit() {
|
|
Services.obs.removeObserver(this, PREFERENCES_LOADED_EVENT);
|
|
}
|
|
|
|
onAction(action) {
|
|
switch (action.type) {
|
|
case at.INIT:
|
|
this.init();
|
|
break;
|
|
case at.UNINIT:
|
|
this.uninit();
|
|
break;
|
|
case at.SETTINGS_OPEN:
|
|
action._target.browser.ownerGlobal.openPreferences("paneHome");
|
|
break;
|
|
// This is used to open the web extension settings page for an extension
|
|
case at.OPEN_WEBEXT_SETTINGS:
|
|
action._target.browser.ownerGlobal.BrowserAddonUI.openAddonsMgr(
|
|
`addons://detail/${encodeURIComponent(action.data)}`
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
setupUserEvent(element, eventSource) {
|
|
element.addEventListener("command", e => {
|
|
const { checked } = e.target;
|
|
if (typeof checked === "boolean") {
|
|
this.store.dispatch(
|
|
ac.UserEvent({
|
|
event: "PREF_CHANGED",
|
|
source: eventSource,
|
|
value: { status: checked, menu_source: "ABOUT_PREFERENCES" },
|
|
})
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
observe(window) {
|
|
const { document, Preferences } = window;
|
|
|
|
// Extract just the "Recent activity" pref info from SectionsManager as we have everything else already
|
|
const highlights = this.store
|
|
.getState()
|
|
.Sections.find(el => el.id === "highlights");
|
|
|
|
const allSections = [...PREFS_FOR_SETTINGS(), highlights];
|
|
|
|
// Render the preferences
|
|
allSections.forEach(pref => {
|
|
this.renderPreferenceSection(pref, document, Preferences);
|
|
});
|
|
|
|
// Update the visibility of the Restore Defaults button based on checked prefs
|
|
this.toggleRestoreDefaults(window.gHomePane);
|
|
}
|
|
|
|
/**
|
|
* Render a single preference with all the details, e.g. description, links,
|
|
* more granular preferences.
|
|
*
|
|
* @param sectionData
|
|
* @param document
|
|
* @param Preferences
|
|
*/
|
|
renderPreferenceSection(sectionData, document, Preferences) {
|
|
const {
|
|
id,
|
|
pref: prefData,
|
|
maxRows,
|
|
rowsPref,
|
|
shouldHidePref,
|
|
eventSource,
|
|
} = sectionData;
|
|
const {
|
|
feed: name,
|
|
titleString = {},
|
|
descString,
|
|
nestedPrefs = [],
|
|
} = prefData || {};
|
|
|
|
// Helper to link a UI element to a preference for updating
|
|
const linkPref = (element, prefName, type) => {
|
|
const fullPref = `browser.newtabpage.activity-stream.${prefName}`;
|
|
element.setAttribute("preference", fullPref);
|
|
Preferences.add({ id: fullPref, type });
|
|
|
|
// Prevent changing the UI if the preference can't be changed
|
|
element.disabled = Preferences.get(fullPref).locked;
|
|
};
|
|
|
|
// Don't show any sections that we don't want to expose in preferences UI
|
|
if (shouldHidePref) {
|
|
return;
|
|
}
|
|
|
|
// Add the main preference for turning on/off a section
|
|
const sectionVbox = document.getElementById(id);
|
|
sectionVbox.setAttribute("data-subcategory", id);
|
|
const checkbox = this.createAppend(document, "checkbox", sectionVbox);
|
|
checkbox.classList.add("section-checkbox");
|
|
// Set up a user event if we have an event source for this pref.
|
|
if (eventSource) {
|
|
this.setupUserEvent(checkbox, eventSource);
|
|
}
|
|
document.l10n.setAttributes(
|
|
checkbox,
|
|
this.getString(titleString),
|
|
titleString.values
|
|
);
|
|
|
|
linkPref(checkbox, name, "bool");
|
|
|
|
// Specially add a link for Weather
|
|
if (id === "weather") {
|
|
const hboxWithLink = this.createAppend(document, "hbox", sectionVbox);
|
|
hboxWithLink.appendChild(checkbox);
|
|
checkbox.classList.add("tail-with-learn-more");
|
|
|
|
const link = this.createAppend(document, "label", hboxWithLink, {
|
|
is: "text-link",
|
|
});
|
|
link.setAttribute("href", sectionData.pref.learnMore.link.href);
|
|
document.l10n.setAttributes(link, sectionData.pref.learnMore.link.id);
|
|
}
|
|
|
|
// Add more details for the section (e.g., description, more prefs)
|
|
const detailVbox = this.createAppend(document, "vbox", sectionVbox);
|
|
detailVbox.classList.add("indent");
|
|
if (descString) {
|
|
const description = this.createAppend(
|
|
document,
|
|
"description",
|
|
detailVbox
|
|
);
|
|
description.classList.add("text-deemphasized");
|
|
document.l10n.setAttributes(
|
|
description,
|
|
this.getString(descString),
|
|
descString.values
|
|
);
|
|
|
|
// Add a rows dropdown if we have a pref to control and a maximum
|
|
if (rowsPref && maxRows) {
|
|
const detailHbox = this.createAppend(document, "hbox", detailVbox);
|
|
detailHbox.setAttribute("align", "center");
|
|
description.setAttribute("flex", 1);
|
|
detailHbox.appendChild(description);
|
|
|
|
// Add box so the search tooltip is positioned correctly
|
|
const tooltipBox = this.createAppend(document, "hbox", detailHbox);
|
|
|
|
// Add appropriate number of localized entries to the dropdown
|
|
const menulist = this.createAppend(document, "menulist", tooltipBox);
|
|
menulist.setAttribute("crop", "none");
|
|
const menupopup = this.createAppend(document, "menupopup", menulist);
|
|
for (let num = 1; num <= maxRows; num++) {
|
|
const item = this.createAppend(document, "menuitem", menupopup);
|
|
document.l10n.setAttributes(item, "home-prefs-sections-rows-option", {
|
|
num,
|
|
});
|
|
item.setAttribute("value", num);
|
|
}
|
|
linkPref(menulist, rowsPref, "int");
|
|
}
|
|
}
|
|
|
|
const subChecks = [];
|
|
const fullName = `browser.newtabpage.activity-stream.${sectionData.pref.feed}`;
|
|
const pref = Preferences.get(fullName);
|
|
|
|
// Add a checkbox pref for any nested preferences
|
|
nestedPrefs.forEach(nested => {
|
|
if (nested.shouldHidePref !== true) {
|
|
const subcheck = this.createAppend(document, "checkbox", detailVbox);
|
|
// Set up a user event if we have an event source for this pref.
|
|
if (nested.eventSource) {
|
|
this.setupUserEvent(subcheck, nested.eventSource);
|
|
}
|
|
document.l10n.setAttributes(subcheck, nested.titleString);
|
|
|
|
linkPref(subcheck, nested.name, "bool");
|
|
|
|
subChecks.push(subcheck);
|
|
subcheck.disabled = !pref._value;
|
|
if (nested.shouldDisablePref) {
|
|
subcheck.disabled = nested.shouldDisablePref;
|
|
}
|
|
subcheck.hidden = nested.hidden;
|
|
}
|
|
});
|
|
|
|
// Special cases to like the nested prefs with another pref,
|
|
// so we can disable it real time.
|
|
if (id === "support-firefox") {
|
|
function setupSupportFirefoxSubCheck(triggerPref, subPref) {
|
|
const subCheckFullName = `browser.newtabpage.activity-stream.${triggerPref}`;
|
|
const subCheckPref = Preferences.get(subCheckFullName);
|
|
|
|
subCheckPref?.on("change", () => {
|
|
const showSponsoredFullName = `browser.newtabpage.activity-stream.${subPref}`;
|
|
const showSponsoredSubcheck = subChecks.find(
|
|
subcheck =>
|
|
subcheck.getAttribute("preference") === showSponsoredFullName
|
|
);
|
|
if (showSponsoredSubcheck) {
|
|
showSponsoredSubcheck.disabled = !Services.prefs.getBoolPref(
|
|
subCheckFullName,
|
|
true
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
setupSupportFirefoxSubCheck("feeds.section.topstories", "showSponsored");
|
|
setupSupportFirefoxSubCheck("feeds.topsites", "showSponsoredTopSites");
|
|
}
|
|
|
|
pref.on("change", () => {
|
|
subChecks.forEach(subcheck => {
|
|
// Update child preferences for the "Support Firefox" checkbox group
|
|
// so that they're turned on and off at the same time.
|
|
if (id === "support-firefox") {
|
|
const subPref = Preferences.get(subcheck.getAttribute("preference"));
|
|
subPref.value = pref.value;
|
|
}
|
|
|
|
// Disable any nested checkboxes if the parent pref is not enabled.
|
|
subcheck.disabled = !pref._value;
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update the visibility of the Restore Defaults button based on checked prefs.
|
|
*
|
|
* @param gHomePane
|
|
*/
|
|
toggleRestoreDefaults(gHomePane) {
|
|
gHomePane.toggleRestoreDefaultsBtn();
|
|
}
|
|
|
|
/**
|
|
* A helper function to append XUL elements on the page.
|
|
*
|
|
* @param document
|
|
* @param tag
|
|
* @param parent
|
|
* @param options
|
|
*/
|
|
createAppend(document, tag, parent, options = {}) {
|
|
return parent.appendChild(document.createXULElement(tag, options));
|
|
}
|
|
|
|
/**
|
|
* Helper to get fluentIDs sometimes encase in an object
|
|
*
|
|
* @param message
|
|
* @returns string
|
|
*/
|
|
getString(message) {
|
|
return typeof message !== "object" ? message : message.id;
|
|
}
|
|
}
|