Added experiment for firefox download promo
This commit is contained in:
parent
d0d41b743a
commit
e7fdf76120
@ -1,6 +1,28 @@
|
||||
import hash from 'string-hash';
|
||||
|
||||
const experiments = {};
|
||||
const experiments = {
|
||||
'SyI-hI7gT9agiH-f3f0BYg': {
|
||||
id: 'SyI-hI7gT9agiH-f3f0BYg',
|
||||
run: function(variant, state, emitter) {
|
||||
state.promo = variant === 1 ? 'body' : 'header';
|
||||
emitter.emit('render');
|
||||
},
|
||||
eligible: function() {
|
||||
return (
|
||||
!/firefox/i.test(navigator.userAgent) &&
|
||||
document.querySelector('html').lang === 'en-US'
|
||||
);
|
||||
},
|
||||
variant: function(state) {
|
||||
return this.luckyNumber(state) > 0.5 ? 1 : 0;
|
||||
},
|
||||
luckyNumber: function(state) {
|
||||
return luckyNumber(
|
||||
`${this.id}:${state.storage.get('testpilot_ga__cid')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//Returns a number between 0 and 1
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
@ -32,12 +54,12 @@ export default function initialize(state, emitter) {
|
||||
checkExperiments(state, emitter);
|
||||
});
|
||||
} else {
|
||||
const enrolled = state.storage.enrolled;
|
||||
enrolled.forEach(([id, variant]) => {
|
||||
const enrolled = state.storage.enrolled.filter(([id, variant]) => {
|
||||
const xp = experiments[id];
|
||||
if (xp) {
|
||||
xp.run(variant, state, emitter);
|
||||
}
|
||||
return !!xp;
|
||||
});
|
||||
// single experiment per session for now
|
||||
if (enrolled.length === 0) {
|
||||
|
@ -47,4 +47,4 @@ app.use(fileManager);
|
||||
app.use(dragManager);
|
||||
app.use(experiments);
|
||||
|
||||
app.mount('#page-one');
|
||||
app.mount('body');
|
||||
|
@ -20,7 +20,7 @@ let experiment = null;
|
||||
export default function initialize(state, emitter) {
|
||||
appState = state;
|
||||
emitter.on('DOMContentLoaded', () => {
|
||||
addExitHandlers();
|
||||
// addExitHandlers();
|
||||
experiment = storage.enrolled[0];
|
||||
sendEvent(category(), 'visit', {
|
||||
cm5: storage.totalUploads,
|
||||
@ -29,6 +29,9 @@ export default function initialize(state, emitter) {
|
||||
});
|
||||
//TODO restart handlers... somewhere
|
||||
});
|
||||
emitter.on('exit', evt => {
|
||||
exitEvent(evt);
|
||||
});
|
||||
}
|
||||
|
||||
function category() {
|
||||
@ -81,6 +84,8 @@ function urlToMetric(url) {
|
||||
case 'https://testpilot.firefox.com/':
|
||||
case 'https://testpilot.firefox.com/experiments/send':
|
||||
return 'testpilot';
|
||||
case 'https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com':
|
||||
return 'promo';
|
||||
default:
|
||||
return 'other';
|
||||
}
|
||||
@ -244,6 +249,7 @@ function exitEvent(target) {
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function addExitHandlers() {
|
||||
const links = Array.from(document.querySelectorAll('a'));
|
||||
links.forEach(l => {
|
||||
|
@ -1,17 +1,43 @@
|
||||
const choo = require('choo');
|
||||
const html = require('choo/html');
|
||||
const download = require('./download');
|
||||
const header = require('../templates/header');
|
||||
const footer = require('../templates/footer');
|
||||
const fxPromo = require('../templates/fxPromo');
|
||||
|
||||
const app = choo();
|
||||
|
||||
app.route('/', require('./home'));
|
||||
app.route('/share/:id', require('../templates/share'));
|
||||
app.route('/download/:id', download);
|
||||
app.route('/download/:id/:key', download);
|
||||
app.route('/completed', require('../templates/completed'));
|
||||
app.route('/unsupported/:reason', require('../templates/unsupported'));
|
||||
app.route('/legal', require('../templates/legal'));
|
||||
app.route('/error', require('../templates/error'));
|
||||
app.route('/blank', require('../templates/blank'));
|
||||
app.route('*', require('../templates/notFound'));
|
||||
function body(template) {
|
||||
return function(state, emit) {
|
||||
const b = html`<body>
|
||||
${state.promo === 'header' ? fxPromo(state, emit) : ''}
|
||||
${header(state)}
|
||||
<div class="all">
|
||||
<noscript>
|
||||
<h2>Firefox Send requires JavaScript</h2>
|
||||
<p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">Why does Firefox Send require JavaScript?</a></p>
|
||||
<p>Please enable JavaScript and try again.</p>
|
||||
</noscript>
|
||||
${template(state, emit)}
|
||||
</div>
|
||||
${footer(state)}
|
||||
</body>`;
|
||||
if (state.layout) {
|
||||
return state.layout(state, b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
}
|
||||
|
||||
app.route('/', body(require('./home')));
|
||||
app.route('/share/:id', body(require('../templates/share')));
|
||||
app.route('/download/:id', body(download));
|
||||
app.route('/download/:id/:key', body(download));
|
||||
app.route('/completed', body(require('../templates/completed')));
|
||||
app.route('/unsupported/:reason', body(require('../templates/unsupported')));
|
||||
app.route('/legal', body(require('../templates/legal')));
|
||||
app.route('/error', body(require('../templates/error')));
|
||||
app.route('/blank', body(require('../templates/blank')));
|
||||
app.route('*', body(require('../templates/notFound')));
|
||||
|
||||
module.exports = app;
|
||||
|
@ -1,9 +1,6 @@
|
||||
const html = require('choo/html');
|
||||
|
||||
module.exports = function(state) {
|
||||
module.exports = function() {
|
||||
const div = html`<div id="page-one"></div>`;
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
const html = require('choo/html');
|
||||
const progress = require('./progress');
|
||||
const { fadeOut } = require('../utils');
|
||||
const fxPromo = require('./fxPromo');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const div = html`
|
||||
<div id="page-one">
|
||||
<div id="download" class="fadeIn">
|
||||
<div id="download-progress">
|
||||
<div id="dl-title" class="title">${state.translate(
|
||||
@ -19,6 +21,8 @@ module.exports = function(state, emit) {
|
||||
sendNew
|
||||
}>${state.translate('sendYourFilesLink')}</a>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
async function sendNew(e) {
|
||||
|
@ -1,10 +1,12 @@
|
||||
const html = require('choo/html');
|
||||
const progress = require('./progress');
|
||||
const { bytes } = require('../utils');
|
||||
const fxPromo = require('./fxPromo');
|
||||
|
||||
module.exports = function(state) {
|
||||
module.exports = function(state, emit) {
|
||||
const transfer = state.transfer;
|
||||
const div = html`
|
||||
<div id="page-one">
|
||||
<div id="download-progress" class="fadeIn">
|
||||
<div id="dl-title" class="title">${state.translate(
|
||||
'downloadingPageProgress',
|
||||
@ -22,6 +24,8 @@ module.exports = function(state) {
|
||||
)}</div>
|
||||
</div>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
return div;
|
||||
|
31
app/templates/footer.js
Normal file
31
app/templates/footer.js
Normal file
@ -0,0 +1,31 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
module.exports = function(state) {
|
||||
return html`<div class="footer">
|
||||
<div class="legal-links">
|
||||
<a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="${assets.get(
|
||||
'mozilla-logo.svg'
|
||||
)}" alt="mozilla"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal">${state.translate(
|
||||
'footerLinkLegal'
|
||||
)}</a>
|
||||
<a href="https://testpilot.firefox.com/about">${state.translate(
|
||||
'footerLinkAbout'
|
||||
)}</a>
|
||||
<a href="/legal">${state.translate('footerLinkPrivacy')}</a>
|
||||
<a href="/legal">${state.translate('footerLinkTerms')}</a>
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies">${state.translate(
|
||||
'footerLinkCookies'
|
||||
)}</a>
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="${assets.get(
|
||||
'github-icon.svg'
|
||||
)}" alt="github"/></a>
|
||||
<a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="${assets.get(
|
||||
'twitter-icon.svg'
|
||||
)}" alt="twitter"/></a>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
44
app/templates/fxPromo.js
Normal file
44
app/templates/fxPromo.js
Normal file
@ -0,0 +1,44 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
// function replaceLinks(str, urls) {
|
||||
// let i = -1;
|
||||
// const s = str.replace(/<a>([^<]+)<\/a>/g, (m, v) => {
|
||||
// i++;
|
||||
// return `<a class="link" href="${urls[i]}">${v}</a>`;
|
||||
// });
|
||||
// return [`<span>${s}</span>`];
|
||||
// }
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
// function close() {
|
||||
// document.querySelector('.banner').remove();
|
||||
// }
|
||||
|
||||
function clicked(evt) {
|
||||
emit('exit', evt);
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="banner">
|
||||
<div>
|
||||
<img
|
||||
src="${assets.get('firefox_logo-only.svg')}"
|
||||
class="firefox-logo-small"
|
||||
alt="Firefox"/>
|
||||
<span>Send is brought to you by the all-new Firefox.
|
||||
<a
|
||||
class="link"
|
||||
href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com"
|
||||
onclick=${clicked}
|
||||
>Download Firefox now ≫</a></span>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
/*
|
||||
<img
|
||||
src="${assets.get('close-16.svg')}"
|
||||
class="icon-delete"
|
||||
onclick=${close}>
|
||||
*/
|
21
app/templates/header.js
Normal file
21
app/templates/header.js
Normal file
@ -0,0 +1,21 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
module.exports = function(state) {
|
||||
return html`<header class="header">
|
||||
<div class="send-logo">
|
||||
<a href="/">
|
||||
<img src="${assets.get(
|
||||
'send_logo.svg'
|
||||
)}" alt="Send"/><h1 class="site-title">Send</h1>
|
||||
</a>
|
||||
<div class="site-subtitle">
|
||||
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
||||
<div>${state.translate('siteSubtitle')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank">${state.translate(
|
||||
'siteFeedback'
|
||||
)}</a>
|
||||
</header>`;
|
||||
};
|
@ -30,9 +30,5 @@ module.exports = function(state) {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
@ -17,9 +17,5 @@ module.exports = function(state) {
|
||||
)}</a>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
@ -3,6 +3,7 @@ const assets = require('../../common/assets');
|
||||
const notFound = require('./notFound');
|
||||
const downloadPassword = require('./downloadPassword');
|
||||
const { bytes } = require('../utils');
|
||||
const fxPromo = require('./fxPromo');
|
||||
|
||||
function getFileFromDOM() {
|
||||
const el = document.getElementById('dl-file');
|
||||
@ -61,6 +62,7 @@ module.exports = function(state, emit) {
|
||||
</div>
|
||||
<a class="send-new" href="/">${state.translate('sendYourFilesLink')}</a>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -68,9 +70,5 @@ module.exports = function(state, emit) {
|
||||
event.preventDefault();
|
||||
emit('download', fileInfo);
|
||||
}
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
@ -42,9 +42,5 @@ module.exports = function(state) {
|
||||
)}</div>
|
||||
</div>`;
|
||||
const div = html`<div id="page-one">${msg}</div>`;
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
const fileList = require('./fileList');
|
||||
const fxPromo = require('./fxPromo');
|
||||
const { fadeOut } = require('../utils');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
@ -35,6 +36,7 @@ module.exports = function(state, emit) {
|
||||
title="${state.translate('uploadPageBrowseButton1')}">
|
||||
${state.translate('uploadPageBrowseButton1')}</label>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
${fileList(state, emit)}
|
||||
</div>
|
||||
`;
|
||||
@ -67,9 +69,5 @@ module.exports = function(state, emit) {
|
||||
await fadeOut('page-one');
|
||||
emit('upload', { file, type: 'click' });
|
||||
}
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
@ -108,7 +108,8 @@ function bytes(num) {
|
||||
let nStr = n.toFixed(1);
|
||||
if (LOCALIZE_NUMBERS) {
|
||||
try {
|
||||
nStr = n.toLocaleString(navigator.languages.map(l => l.split(';')[0]), {
|
||||
const locale = document.querySelector('html').lang;
|
||||
nStr = n.toLocaleString(locale, {
|
||||
minimumFractionDigits: 1,
|
||||
maximumFractionDigits: 1
|
||||
});
|
||||
@ -122,10 +123,8 @@ function bytes(num) {
|
||||
function percent(ratio) {
|
||||
if (LOCALIZE_NUMBERS) {
|
||||
try {
|
||||
return ratio.toLocaleString(
|
||||
navigator.languages.map(l => l.split(';')[0]),
|
||||
{ style: 'percent' }
|
||||
);
|
||||
const locale = document.querySelector('html').lang;
|
||||
return ratio.toLocaleString(locale, { style: 'percent' });
|
||||
} catch (e) {
|
||||
// fall through
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 16 KiB |
@ -8,7 +8,6 @@ html {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center top;
|
||||
height: 100%;
|
||||
max-width: 1440px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@ -130,7 +129,7 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
max-width: 630px;
|
||||
max-width: 650px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
@ -213,7 +212,7 @@ a {
|
||||
|
||||
.upload-window {
|
||||
border: 3px dashed rgba(0, 148, 251, 0.5);
|
||||
margin: 0 auto;
|
||||
margin: 0 auto 10px;
|
||||
height: 255px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
@ -709,6 +708,10 @@ tbody {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.firefox-logo-small {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
#dl-firefox,
|
||||
#update-firefox {
|
||||
margin-bottom: 181px;
|
||||
@ -766,7 +769,7 @@ tbody {
|
||||
}
|
||||
|
||||
#download {
|
||||
margin: 0 auto;
|
||||
margin: 0 auto 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@ -955,6 +958,29 @@ tbody {
|
||||
background-position: 2px 1px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
padding: 0 15px;
|
||||
height: 48px;
|
||||
background-color: #efeff1;
|
||||
color: #4a4a4f;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.banner > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.banner > div > span {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@media (max-device-width: 992px), (max-width: 992px) {
|
||||
.popup .popuptext {
|
||||
left: auto;
|
||||
|
@ -112,6 +112,7 @@
|
||||
"en-US",
|
||||
"ast",
|
||||
"az",
|
||||
"bs",
|
||||
"ca",
|
||||
"cak",
|
||||
"cs",
|
||||
@ -132,6 +133,7 @@
|
||||
"id",
|
||||
"it",
|
||||
"ja",
|
||||
"ka",
|
||||
"kab",
|
||||
"ko",
|
||||
"ms",
|
||||
@ -145,6 +147,7 @@
|
||||
"sl",
|
||||
"sr",
|
||||
"sv-SE",
|
||||
"tl",
|
||||
"tr",
|
||||
"uk",
|
||||
"vi",
|
||||
|
@ -8,7 +8,7 @@ module.exports = function(state, body = '') {
|
||||
: '';
|
||||
return html`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="${state.locale}">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta charset="utf-8" />
|
||||
@ -71,58 +71,7 @@ module.exports = function(state, body = '') {
|
||||
<script defer src="${locales.get(state.locale)}"></script>
|
||||
<script defer src="${assets.get('app.js')}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
<div class="send-logo">
|
||||
<a href="/">
|
||||
<img src="${assets.get(
|
||||
'send_logo.svg'
|
||||
)}" alt="Send"/><h1 class="site-title">Send</h1>
|
||||
</a>
|
||||
<div class="site-subtitle">
|
||||
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
||||
<div>${state.translate('siteSubtitle')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank">${state.translate(
|
||||
'siteFeedback'
|
||||
)}</a>
|
||||
</header>
|
||||
<div class="all">
|
||||
<noscript>
|
||||
<h2>Firefox Send requires JavaScript</h2>
|
||||
<p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">Why does Firefox Send require JavaScript?</a></p>
|
||||
<p>Please enable JavaScript and try again.</p>
|
||||
</noscript>
|
||||
${body}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="legal-links">
|
||||
<a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="${assets.get(
|
||||
'mozilla-logo.svg'
|
||||
)}" alt="mozilla"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal">${state.translate(
|
||||
'footerLinkLegal'
|
||||
)}</a>
|
||||
<a href="https://testpilot.firefox.com/about">${state.translate(
|
||||
'footerLinkAbout'
|
||||
)}</a>
|
||||
<a href="/legal">${state.translate('footerLinkPrivacy')}</a>
|
||||
<a href="/legal">${state.translate('footerLinkTerms')}</a>
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies">${state.translate(
|
||||
'footerLinkCookies'
|
||||
)}</a>
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="${assets.get(
|
||||
'github-icon.svg'
|
||||
)}" alt="github"/></a>
|
||||
<a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="${assets.get(
|
||||
'twitter-icon.svg'
|
||||
)}" alt="twitter"/></a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user