Bug 1183932 - Update onboarding for Fx 40 with single slide [r=emto, feedback=flod]

This commit is contained in:
Maxim Zhilyaev 2015-07-20 22:17:09 -07:00
Родитель a714287abf
Коммит 13fd558e67
8 изменённых файлов: 48 добавлений и 415 удалений

Просмотреть файл

@ -1680,9 +1680,6 @@ pref("browser.newtab.preload", true);
// Remembers if the about:newtab intro has been shown
pref("browser.newtabpage.introShown", false);
// Remembers if the about:newtab update intro has been shown
pref("browser.newtabpage.updateIntroShown", false);
// Toggles the content of 'about:newtab'. Shows the grid when enabled.
pref("browser.newtabpage.enabled", true);

Просмотреть файл

@ -5,118 +5,49 @@
#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);
_showMessage: function() {
// 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];
this._paragraphs.forEach((arg, index) => {
paragraphNodes[index].innerHTML = 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));
});
// Set the button
document.getElementById("newtab-intro-button").
setAttribute("value", newTabString("intro.gotit"));
},
_bold: function(str) {
return `<strong>${str}</strong>`
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", () => {
@ -124,85 +55,14 @@ let gIntro = {
});
},
_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
}
}
this._paragraphs.push(newTabString("intro1.paragraph1"));
this._paragraphs.push(newTabString("intro1.paragraph2",
[
this._link(TILES_PRIVACY_LINK, newTabString("privacy.link")),
customizeIcon
]));
},
showIfNecessary: function() {
@ -210,14 +70,9 @@ let gIntro = {
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_INTRO_SHOWN, true);
Services.prefs.setBoolPref(PREF_UPDATE_INTRO_SHOWN, true);
},
showPanel: function() {
@ -227,20 +82,14 @@ let gIntro = {
if (!this._paragraphs.length) {
// It's our first time showing the panel. Do some initial setup
this._generateParagraphs();
this._generateImages();
}
this._goToPage(0);
this._showMessage();
// Header text
let boldSubstr = this._onboardingType == WELCOME ? this._span(this._brandShortName, "bold") : "";
this._nodes.header.innerHTML = newTabString("intro.header." + this._onboardingType, [boldSubstr]);
this._nodes.header.innerHTML = newTabString("intro.header.update");
// 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;
});
let footerLinkNode = document.getElementById("newtab-intro-link");
footerLinkNode.innerHTML = this._link(TILES_INTRO_LINK, newTabString("learn.link2"))
},
};

Просмотреть файл

