344 lines
12 KiB
JavaScript
344 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/. */
|
|
|
|
// Based on the original onboarding code with deep changes from Ruben Rodriguez
|
|
// Copyright (C) 2018 Ruben Rodriguez <ruben@gnu.org>
|
|
|
|
/* eslint-env mozilla/frame-script */
|
|
|
|
"use strict";
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
const ABOUT_HOME_URL = "about:home";
|
|
const ABOUT_NEWTAB_URL = "about:newtab";
|
|
|
|
/**
|
|
* @param {String} action the action to ask the chrome to do
|
|
* @param {Array | Object} params the parameters for the action
|
|
*/
|
|
function sendMessageToChrome(action, params) {
|
|
sendAsyncMessage("Onboarding:OnContentMessage", {
|
|
action, params
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* The script won't be initialized if we turned off onboarding by
|
|
* setting "browser.onboarding.enabled" to false.
|
|
*/
|
|
class Onboarding {
|
|
constructor(contentWindow) {
|
|
this.init(contentWindow);
|
|
|
|
this._bundle = Services.strings.createBundle("chrome://onboarding/locale/onboarding.properties");
|
|
|
|
this.keylist = {
|
|
"javascript.enabled": {
|
|
type: "boolean",
|
|
name: "javascript.enabled",
|
|
label: this._bundle.GetStringFromName("onboarding.disable-javascript.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.disable-javascript.description"),
|
|
defaultvalue: true,
|
|
onvalue: false,
|
|
offvalue: true,
|
|
},
|
|
"browser.display.use_document_fonts": {
|
|
type: "integer",
|
|
name: "browser.display.use_document_fonts",
|
|
label: this._bundle.GetStringFromName("onboarding.custom-fonts.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.custom-fonts.description"),
|
|
defaultvalue: 1,
|
|
onvalue: 0,
|
|
offvalue: 1,
|
|
},
|
|
"browser.safebrowsing.provider.mozilla.updateURL": {
|
|
type: "string",
|
|
name: "browser.safebrowsing.provider.mozilla.updateURL",
|
|
label: this._bundle.GetStringFromName("onboarding.tracking-protection.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.tracking-protection.description"),
|
|
defaultvalue: "",
|
|
onvalue: "https://shavar.services.mozilla.com/downloads?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2",
|
|
offvalue: "",
|
|
},
|
|
"privacy.firstparty.isolate": {
|
|
type: "boolean",
|
|
name: "privacy.firstparty.isolate",
|
|
label: this._bundle.GetStringFromName("onboarding.isolate-request-first-party.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.isolate-request-first-party.description"),
|
|
defaultvalue: false,
|
|
onvalue: true,
|
|
offvalue: false,
|
|
},
|
|
"extensions.update.enabled": {
|
|
type: "boolean",
|
|
name: "extensions.update.enabled",
|
|
label: this._bundle.GetStringFromName("onboarding.auto-update-extensions.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.auto-update-extensions.description"),
|
|
defaultvalue: false,
|
|
onvalue: true,
|
|
offvalue: false,
|
|
},
|
|
"network.http.referer.spoofSource": {
|
|
type: "boolean",
|
|
name: "network.http.referer.spoofSource",
|
|
label: this._bundle.GetStringFromName("onboarding.spoof-referers.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.spoof-referers.description"),
|
|
defaultvalue: true,
|
|
onvalue: true,
|
|
offvalue: false,
|
|
},
|
|
"captivedetect.canonicalURL": {
|
|
type: "string",
|
|
name: "captivedetect.canonicalURL",
|
|
label: this._bundle.GetStringFromName("onboarding.detect-captative-portal.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.detect-captative-portal.description"),
|
|
defaultvalue: "",
|
|
onvalue: "http://detectportal.firefox.com/success.txt",
|
|
offvalue: "",
|
|
},
|
|
"browser.search.geoip.url": {
|
|
type: "string",
|
|
name: "browser.search.geoip.url",
|
|
label: this._bundle.GetStringFromName("onboarding.geolocation.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.geolocation.description"),
|
|
defaultvalue: "",
|
|
onvalue: "https://location.services.mozilla.com/v1/country?key=%MOZILLA_API_KEY%",
|
|
offvalue: ""
|
|
},
|
|
|
|
"webgl.disabled": {
|
|
type: "boolean",
|
|
name: "webgl.disabled",
|
|
label: this._bundle.GetStringFromName("onboarding.webgl.title"),
|
|
description: this._bundle.GetStringFromName("onboarding.webgl.description"),
|
|
defaultvalue: true,
|
|
onvalue: false,
|
|
offvalue: true
|
|
}
|
|
}
|
|
}
|
|
|
|
async init(contentWindow) {
|
|
this._window = contentWindow;
|
|
|
|
// Destroy on unloading. This is to ensure we remove all the stuff we left.
|
|
// No any leak out there.
|
|
this._window.addEventListener("unload", () => this.destroy());
|
|
|
|
this.uiInitialized = false;
|
|
this._window.requestIdleCallback(() => this._initUI());
|
|
}
|
|
|
|
getPref(type, key, def){
|
|
switch (type){
|
|
case "integer":
|
|
return Services.prefs.getIntPref(key, def);
|
|
break;
|
|
case "string":
|
|
return Services.prefs.getStringPref(key, def);
|
|
break;
|
|
case "boolean":
|
|
return Services.prefs.getBoolPref(key, def);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_callback(id, val){
|
|
this._window.document.getElementById(id).checked= (val==this.keylist[id].onvalue);
|
|
}
|
|
|
|
newcheckbox(kind, type, name, label, description, defaultvalue, onvalue, offvalue){
|
|
let content = this._window.document.createElement("div");
|
|
content.style="border-top: 1px solid #DDDDDD; padding-top:10px";
|
|
if (kind == "addon")
|
|
sendMessageToChrome("check-addon", [{
|
|
name: name,
|
|
}]);
|
|
else
|
|
Services.prefs.addObserver(name, () => {this._callback(name, this.getPref(type, name, defaultvalue));});
|
|
content.appendChild(this._window.document.createElement("input"));
|
|
content.appendChild(this._window.document.createElement("label"));
|
|
content.appendChild(this._window.document.createElement("p"));
|
|
content.children[0].id=name;
|
|
content.children[0].name=name;
|
|
content.children[0].className=kind;
|
|
content.children[0].type="checkbox";
|
|
content.children[0].style="position:relative; top:2px;";
|
|
content.children[0].checked=this.getPref(type, name, defaultvalue)==onvalue;
|
|
content.children[0].addEventListener("click", this);
|
|
content.children[0].addEventListener("keypress", this);
|
|
content.children[1].for=name;
|
|
content.children[1].innerHTML=label;
|
|
content.children[1].style="font-size:15px";
|
|
if (description != ""){
|
|
content.children[2].innerHTML=description;
|
|
content.children[2].style="padding-left:35px; font-size: small; color:#999; margin-top:5px";
|
|
}
|
|
|
|
return content;
|
|
}
|
|
|
|
_initUI() {
|
|
if (this.uiInitialized) {
|
|
return;
|
|
}
|
|
this.uiInitialized = true;
|
|
|
|
let { body } = this._window.document;
|
|
|
|
let main = this._window.document.getElementsByTagName("main")[0];
|
|
let settingsblock = this._window.document.createElement("div");
|
|
settingsblock.style=`border:1px solid #D7D7DB;
|
|
border-radius:3px;
|
|
margin-bottom:40px;
|
|
padding:0 15px 10px 15px;
|
|
color:#4A4A4F;
|
|
`;
|
|
let title = this._window.document.createElement("div");
|
|
title.innerHTML=`<h2 style="margin:10px 0 5px; font-size:20px">` + this._bundle.GetStringFromName("onboarding.privacy-settings.title") + `</h2> <p style="font-size:14px">` + this._bundle.GetStringFromName("onboarding.privacy-settings.description") + `</p>`;
|
|
main.insertBefore(settingsblock, main.childNodes[0]);
|
|
settingsblock.appendChild(title);
|
|
|
|
for ( var key in this.keylist){
|
|
key = this.keylist[key];
|
|
settingsblock.appendChild(this.newcheckbox("key", key.type, key.name, key.label, key.description, key.defaultvalue, key.onvalue, key.offvalue));
|
|
}
|
|
settingsblock.appendChild(this.newcheckbox("addon", null, "uBlock0@raymondhill.net", "uBlock Origin", "Block ads and other intrusing trackers."));
|
|
settingsblock.appendChild(this.newcheckbox("addon", null, "jid1-KtlZuoiikVfFew@jetpack", "GNU LibreJs", "Block nonfree <a href=\"https://www.gnu.org/software/librejs/\">JavaScript</a>."));
|
|
|
|
}
|
|
|
|
_clearPrefObserver() {
|
|
for ( var key in this.keylist){
|
|
key = this.keylist[key];
|
|
Services.prefs.removeObserver(key.name, () => {this._callbacktest(key.name, this.getPref(key.type, key.name, key.defaultvalue));});
|
|
}
|
|
}
|
|
|
|
handleClick(target) {
|
|
switch (target.className){
|
|
case "addon":
|
|
sendMessageToChrome("flip-addon", [{
|
|
name: target.name
|
|
}]);
|
|
return;
|
|
break;
|
|
case "key":
|
|
let value
|
|
if (target.checked)
|
|
value = this.keylist[target.name].onvalue
|
|
else
|
|
value = this.keylist[target.name].offvalue
|
|
if (target.name == "captivedetect.canonicalURL" && value != "")
|
|
this._window.alert("You need to restart the browser to apply this change.\n\nWhen this feature is enabled the browser will automatically\ntry to connect to detectportal.firefox.com at the beginning of each browsing session.");
|
|
sendMessageToChrome("set-prefs", [{
|
|
type: this.keylist[target.name].type,
|
|
name: target.name,
|
|
value: value
|
|
}]);
|
|
return;
|
|
break
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wrap keyboard focus within the dialog.
|
|
* When moving forward, focus on the first element when the current focused
|
|
* element is the last one.
|
|
* When moving backward, focus on the last element when the current focused
|
|
* element is the first one.
|
|
* Do nothing if focus is moving in the middle of the list of dialog's focusable
|
|
* elements.
|
|
*
|
|
* @param {DOMNode} current currently focused element
|
|
* @param {Boolean} back direction
|
|
* @return {DOMNode} newly focused element if any
|
|
*/
|
|
wrapMoveFocus(current, back) {
|
|
let elms = [...this._dialog.querySelectorAll(
|
|
`button, input[type="checkbox"], input[type="email"], [tabindex="0"]`)];
|
|
let next;
|
|
if (back) {
|
|
if (elms.indexOf(current) === 0) {
|
|
next = elms[elms.length - 1];
|
|
next.focus();
|
|
}
|
|
} else if (elms.indexOf(current) === elms.length - 1) {
|
|
next = elms[0];
|
|
next.focus();
|
|
}
|
|
return next;
|
|
}
|
|
|
|
handleKeypress(event) {
|
|
let { target, key, shiftKey } = event;
|
|
if ([" ", "Enter"].includes(key)) {
|
|
this.handleClick(target);
|
|
event.preventDefault();
|
|
}
|
|
return;
|
|
}
|
|
|
|
handleEvent(evt) {
|
|
switch (evt.type) {
|
|
case "keypress":
|
|
this.handleKeypress(evt);
|
|
break;
|
|
case "click":
|
|
this.handleClick(evt.target);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
if (!this.uiInitialized) {
|
|
return;
|
|
}
|
|
this.uiInitialized = false;
|
|
|
|
this._clearPrefObserver();
|
|
}
|
|
}
|
|
|
|
addEventListener("load", function onLoad(evt) {
|
|
if (!content || evt.target != content.document) {
|
|
return;
|
|
}
|
|
|
|
var window = evt.target.defaultView;
|
|
|
|
// Set the checked value of addons
|
|
function handleMessageFromChrome(message) {
|
|
if (! window) return;
|
|
var payload = message.data;
|
|
var cb = window.document.getElementById(payload.id);
|
|
if (cb == null) return;
|
|
cb.checked=payload.active;
|
|
cb.parentNode.hidden = ! payload.installed;
|
|
}
|
|
|
|
function needsrestart(){
|
|
window.alert("This change will be applied when you restart the browser");
|
|
}
|
|
addMessageListener("Onboarding:message-from-chrome", handleMessageFromChrome);
|
|
addMessageListener("Onboarding:needsrestart", needsrestart);
|
|
|
|
let location = window.location.href;
|
|
if (location == ABOUT_NEWTAB_URL || location == ABOUT_HOME_URL) {
|
|
// We just want to run tests as quickly as possible
|
|
// so in the automation test, we don't do `requestIdleCallback`.
|
|
if (Cu.isInAutomation) {
|
|
new Onboarding(window);
|
|
return;
|
|
}
|
|
window.requestIdleCallback(() => {
|
|
new Onboarding(window);
|
|
});
|
|
}
|
|
}, true);
|