Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
532 lines
17 KiB
JavaScript
Executable file
532 lines
17 KiB
JavaScript
Executable file
/* global DataMobile, SimManager, IccHelper,
|
|
SdManager, UIManager, WifiManager, WifiUI,
|
|
ImportIntegration,
|
|
OperatorVariant */
|
|
/* exported Navigation */
|
|
(function(exports) {
|
|
'use strict';
|
|
|
|
const DOGFOODSETTING = 'debug.performance_data.dogfooding';
|
|
const METRICSSETTING = 'metrics.selectedMetrics.level';
|
|
|
|
/*
|
|
Steps of the First Time Usage App
|
|
*/
|
|
var steps = [
|
|
{
|
|
onlyForward: true,
|
|
hash: '#languages',
|
|
requireSIM: false
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#data_3g',
|
|
requireSIM: true
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#wifi',
|
|
requireSIM: false
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#date_and_time',
|
|
requireSIM: false
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#geolocation',
|
|
requireSIM: false
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#import_contacts',
|
|
requireSIM: false
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#firefox_accounts',
|
|
requireSIM: false
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#welcome_browser',
|
|
requireSIM: false
|
|
},
|
|
{
|
|
onlyForward: false,
|
|
hash: '#browser_privacy',
|
|
requireSIM: false
|
|
}
|
|
];
|
|
|
|
exports.Navigation = {
|
|
get stepCount() {
|
|
return this._stepOrder ? this._stepOrder.length : 0;
|
|
},
|
|
currentStepIndex: 0,
|
|
previousStepIndex: 0,
|
|
simMandatory: false,
|
|
skipMobileDataScreen: false,
|
|
skipDateTimeScreen: false,
|
|
tzInitialized: false,
|
|
|
|
_stepsById: null,
|
|
_stepOrder: null,
|
|
|
|
init: function n_init() {
|
|
this._stepOrder = [];
|
|
this._stepsById = {};
|
|
|
|
var settings = navigator.mozSettings;
|
|
var forward = document.getElementById('forward');
|
|
var back = document.getElementById('back');
|
|
this._onForwardClick = this.forward.bind(this);
|
|
this._onBackClick = this.back.bind(this);
|
|
forward.addEventListener('click', this._onForwardClick);
|
|
back.addEventListener('click', this._onBackClick);
|
|
window.addEventListener('hashchange', this);
|
|
this._onActivationScreenClick = this.handleExternalLinksClick.bind(this);
|
|
UIManager.activationScreen.addEventListener('click',
|
|
this._onActivationScreenClick);
|
|
|
|
// register pre-defined steps in the oder they appear
|
|
steps.forEach(step => {
|
|
this.registerStep(step);
|
|
});
|
|
|
|
var self = this;
|
|
|
|
var reqSIM =
|
|
settings && settings.createLock().get('ftu.sim.mandatory') || {};
|
|
reqSIM.onsuccess = function onSuccess() {
|
|
self.simMandatory = reqSIM.result['ftu.sim.mandatory'] || false;
|
|
};
|
|
|
|
navigator.mozApps.getSelf().onsuccess = function(evt) {
|
|
var app = evt.target.result;
|
|
app.connect('ftucomms').then(function onConnAccepted(ports) {
|
|
self.ports = ports;
|
|
ports.forEach(port => port.postMessage('started'));
|
|
}, function onConnRejected(reason) {
|
|
console.warn('FTU navigation cannot use IAC: ' + reason);
|
|
});
|
|
};
|
|
},
|
|
|
|
uninit: function() {
|
|
this._stepOrder = null;
|
|
this._stepsById = null;
|
|
this.currentStepIndex = 0;
|
|
this.previousStepIndex = 0;
|
|
this.ports = null;
|
|
|
|
var forward = document.getElementById('forward');
|
|
var back = document.getElementById('back');
|
|
var activationScreen = UIManager && UIManager.activationScreen;
|
|
|
|
if (forward && this._onForwardClick) {
|
|
forward.removeEventListener('click', this._onForwardClick);
|
|
}
|
|
if (back && this._onBackClick) {
|
|
back.removeEventListener('click', this._onBackClick);
|
|
}
|
|
if (activationScreen && this._onActivationScreenClick) {
|
|
activationScreen.removeEventListener('click',
|
|
this._onActivationScreenClick);
|
|
}
|
|
window.removeEventListener('hashchange', this);
|
|
},
|
|
|
|
registerStep: function(step) {
|
|
if (!step.id) {
|
|
step.id = step.hash.substring(1); // strip off '#' to make an id;
|
|
}
|
|
var id = step.id;
|
|
this._stepsById[id] = step;
|
|
var beforeStepIdx = step.hasOwnProperty('beforeStep') ?
|
|
this._stepOrder.indexOf(step.beforeStep) : -1;
|
|
var afterStepIdx = step.hasOwnProperty('afterStep') ?
|
|
this._stepOrder.indexOf(step.afterStep) : -1;
|
|
|
|
if (beforeStepIdx > -1) {
|
|
this._stepOrder.splice(beforeStepIdx, 0, id);
|
|
} else if (afterStepIdx > -1) {
|
|
this._stepOrder.splice(afterStepIdx+1, 0, id);
|
|
} else {
|
|
this._stepOrder.push(id);
|
|
}
|
|
},
|
|
|
|
stepAt: function(idx) {
|
|
var stepId = this._stepOrder[idx];
|
|
if (stepId) {
|
|
return this._stepsById[stepId];
|
|
}
|
|
},
|
|
indexOfStep: function(step) {
|
|
var id = (typeof id === 'string') ? step.id : step;
|
|
return this._stepOrder.indexOf(id);
|
|
},
|
|
|
|
back: function n_back(event) {
|
|
var currentStep = this.stepAt(this.currentStepIndex);
|
|
var actualHash = window.location.hash;
|
|
if (actualHash != currentStep.hash) {
|
|
window.history.back();
|
|
} else {
|
|
var self = this;
|
|
var goToStep = function() {
|
|
self.previousStepIndex = self.currentStepIndex;
|
|
self.currentStepIndex--;
|
|
if (self.currentStepIndex >= 0) {
|
|
self.manageStep();
|
|
}
|
|
};
|
|
goToStep();
|
|
}
|
|
},
|
|
|
|
forward: function n_forward(event) {
|
|
var self = this;
|
|
var goToStepForward = function() {
|
|
self.previousStepIndex = self.currentStepIndex;
|
|
self.currentStepIndex++;
|
|
if (self.currentStepIndex >= self.stepCount) {
|
|
// Try to send Newsletter here
|
|
UIManager.sendNewsletter(function newsletterSent(result) {
|
|
if (result) { // sending process ok, we advance
|
|
UIManager.activationScreen.classList.remove('show');
|
|
UIManager.changeStatusBarColor(UIManager.DARK_THEME);
|
|
UIManager.finishScreen.classList.add('show');
|
|
UIManager.hideActivationScreenFromScreenReader();
|
|
} else { // error on sending, we stay where we are
|
|
self.currentStepIndex--;
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
self.manageStep();
|
|
};
|
|
goToStepForward();
|
|
},
|
|
|
|
handleExternalLinksClick: function n_handleExternalLinksClick(e) {
|
|
var link = e.target;
|
|
if (! link.mozMatchesSelector('a.external')) {
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
var href = link.href,
|
|
title = link.getAttribute('title') || link.textContent;
|
|
|
|
if (navigator.onLine) {
|
|
this.displayExternalLink(href, title);
|
|
} else {
|
|
UIManager.displayOfflineDialog(href, title);
|
|
}
|
|
},
|
|
|
|
displayExternalLink: function n_displayExternalLink(href, title) {
|
|
window.open(href, '', 'dialog');
|
|
},
|
|
|
|
ensureTZInitialized: function () {
|
|
if (!this.tzInitialized) {
|
|
return UIManager.initTZ().then(() => {
|
|
this.skipDateTimeScreen = !UIManager.timeZoneNeedsConfirmation;
|
|
this.tzInitialized = true;
|
|
});
|
|
} else {
|
|
return Promise.resolve();
|
|
}
|
|
},
|
|
|
|
handleEvent: function n_handleEvent(event) {
|
|
var actualHash = window.location.hash;
|
|
switch (actualHash) {
|
|
case '#languages':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'language');
|
|
break;
|
|
case '#data_3g':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', '3g');
|
|
DataMobile.
|
|
getStatus(UIManager.updateDataConnectionStatus.bind(UIManager));
|
|
break;
|
|
case '#wifi':
|
|
DataMobile.removeSVStatusObserver();
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'selectNetwork');
|
|
UIManager.activationScreen.classList.remove('no-options');
|
|
if (UIManager.navBar.classList.contains('secondary-menu')) {
|
|
UIManager.navBar.classList.remove('secondary-menu');
|
|
return;
|
|
}
|
|
|
|
// This might seem like an odd place to call UIManager.initTZ, but
|
|
// there's a reason for it. initTZ tries to determine the timezone
|
|
// using information about the current mobile network connection.
|
|
// We want to call initTZ as late as possible to give the mobile
|
|
// network time to connect before the function is called.
|
|
// But we have to call initTZ *before* the Date & Time page
|
|
// appears so that it doesn't delay the appearance of the page.
|
|
// This is the last good opportunity to call it.
|
|
|
|
WifiManager.getNetworks(networks => {
|
|
this.ensureTZInitialized().then(() => {
|
|
WifiUI.renderNetworks(networks);
|
|
});
|
|
});
|
|
|
|
break;
|
|
case '#date_and_time':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'dateAndTime');
|
|
break;
|
|
case '#geolocation':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'geolocation');
|
|
break;
|
|
case '#import_contacts':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'importContacts3');
|
|
// Enabling or disabling SIM import depending on card status
|
|
SimManager.checkSIMButton();
|
|
|
|
// Enabling or disabling SD import depending on card status
|
|
SdManager.checkSDButton();
|
|
|
|
// If we have 3G or Wifi activate online services import
|
|
var onlineState;
|
|
if (!WifiManager.api) {
|
|
// Desktop
|
|
ImportIntegration.checkImport('enabled');
|
|
break;
|
|
}
|
|
|
|
onlineState = window.navigator.onLine ? 'enabled' : 'disabled';
|
|
ImportIntegration.checkImport(onlineState);
|
|
break;
|
|
case '#firefox_accounts':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'firefox-accounts');
|
|
break;
|
|
case '#welcome_browser':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'aboutBrowser');
|
|
|
|
// Initialize the radio button to preselect the basic metrics.
|
|
var settings = navigator.mozSettings;
|
|
var basicMetrics = document.getElementById('metrics-basic');
|
|
var enhancedMetrics = document.getElementById('metrics-enhanced');
|
|
var noneMetrics = document.getElementById('metrics-none');
|
|
|
|
var defaultLevel = settings &&
|
|
settings.createLock().get(METRICSSETTING);
|
|
if (defaultLevel) {
|
|
defaultLevel.onsuccess = function() {
|
|
var result = defaultLevel.result[METRICSSETTING];
|
|
if (result === 'Basic') {
|
|
basicMetrics.checked = true;
|
|
} else if (result === 'Enhanced') {
|
|
enhancedMetrics.checked = true;
|
|
} else if (result === 'None') {
|
|
noneMetrics.checked = true;
|
|
}
|
|
};
|
|
}
|
|
|
|
// If it's a dogfooder, we don't want them to disable the metrics.
|
|
var dogfood = settings && settings.createLock().get(DOGFOODSETTING);
|
|
if (dogfood) {
|
|
dogfood.onsuccess = function() {
|
|
if (dogfood.result[DOGFOODSETTING]) {
|
|
basicMetrics.setAttribute('disabled', 'true');
|
|
enhancedMetrics.setAttribute('disabled', 'true');
|
|
noneMetrics.setAttribute('disabled', 'true');
|
|
} else {
|
|
basicMetrics.removeAttribute('disabled');
|
|
enhancedMetrics.removeAttribute('disabled');
|
|
noneMetrics.removeAttribute('disabled');
|
|
}
|
|
};
|
|
}
|
|
break;
|
|
case '#browser_privacy':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'aboutBrowser');
|
|
break;
|
|
case '#SIM_mandatory':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'SIM_mandatory');
|
|
break;
|
|
case '#about-your-rights':
|
|
case '#about-your-privacy':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'aboutBrowser');
|
|
UIManager.navBar.classList.add('back-only');
|
|
break;
|
|
case '#sharing-performance-data':
|
|
UIManager.mainTitle.setAttribute('data-l10n-id', 'aboutBrowser');
|
|
UIManager.navBar.classList.add('back-only');
|
|
break;
|
|
}
|
|
|
|
// If SIM card is mandatory, we hide the button skip
|
|
if (this.simMandatory) {
|
|
UIManager.skipPinButton.classList.add('hidden');
|
|
UIManager.backSimButton.classList.remove('hidden');
|
|
} else {
|
|
UIManager.skipPinButton.classList.remove('hidden');
|
|
UIManager.backSimButton.classList.add('hidden');
|
|
}
|
|
|
|
// Managing options button
|
|
var lastIndex = this.stepCount - 1;
|
|
if (this.currentStepIndex <= lastIndex &&
|
|
(this.stepAt(this.currentStepIndex).hash !== '#wifi')) {
|
|
UIManager.activationScreen.classList.add('no-options');
|
|
}
|
|
|
|
// Managing nav buttons when coming back from out-of-steps (privacy)
|
|
if (this.currentStepIndex <= lastIndex &&
|
|
this.stepAt(this.currentStepIndex).hash === actualHash) {
|
|
UIManager.navBar.classList.remove('back-only');
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Posts IAC message about FTU steps passed.
|
|
*/
|
|
postStepMessage: function n_postStepMessage(stepIndex) {
|
|
if (!this.ports) {
|
|
return;
|
|
}
|
|
var step = this.stepAt(stepIndex);
|
|
this.ports.forEach(function(port) {
|
|
port.postMessage({
|
|
type: 'step',
|
|
hash: step.hash
|
|
});
|
|
});
|
|
},
|
|
|
|
skipStep: function n_skipStep() {
|
|
var stepIndex = this.currentStepIndex;
|
|
stepIndex += stepIndex > this.previousStepIndex ? 1 : -1;
|
|
if (stepIndex <= 0) {
|
|
this.previousStepIndex = stepIndex = 0;
|
|
}
|
|
if (stepIndex > this.stepCount) {
|
|
this.previousStepIndex = stepIndex = this.stepCount;
|
|
}
|
|
this.currentStepIndex = stepIndex;
|
|
this.manageStep();
|
|
},
|
|
|
|
manageStep: function n_manageStep() {
|
|
var self = this;
|
|
|
|
// If we moved forward in FTU, post iac message about progress.
|
|
if (self.currentStepIndex > self.previousStepIndex) {
|
|
self.postStepMessage(self.previousStepIndex);
|
|
}
|
|
|
|
//SV - We need remember if phone startup with SIM
|
|
if (self.currentStepIndex >= self.stepCount) {
|
|
OperatorVariant.setSIMOnFirstBootState();
|
|
}
|
|
|
|
// Reset skip screen flags at beginning of navigation
|
|
if (self.currentStepIndex === 0) {
|
|
self.skipMobileDataScreen = false;
|
|
}
|
|
|
|
// Retrieve future location
|
|
var futureLocation = this.stepAt(self.currentStepIndex);
|
|
|
|
// If SIMcard is mandatory and no SIM, go to message window
|
|
if (this.simMandatory &&
|
|
!IccHelper.cardState &&
|
|
futureLocation.requireSIM) {
|
|
//Send to SIM Mandatory message
|
|
futureLocation.hash = '#SIM_mandatory';
|
|
futureLocation.requireSIM = false;
|
|
futureLocation.onlyBackward = true;
|
|
}
|
|
|
|
// Navigation bar management
|
|
if (this.stepAt(this.currentStepIndex).onlyForward) {
|
|
UIManager.navBar.classList.add('forward-only');
|
|
} else {
|
|
UIManager.navBar.classList.remove('forward-only');
|
|
}
|
|
var nextButton = document.getElementById('forward');
|
|
if (this.stepAt(this.currentStepIndex).onlyBackward) {
|
|
nextButton.setAttribute('disabled', 'disabled');
|
|
} else {
|
|
nextButton.removeAttribute('disabled');
|
|
}
|
|
|
|
// Substitute button content on last step
|
|
if (this.currentStepIndex === this.stepCount) {
|
|
nextButton.setAttribute('data-l10n-id', 'done');
|
|
} else {
|
|
nextButton.setAttribute('data-l10n-id', 'navbar-next');
|
|
}
|
|
|
|
if (futureLocation.hash === '#firefox_accounts') {
|
|
nextButton.setAttribute('data-l10n-id', 'skip');
|
|
}
|
|
|
|
// Change hash to the right location
|
|
window.location.hash = futureLocation.hash;
|
|
|
|
// SIM card management
|
|
if (futureLocation.requireSIM) {
|
|
var check_cardState = function(response) {
|
|
if (!response || (!SimManager.available() &&
|
|
// Don't skip it if next step is data 3g
|
|
futureLocation.hash !== '#data_3g')) {
|
|
self.skipStep();
|
|
if (self.currentStepIndex > self.previousStepIndex) {
|
|
self.skipMobileDataScreen = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
// if we are navigating backwards, we do not want to
|
|
// show the SIM unlock screens for the data_3g step
|
|
var skipUnlockScreens = this.currentStepIndex < this.previousStepIndex;
|
|
SimManager.handleCardState(check_cardState, skipUnlockScreens);
|
|
}
|
|
|
|
// Only show the Date & Time screen if we couldn't determine the
|
|
// timezone from the network. (We assume that if we can
|
|
// determine the timezone, we can determine the time too.)
|
|
if (this.stepAt(this.currentStepIndex).hash === '#date_and_time') {
|
|
if (!self.tzInitialized) {
|
|
self.skipDateTimeScreen = !UIManager.timeZoneNeedsConfirmation;
|
|
}
|
|
|
|
if (self.skipDateTimeScreen) {
|
|
self.postStepMessage(self.currentStepIndex);
|
|
if(navigator.onLine) {
|
|
//if you are online you can get a more accurate guess for the time
|
|
//time you just need to trigger it
|
|
UIManager.updateSetting(
|
|
'time.timezone.automatic-update.enabled',
|
|
true
|
|
);
|
|
UIManager.updateSetting(
|
|
'time.clock.automatic-update.enabled',
|
|
true
|
|
);
|
|
}
|
|
self.skipStep();
|
|
}
|
|
}
|
|
|
|
// if we are not connected we should not try fxa
|
|
if ((futureLocation.hash === '#firefox_accounts' &&
|
|
!navigator.onLine) ||
|
|
(futureLocation.hash === '#firefox_accounts' &&
|
|
UIManager.skipFxA)) {
|
|
self.postStepMessage(self.currentStepIndex);
|
|
self.skipStep();
|
|
}
|
|
}
|
|
};
|
|
})(window);
|