@ -655,7 +655,7 @@ input[type=button] {
#newtab-intro-modal {
font-family: "Helvetica";
height: 512px;
max-height: 800px;
position: fixed;
left: 0;
right: 0;
@ -665,7 +665,6 @@ input[type=button] {
background: linear-gradient(#FFFFFF, #F9F9F9);
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.7);
border-radius: 8px 8px 0px 0px;
min-width: 715px;
position: relative;
display: inline-block;
top: 50%;
@ -676,14 +675,14 @@ input[type=button] {
font-size: 28px;
color: #737980;
text-align: center;
top: 50px;
top: 30px;
position: relative;
border-bottom: 2px solid #E0DFE0;
padding-bottom: 10px;
display: block;
margin: 0px auto;
margin: 0px 50px;
font-weight: 100;
padding: 0px 15px;
padding: 0px 15px 10px;
}
#newtab-intro-header .bold {
@ -697,7 +696,6 @@ input[type=button] {
margin: 0px auto;
display: block;
position: absolute;
bottom: 0px;
background-color: white;
box-shadow: 0 -1px 4px -1px #EBEBEB;
text-align: center;
@ -722,20 +720,10 @@ input[type=button] {
color: #4A90E2;
}
#newtab-intro-footer > ul > li > a:visited {
color: #171F26;
}
#newtab-intro-footer > ul > :first-child {
border-right: solid 1px #C1C1C1;
}
#newtab-intro-body {
height: 330px;
position: relative;
display: block;
top: 50px;
margin: 25px 50px 30px;
margin: 55px 50px 38px;
}
#newtab-intro-content > * {
@ -743,14 +731,12 @@ input[type=button] {
}
#newtab-intro-content {
height: 210px;
position: relative;
}
#newtab-intro-buttons {
text-align: center;
vertical-align: middle;
position: absolute;
display: block;
bottom: 0px;
width: 100%;
@ -764,53 +750,19 @@ input[type=button] {
#newtab-intro-text {
text-align: left;
right: 0px;
width: 270px;
}
#newtab-intro-text,
#newtab-intro-image {
height: 100%;
right: 0px;
font-size: 14px;
line-height: 20px;
min-width: 270px;
}
#newtab-intro-image {
left: 0px;
right: auto;
float: left;
margin-right: 40px;
}
.newtab-intro-image-customize {
box-shadow: 3px 3px 5px #888;
margin-top: 0px;
background-color: #FFF;
float: left;
z-index: 101;
margin-top: -5px;
min-width: 270px;
padding: 0;
}
.newtab-intro-image-customize #newtab-customize-title {
display: block;
max-height: 40px;
}
.newtab-intro-image-customize #newtab-customize-panel-anchor {
display: none;
}
.newtab-intro-image-customize .newtab-customize-panel-item:not([selected]):hover {
background-color: inherit;
color: #7A7A7A;
background: none;
width: 460px;
}
#newtab-intro-text > p {
margin: 0 0 1em 0;
margin: 0 0 30px;
}
#newtab-intro-text > p > a {
text-decoration: none;
color: #4A90E2;
}
#newtab-intro-text .newtab-control {
@ -820,10 +772,11 @@ input[type=button] {
vertical-align: middle;
opacity: 1;
position: inherit;
pointer-events: none;
}
#newtab-intro-buttons > input {
min-width: 150px;
min-width: 120px;
height: 50px;
margin: 0px 5px;
vertical-align: bottom;
@ -844,51 +797,3 @@ input[type=button] {
background-color: #2C72E2;
color: #FFFFFF;
}
#newtab-intro-progress {
position: absolute;
width: 100%;
}
#newtab-intro-numerical-progress {
text-align: center;
top: 15px;
position: relative;
font-size: 12px;
color: #424F5A;
}
#newtab-intro-graphical-progress {
text-align: left;
border-radius: 1.5px;
overflow: hidden;
position: relative;
margin: 10px auto 0px;
height: 3px;
top: 8px;
width: 35px;
background-color: #DCDCDC;
}
#indicator {
position: absolute;
top: 0px;
left: 0px;
display: inline-block;
width: 0%;
height: 4px;
background: none repeat scroll 0% 0% #FF9500;
transition: width 0.3s ease-in-out 0s;
}
#newtab-intro-numerical-progress[page="0"] + #newtab-intro-graphical-progress > #indicator {
width: 33%;
}
#newtab-intro-numerical-progress[page="1"] + #newtab-intro-graphical-progress > #indicator {
width: 66%;
}
#newtab-intro-numerical-progress[page="2"] + #newtab-intro-graphical-progress > #indicator {
width: 100%;
}

Просмотреть файл

@ -49,28 +49,20 @@
<div id="newtab-intro-mask">
<div id="newtab-intro-modal">
<div id="newtab-intro-progress">
<div id="newtab-intro-numerical-progress"/>
<div id="newtab-intro-graphical-progress">
<span id="indicator"/>
</div>
</div>
<div id="newtab-intro-header"/>
<div id="newtab-intro-body">
<div id="newtab-intro-content">
<div id="newtab-intro-image"/>
<div id="newtab-intro-text">
<p/><p/>
</div>
</div>
<div id="newtab-intro-buttons">
<input type="button" onclick="gIntro._back()"/>
<input type="button" default="true" onclick="gIntro._next()"/>
<input id="newtab-intro-button" type="button" default="true" onclick="gIntro._exitIntro()"/>
</div>
</div>
<div id="newtab-intro-footer">
<ul>
<li/><li/>
<li id="newtab-intro-link"/>
</ul>
</div>
</div>

Просмотреть файл

@ -2,35 +2,27 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
const INTRO_PREF = "browser.newtabpage.introShown";
const UPDATE_INTRO_PREF = "browser.newtabpage.updateIntroShown";
const PRELOAD_PREF = "browser.newtab.preload";
function runTests() {
let origIntro = Services.prefs.getBoolPref(INTRO_PREF);
let origUpdateIntro = Services.prefs.getBoolPref(UPDATE_INTRO_PREF);
let origPreload = Services.prefs.getBoolPref(PRELOAD_PREF);
registerCleanupFunction(_ => {
Services.prefs.setBoolPref(INTRO_PREF, origIntro);
Services.prefs.setBoolPref(INTRO_PREF, origUpdateIntro);
Services.prefs.setBoolPref(PRELOAD_PREF, origPreload);
});
// Test with preload false
Services.prefs.setBoolPref(INTRO_PREF, false);
Services.prefs.setBoolPref(UPDATE_INTRO_PREF, false);
Services.prefs.setBoolPref(PRELOAD_PREF, false);
let intro;
let brand = Services.strings.createBundle("chrome://branding/locale/brand.properties");
let brandShortName = brand.GetStringFromName("brandShortName");
yield addNewTabPageTab();
let intro;
intro = getContentDocument().getElementById("newtab-intro-mask");
is(intro.style.opacity, 1, "intro automatically shown on first opening");
is(getContentDocument().getElementById("newtab-intro-header").innerHTML,
'Welcome to New Tab on <span xmlns="http://www.w3.org/1999/xhtml" class="bold">' + brandShortName + '</span>!', "we show the first-run intro.");
'New Tab got an update!', "we show intro.");
is(Services.prefs.getBoolPref(INTRO_PREF), true, "newtab remembers that the intro was shown");
is(Services.prefs.getBoolPref(UPDATE_INTRO_PREF), true, "newtab avoids showing update if intro was shown");
yield addNewTabPageTab();
intro = getContentDocument().getElementById("newtab-intro-mask");
@ -44,76 +36,11 @@ function runTests() {
intro = getContentDocument().getElementById("newtab-intro-mask");
is(intro.style.opacity, 1, "intro automatically shown on preloaded opening");
is(getContentDocument().getElementById("newtab-intro-header").innerHTML,
'Welcome to New Tab on <span xmlns="http://www.w3.org/1999/xhtml" class="bold">' + brandShortName + '</span>!', "we show the first-run intro.");
'New Tab got an update!', "we show intro.");
is(Services.prefs.getBoolPref(INTRO_PREF), true, "newtab remembers that the intro was shown");
is(Services.prefs.getBoolPref(UPDATE_INTRO_PREF), true, "newtab avoids showing update if intro was shown");
// Test with first run true but update false
Services.prefs.setBoolPref(UPDATE_INTRO_PREF, false);
let gotit = getContentDocument().getElementById("newtab-intro-button");
gotit.click();
yield addNewTabPageTab();
intro = getContentDocument().getElementById("newtab-intro-mask");
is(intro.style.opacity, 1, "intro automatically shown on preloaded opening");
is(getContentDocument().getElementById("newtab-intro-header").innerHTML,
"New Tab got an update!", "we show the update intro.");
is(Services.prefs.getBoolPref(INTRO_PREF), true, "INTRO_PREF stays true");
is(Services.prefs.getBoolPref(UPDATE_INTRO_PREF), true, "newtab remembers that the update intro was show");
// Test clicking the 'next' and 'back' buttons.
let buttons = getContentDocument().getElementById("newtab-intro-buttons").getElementsByTagName("input");
let progress = getContentDocument().getElementById("newtab-intro-numerical-progress");
let back = buttons[0];
let next = buttons[1];
is(progress.getAttribute("page"), 0, "we are on the first page");
is(intro.style.opacity, 1, "intro visible");
let createMutationObserver = function(fcn) {
return new Promise(resolve => {
let observer = new MutationObserver(function(mutations) {
fcn();
observer.disconnect();
resolve();
});
let config = { attributes: true, attributeFilter: ["style"], childList: true };
observer.observe(progress, config);
});
}
let p = createMutationObserver(function() {
is(progress.getAttribute("page"), 1, "we get to the 2nd page");
is(intro.style.opacity, 1, "intro visible");
});
next.click();
yield p.then(TestRunner.next);
p = createMutationObserver(function() {
is(progress.getAttribute("page"), 2, "we get to the 3rd page");
is(intro.style.opacity, 1, "intro visible");
});
next.click();
yield p.then(TestRunner.next);
p = createMutationObserver(function() {
is(progress.getAttribute("page"), 1, "go back to 2nd page");
is(intro.style.opacity, 1, "intro visible");
});
back.click();
yield p.then(TestRunner.next);
p = createMutationObserver(function() {
is(progress.getAttribute("page"), 0, "go back to 1st page");
is(intro.style.opacity, 1, "intro visible");
});
back.click();
yield p.then(TestRunner.next);
p = createMutationObserver(function() {
is(progress.getAttribute("page"), 0, "another back will 'skip tutorial'");
is(intro.style.opacity, 0, "intro exited");
});
back.click();
p.then(TestRunner.next);
is(intro.style.opacity, 0, "intro exited");
}

Просмотреть файл

@ -34,40 +34,13 @@ newtab.suggested.explain=This site is suggested to you by Mozilla. You can remov
# the gear icon used to customize the new tab window. %2$S will be replaced by
# an active link using string newtab.learn.link as text.
newtab.enhanced.explain=A Mozilla partner has visually enhanced this tile, replacing the screenshot. You can turn off enhanced tiles by clicking the %1$S button for your preferences. %2$S
# LOCALIZATION NOTE(newtab.intro.paragraph2): %1$S will be replaced inline by
# active link using string newtab.privacy.link as text.
newtab.intro.paragraph2=In order to provide this service, Mozilla collects and uses certain analytics information relating to your use of the tiles in accordance with our %1$S.
# LOCALIZATION NOTE(newtab.intro.paragraph4.2): %1$S will be replaced inline by
# the gear icon used to customize the new tab window. %2$S will be replaced by
# newtab.intro.controls as text. The quoted strings should be the same as
# newtab.customize.cog.enhanced.
newtab.intro.paragraph4.2=You can turn off this service by clicking the gear (%1$S) button and unchecking "Include suggested sites" in the %2$S menu.
newtab.intro.paragraph5=New Tab will show the sites you visit most frequently, along with sites we think might be of interest to you. To get started, you'll see several sites from Mozilla.
# LOCALIZATION NOTE(newtab.intro.paragraph6): %1$S will be replaced by
# newtab.intro.paragraph6.remove as bold text. %2$S will be replaced by
# newtab.intro.paragraph6.pin as bold text
newtab.intro.paragraph6=You can %1$S or %2$S any site by using the controls available on rollover.
newtab.intro.paragraph6.remove=remove
newtab.intro.paragraph6.pin=pin
newtab.intro.paragraph7=Some of the sites you will see may be suggested by Mozilla and may be sponsored by a Mozilla partner. We'll always indicate which sites are sponsored.
# LOCALIZATION NOTE(newtab.intro.paragraph8): %1$S will be replaced by
# brandShortName as text. %2$S will be replaced inline by an active link using
# string newtab.learn.link as text.
newtab.intro.paragraph8=%1$S will only show sites that most closely match your interests on the Web. %2$S
newtab.intro.paragraph9=Now when you open New Tab, you'll also see sites we think might be interesting to you.
# LOCALIZATION NOTE(newtab.intro.controls): the controls in the gear icon
# menu for customizing the new tab window. Used in newtab.intro.paragraph4
newtab.intro.controls=New Tab Controls
newtab.intro1.paragraph1=Now when you open New Tab, you'll also see sites we think might be interesting to you. Some may be suggested by Mozilla or sponsored by one of our partners.
# LOCALIZATION NOTE(newtab.intro1.paragraph2): %1$S will be replaced inline by
# an active link using string newtab.privacy.link as text. %2$S will be replaced
# inline by the gear icon used to customize the new tab window.
newtab.intro1.paragraph2=In order to provide this service, some data is automatically sent back to us in accordance with our %1$S. You can turn this off by unchecking the option under the gear icon (%2$S).
newtab.learn.link=Learn more…
newtab.privacy.link=Privacy Notice
newtab.learn.link2=More about New Tab
newtab.privacy.link2=About your privacy
# LOCALIZATION NOTE(newtab.intro.header.welcome): %1$S will be replaced by
# brandShortName as bold text.
newtab.intro.header.welcome=Welcome to New Tab on %1$S!
newtab.intro.header.update=New Tab got an update!
newtab.intro.skip=Skip this
newtab.intro.continue=Continue tour
newtab.intro.back=Back
newtab.intro.next=Next
newtab.intro.gotit=Got it!

Просмотреть файл

@ -87,9 +87,7 @@
}
/* CELLS */
.newtab-cell,
.newtab-intro-cell,
.newtab-intro-cell-hover {
.newtab-cell {
background-color: rgba(255,255,255,.2);
border-radius: 8px;
}
@ -109,19 +107,12 @@
.newtab-cell:not([ignorehover]) .newtab-control:hover ~ .newtab-link,
.newtab-cell:not([ignorehover]) .newtab-link:hover,
.newtab-site[dragged],
.newtab-intro-cell-hover .newtab-link {
.newtab-site[dragged] {
border: 2px solid white;
box-shadow: 0 0 6px 2px #4cb1ff;
margin: -2px;
}
.newtab-intro-cell .newtab-thumbnail,
.newtab-intro-cell-hover .newtab-thumbnail {
background-color: #cae1f4;
background-image: url("chrome://browser/skin/newtab/whimsycorn.png");
}
.newtab-site[dragged] {
transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);

Просмотреть файл

@ -195,7 +195,6 @@ user_pref("browser.download.panel.shown", true);
// Assume the about:newtab page's intro panels have been shown to not depend on
// which test runs first and happens to open about:newtab
user_pref("browser.newtabpage.introShown", true);
user_pref("browser.newtabpage.updateIntroShown", true);
// Tell the PBackground infrastructure to run a test at startup.
user_pref("pbackground.testing", true);