refactored metrics
This commit is contained in:
parent
2a7099a7a2
commit
b0d36529a1
@ -1,61 +1,22 @@
|
|||||||
const testPilotGA = require('testpilot-ga');
|
|
||||||
const Raven = require('raven-js');
|
const Raven = require('raven-js');
|
||||||
|
const { unsupported } = require('./metrics');
|
||||||
|
|
||||||
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
|
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
|
||||||
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
|
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
|
||||||
}
|
}
|
||||||
|
|
||||||
const analytics = new testPilotGA({
|
|
||||||
an: 'Firefox Send',
|
|
||||||
ds: 'web',
|
|
||||||
tid: window.GOOGLE_ANALYTICS_ID
|
|
||||||
});
|
|
||||||
|
|
||||||
function sendEvent() {
|
|
||||||
return analytics.sendEvent.apply(analytics, arguments).catch(() => 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findMetric(href) {
|
|
||||||
switch (href) {
|
|
||||||
case 'https://www.mozilla.org/':
|
|
||||||
return 'mozilla';
|
|
||||||
case 'https://www.mozilla.org/about/legal':
|
|
||||||
return 'legal';
|
|
||||||
case 'https://testpilot.firefox.com/about':
|
|
||||||
return 'about';
|
|
||||||
case 'https://testpilot.firefox.com/privacy':
|
|
||||||
return 'privacy';
|
|
||||||
case 'https://testpilot.firefox.com/terms':
|
|
||||||
return 'terms';
|
|
||||||
case 'https://www.mozilla.org/privacy/websites/#cookies':
|
|
||||||
return 'cookies';
|
|
||||||
case 'https://github.com/mozilla/send':
|
|
||||||
return 'github';
|
|
||||||
case 'https://twitter.com/FxTestPilot':
|
|
||||||
return 'twitter';
|
|
||||||
case 'https://www.mozilla.org/firefox/new/?scene=2':
|
|
||||||
return 'download-firefox';
|
|
||||||
default:
|
|
||||||
return 'other';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ua = navigator.userAgent.toLowerCase();
|
const ua = navigator.userAgent.toLowerCase();
|
||||||
if (
|
if (
|
||||||
ua.indexOf('firefox') > -1 &&
|
ua.indexOf('firefox') > -1 &&
|
||||||
parseInt(ua.match(/firefox\/*([^\n\r]*)\./)[1], 10) <= 49
|
parseInt(ua.match(/firefox\/*([^\n\r]*)\./)[1], 10) <= 49
|
||||||
) {
|
) {
|
||||||
const isSender = !location.pathname.includes('/download');
|
unsupported({
|
||||||
const ec = isSender ? 'sender' : 'recipient';
|
err: new Error('Firefox is outdated.')
|
||||||
sendEvent(ec, 'unsupported', {
|
|
||||||
cd6: new Error('Firefox is outdated.')
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
location.replace('/unsupported/outdated');
|
location.replace('/unsupported/outdated');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Raven,
|
Raven
|
||||||
sendEvent,
|
|
||||||
findMetric
|
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
const { Raven, findMetric, sendEvent } = require('./common');
|
const { Raven } = require('./common');
|
||||||
const FileReceiver = require('./fileReceiver');
|
const FileReceiver = require('./fileReceiver');
|
||||||
const { notify, gcmCompliant } = require('./utils');
|
const { notify, gcmCompliant } = require('./utils');
|
||||||
const bytes = require('bytes');
|
const bytes = require('bytes');
|
||||||
const Storage = require('./storage');
|
const Storage = require('./storage');
|
||||||
const storage = new Storage(localStorage);
|
const storage = new Storage(localStorage);
|
||||||
const links = require('./links');
|
const links = require('./links');
|
||||||
|
const metrics = require('./metrics');
|
||||||
|
|
||||||
const $ = require('jquery');
|
const $ = require('jquery');
|
||||||
require('jquery-circle-progress');
|
require('jquery-circle-progress');
|
||||||
@ -13,28 +14,13 @@ $(() => {
|
|||||||
gcmCompliant()
|
gcmCompliant()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const $downloadBtn = $('#download-btn');
|
const $downloadBtn = $('#download-btn');
|
||||||
const $sendNew = $('.send-new');
|
|
||||||
const $dlProgress = $('#dl-progress');
|
const $dlProgress = $('#dl-progress');
|
||||||
const $progressText = $('.progress-text');
|
const $progressText = $('.progress-text');
|
||||||
const $title = $('.title');
|
const $title = $('.title');
|
||||||
|
|
||||||
$sendNew.on('click', () => {
|
|
||||||
sendEvent('recipient', 'restarted', {
|
|
||||||
cd2: 'completed'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.legal-links a, .social-links a, #dl-firefox').on('click', function(target) {
|
|
||||||
const metric = findMetric(target.currentTarget.href);
|
|
||||||
// record exited event by recipient
|
|
||||||
sendEvent('recipient', 'exited', {
|
|
||||||
cd3: metric
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const filename = $('#dl-filename').text();
|
const filename = $('#dl-filename').text();
|
||||||
const bytelength = Number($('#dl-bytelength').text());
|
const size = Number($('#dl-size').text());
|
||||||
const timeToExpiry = Number($('#dl-ttl').text());
|
const ttl = Number($('#dl-ttl').text());
|
||||||
|
|
||||||
//initiate progress bar
|
//initiate progress bar
|
||||||
$dlProgress.circleProgress({
|
$dlProgress.circleProgress({
|
||||||
@ -50,22 +36,11 @@ $(() => {
|
|||||||
$downloadBtn.attr('disabled', 'disabled');
|
$downloadBtn.attr('disabled', 'disabled');
|
||||||
links.setOpenInNewTab(true);
|
links.setOpenInNewTab(true);
|
||||||
|
|
||||||
storage.totalDownloads += 1;
|
|
||||||
|
|
||||||
const fileReceiver = new FileReceiver();
|
const fileReceiver = new FileReceiver();
|
||||||
const unexpiredFiles = storage.numFiles;
|
|
||||||
|
|
||||||
fileReceiver.on('progress', progress => {
|
fileReceiver.on('progress', progress => {
|
||||||
window.onunload = function() {
|
window.onunload = function() {
|
||||||
storage.referrer = 'cancelled-download';
|
metrics.cancelledDownload({ size });
|
||||||
// record download-stopped (cancelled by tab close or reload)
|
|
||||||
sendEvent('recipient', 'download-stopped', {
|
|
||||||
cm1: bytelength,
|
|
||||||
cm5: storage.totalUploads,
|
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads,
|
|
||||||
cd2: 'cancelled'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$('#download-page-one').attr('hidden', true);
|
$('#download-page-one').attr('hidden', true);
|
||||||
@ -115,27 +90,12 @@ $(() => {
|
|||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
// record download-started by recipient
|
metrics.startedDownload({ size, ttl });
|
||||||
sendEvent('recipient', 'download-started', {
|
|
||||||
cm1: bytelength,
|
|
||||||
cm4: timeToExpiry,
|
|
||||||
cm5: storage.totalUploads,
|
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads
|
|
||||||
});
|
|
||||||
|
|
||||||
fileReceiver
|
fileReceiver
|
||||||
.download()
|
.download()
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
// record download-stopped (errored) by recipient
|
metrics.stoppedDownload({ size, err });
|
||||||
sendEvent('recipient', 'download-stopped', {
|
|
||||||
cm1: bytelength,
|
|
||||||
cm5: storage.totalUploads,
|
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads,
|
|
||||||
cd2: 'errored',
|
|
||||||
cd6: err
|
|
||||||
});
|
|
||||||
|
|
||||||
if (err.message === 'notfound') {
|
if (err.message === 'notfound') {
|
||||||
location.reload();
|
location.reload();
|
||||||
@ -150,21 +110,11 @@ $(() => {
|
|||||||
})
|
})
|
||||||
.then(([decrypted, fname]) => {
|
.then(([decrypted, fname]) => {
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
const totalTime = endTime - startTime;
|
const time = endTime - startTime;
|
||||||
const downloadTime = endTime - downloadEnd;
|
const downloadTime = endTime - downloadEnd;
|
||||||
const downloadSpeed = bytelength / (downloadTime / 1000);
|
const speed = size / (downloadTime / 1000);
|
||||||
|
storage.totalDownloads += 1;
|
||||||
storage.referrer = 'completed-download';
|
metrics.completedDownload({ size, time, speed });
|
||||||
// record download-stopped (completed) by recipient
|
|
||||||
sendEvent('recipient', 'download-stopped', {
|
|
||||||
cm1: bytelength,
|
|
||||||
cm2: totalTime,
|
|
||||||
cm3: downloadSpeed,
|
|
||||||
cm5: storage.totalUploads,
|
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads,
|
|
||||||
cd2: 'completed'
|
|
||||||
});
|
|
||||||
|
|
||||||
const dataView = new DataView(decrypted);
|
const dataView = new DataView(decrypted);
|
||||||
const blob = new Blob([dataView]);
|
const blob = new Blob([dataView]);
|
||||||
@ -186,14 +136,12 @@ $(() => {
|
|||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
})
|
})
|
||||||
.then(() => links.setOpenInNewTab(false));
|
.then(() => links.setOpenInNewTab(false));
|
||||||
}
|
};
|
||||||
|
|
||||||
$downloadBtn.on('click', download);
|
$downloadBtn.on('click', download);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
sendEvent('sender', 'unsupported', {
|
metrics.unsupported({ err }).then(() => {
|
||||||
cd6: err
|
|
||||||
}).then(() => {
|
|
||||||
location.replace('/unsupported/gcm');
|
location.replace('/unsupported/gcm');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
234
frontend/src/metrics.js
Normal file
234
frontend/src/metrics.js
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
const testPilotGA = require('testpilot-ga');
|
||||||
|
const Storage = require('./storage');
|
||||||
|
const storage = new Storage(localStorage);
|
||||||
|
|
||||||
|
const analytics = new testPilotGA({
|
||||||
|
an: 'Firefox Send',
|
||||||
|
ds: 'web',
|
||||||
|
tid: window.GOOGLE_ANALYTICS_ID
|
||||||
|
});
|
||||||
|
|
||||||
|
const category = location.pathname.includes('/download')
|
||||||
|
? 'recipient'
|
||||||
|
: 'sender';
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
addExitHandlers();
|
||||||
|
addRestartHandlers();
|
||||||
|
});
|
||||||
|
|
||||||
|
function sendEvent() {
|
||||||
|
return analytics.sendEvent.apply(analytics, arguments).catch(() => 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function urlToMetric(url) {
|
||||||
|
switch (url) {
|
||||||
|
case 'https://www.mozilla.org/':
|
||||||
|
return 'mozilla';
|
||||||
|
case 'https://www.mozilla.org/about/legal':
|
||||||
|
return 'legal';
|
||||||
|
case 'https://testpilot.firefox.com/about':
|
||||||
|
return 'about';
|
||||||
|
case 'https://testpilot.firefox.com/privacy':
|
||||||
|
return 'privacy';
|
||||||
|
case 'https://testpilot.firefox.com/terms':
|
||||||
|
return 'terms';
|
||||||
|
case 'https://www.mozilla.org/privacy/websites/#cookies':
|
||||||
|
return 'cookies';
|
||||||
|
case 'https://github.com/mozilla/send':
|
||||||
|
return 'github';
|
||||||
|
case 'https://twitter.com/FxTestPilot':
|
||||||
|
return 'twitter';
|
||||||
|
case 'https://www.mozilla.org/firefox/new/?scene=2':
|
||||||
|
return 'download-firefox';
|
||||||
|
default:
|
||||||
|
return 'other';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setReferrer(state) {
|
||||||
|
if (category === 'sender') {
|
||||||
|
if (state) {
|
||||||
|
storage.referrer = `${state}-upload`;
|
||||||
|
}
|
||||||
|
} else if (category === 'recipient') {
|
||||||
|
if (state) {
|
||||||
|
storage.referrer = `${state}-download`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function externalReferrer() {
|
||||||
|
if (/^https:\/\/testpilot\.firefox\.com/.test(document.referrer)) {
|
||||||
|
return 'testpilot';
|
||||||
|
}
|
||||||
|
return 'external';
|
||||||
|
}
|
||||||
|
|
||||||
|
function takeReferrer() {
|
||||||
|
const referrer = storage.referrer || externalReferrer();
|
||||||
|
storage.referrer = null;
|
||||||
|
return referrer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function startedUpload(params) {
|
||||||
|
return sendEvent(category, 'upload-started', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles + 1,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd1: params.type,
|
||||||
|
cd5: takeReferrer()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelledUpload(params) {
|
||||||
|
setReferrer('cancelled');
|
||||||
|
return sendEvent(category, 'upload-stopped', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd1: params.type,
|
||||||
|
cd2: 'cancelled'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function completedUpload(params) {
|
||||||
|
return sendEvent(category, 'upload-stopped', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm2: params.time,
|
||||||
|
cm3: params.speed,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd1: params.type,
|
||||||
|
cd2: 'completed'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startedDownload(params) {
|
||||||
|
return sendEvent(category, 'download-started', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm4: params.ttl,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function stoppedDownload(params) {
|
||||||
|
return sendEvent(category, 'download-stopped', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd2: 'errored',
|
||||||
|
cd6: params.err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelledDownload(params) {
|
||||||
|
setReferrer('cancelled');
|
||||||
|
return sendEvent(category, 'download-stopped', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd2: 'cancelled'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function stoppedUpload(params) {
|
||||||
|
return sendEvent(category, 'upload-stopped', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd1: params.type,
|
||||||
|
cd2: 'errored',
|
||||||
|
cd6: params.err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function completedDownload(params) {
|
||||||
|
return sendEvent(category, 'download-stopped', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm2: params.time,
|
||||||
|
cm3: params.speed,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd2: 'completed'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deletedUpload(params) {
|
||||||
|
return sendEvent(category, 'upload-deleted', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm2: params.time,
|
||||||
|
cm3: params.speed,
|
||||||
|
cm4: params.ttl,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.numFiles,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cd1: params.type,
|
||||||
|
cd4: params.location
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsupported(params) {
|
||||||
|
return sendEvent(category, 'unsupported', {
|
||||||
|
cd6: params.err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function copiedLink(params) {
|
||||||
|
return sendEvent(category, 'copied', {
|
||||||
|
cd4: params.location
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitEvent(target) {
|
||||||
|
return sendEvent(category, 'exited', {
|
||||||
|
cd3: urlToMetric(target.currentTarget.href)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addExitHandlers() {
|
||||||
|
const links = document.querySelectorAll('a');
|
||||||
|
links.forEach(l => {
|
||||||
|
if (/^http/.test(l.href)) {
|
||||||
|
l.addEventListener('click', exitEvent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function restartEvent(state) {
|
||||||
|
setReferrer(state);
|
||||||
|
return sendEvent(category, 'restarted', {
|
||||||
|
cd2: state
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRestartHandlers() {
|
||||||
|
const elements = document.querySelectorAll('.send-new');
|
||||||
|
elements.forEach(el => {
|
||||||
|
const state = el.getAttribute('data-state');
|
||||||
|
el.addEventListener('click', restartEvent.bind(null, state));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
copiedLink,
|
||||||
|
startedUpload,
|
||||||
|
cancelledUpload,
|
||||||
|
stoppedUpload,
|
||||||
|
completedUpload,
|
||||||
|
deletedUpload,
|
||||||
|
startedDownload,
|
||||||
|
cancelledDownload,
|
||||||
|
stoppedDownload,
|
||||||
|
completedDownload,
|
||||||
|
unsupported
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
/* global MAXFILESIZE EXPIRE_SECONDS */
|
/* global MAXFILESIZE EXPIRE_SECONDS */
|
||||||
const { Raven, findMetric, sendEvent } = require('./common');
|
const { Raven } = require('./common');
|
||||||
const FileSender = require('./fileSender');
|
const FileSender = require('./fileSender');
|
||||||
const {
|
const {
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
@ -10,17 +10,11 @@ const {
|
|||||||
const bytes = require('bytes');
|
const bytes = require('bytes');
|
||||||
const Storage = require('./storage');
|
const Storage = require('./storage');
|
||||||
const storage = new Storage(localStorage);
|
const storage = new Storage(localStorage);
|
||||||
|
const metrics = require('./metrics');
|
||||||
|
|
||||||
const $ = require('jquery');
|
const $ = require('jquery');
|
||||||
require('jquery-circle-progress');
|
require('jquery-circle-progress');
|
||||||
|
|
||||||
if (storage.has('referrer')) {
|
|
||||||
window.referrer = storage.referrer;
|
|
||||||
storage.remove('referrer');
|
|
||||||
} else {
|
|
||||||
window.referrer = 'external';
|
|
||||||
}
|
|
||||||
|
|
||||||
const allowedCopy = () => {
|
const allowedCopy = () => {
|
||||||
const support = !!document.queryCommandSupported;
|
const support = !!document.queryCommandSupported;
|
||||||
return support ? document.queryCommandSupported('copy') : false;
|
return support ? document.queryCommandSupported('copy') : false;
|
||||||
@ -28,7 +22,7 @@ const allowedCopy = () => {
|
|||||||
|
|
||||||
$(() => {
|
$(() => {
|
||||||
gcmCompliant()
|
gcmCompliant()
|
||||||
.then(function () {
|
.then(function() {
|
||||||
const $pageOne = $('#page-one');
|
const $pageOne = $('#page-one');
|
||||||
const $copyBtn = $('#copy-btn');
|
const $copyBtn = $('#copy-btn');
|
||||||
const $link = $('#link');
|
const $link = $('#link');
|
||||||
@ -42,38 +36,13 @@ $(() => {
|
|||||||
$pageOne.removeAttr('hidden');
|
$pageOne.removeAttr('hidden');
|
||||||
$('#file-upload').on('change', onUpload);
|
$('#file-upload').on('change', onUpload);
|
||||||
|
|
||||||
$('.legal-links a, .social-links a, #dl-firefox').on('click', function(target) {
|
$(document.body).on('dragover', allowDrop).on('drop', onUpload);
|
||||||
// record exited event by recipient
|
|
||||||
sendEvent('sender', 'exited', {
|
|
||||||
cd3: findMetric(target.currentTarget.href)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#send-new-completed').on('click', function() {
|
|
||||||
// record restarted event
|
|
||||||
storage.referrer = 'errored-upload';
|
|
||||||
sendEvent('sender', 'restarted', {
|
|
||||||
cd2: 'completed'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#send-new-error').on('click', function() {
|
|
||||||
// record restarted event
|
|
||||||
storage.referrer = 'errored-upload';
|
|
||||||
sendEvent('sender', 'restarted', {
|
|
||||||
cd2: 'errored'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document.body)
|
|
||||||
.on('dragover', allowDrop)
|
|
||||||
.on('drop', onUpload);
|
|
||||||
|
|
||||||
// reset copy button
|
// reset copy button
|
||||||
$copyBtn.attr({
|
$copyBtn.attr({
|
||||||
disabled: !allowedCopy(),
|
disabled: !allowedCopy(),
|
||||||
'data-l10n-id': 'copyUrlFormButton'
|
'data-l10n-id': 'copyUrlFormButton'
|
||||||
})
|
});
|
||||||
|
|
||||||
$link.attr('disabled', false);
|
$link.attr('disabled', false);
|
||||||
|
|
||||||
@ -84,7 +53,7 @@ $(() => {
|
|||||||
} else {
|
} else {
|
||||||
$fileList.removeAttr('hidden');
|
$fileList.removeAttr('hidden');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const files = storage.files;
|
const files = storage.files;
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
@ -101,10 +70,7 @@ $(() => {
|
|||||||
// copy link to clipboard
|
// copy link to clipboard
|
||||||
$copyBtn.on('click', () => {
|
$copyBtn.on('click', () => {
|
||||||
if (allowedCopy() && copyToClipboard($link.attr('value'))) {
|
if (allowedCopy() && copyToClipboard($link.attr('value'))) {
|
||||||
// record copied event from success screen
|
metrics.copiedLink({ location: 'success-screen' });
|
||||||
sendEvent('sender', 'copied', {
|
|
||||||
cd4: 'success-screen'
|
|
||||||
});
|
|
||||||
|
|
||||||
//disable button for 3s
|
//disable button for 3s
|
||||||
$copyBtn.attr('disabled', true);
|
$copyBtn.attr('disabled', true);
|
||||||
@ -122,12 +88,13 @@ $(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$uploadWindow.on('dragover', () => {
|
$uploadWindow
|
||||||
$uploadWindow.addClass('ondrag');
|
.on('dragover', () => {
|
||||||
})
|
$uploadWindow.addClass('ondrag');
|
||||||
.on('dragleave', () => {
|
})
|
||||||
$uploadWindow.removeClass('ondrag');
|
.on('dragleave', () => {
|
||||||
});
|
$uploadWindow.removeClass('ondrag');
|
||||||
|
});
|
||||||
|
|
||||||
//initiate progress bar
|
//initiate progress bar
|
||||||
$ulProgress.circleProgress({
|
$ulProgress.circleProgress({
|
||||||
@ -144,6 +111,7 @@ $(() => {
|
|||||||
// on file upload by browse or drag & drop
|
// on file upload by browse or drag & drop
|
||||||
function onUpload(event) {
|
function onUpload(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
const clickOrDrop = event.type === 'drop' ? 'drop' : 'click';
|
||||||
|
|
||||||
// don't allow upload if not on upload page
|
// don't allow upload if not on upload page
|
||||||
if ($pageOne.attr('hidden')) {
|
if ($pageOne.attr('hidden')) {
|
||||||
@ -153,7 +121,7 @@ $(() => {
|
|||||||
storage.totalUploads += 1;
|
storage.totalUploads += 1;
|
||||||
|
|
||||||
let file = '';
|
let file = '';
|
||||||
if (event.type === 'drop') {
|
if (clickOrDrop === 'drop') {
|
||||||
if (!event.originalEvent.dataTransfer.files[0]) {
|
if (!event.originalEvent.dataTransfer.files[0]) {
|
||||||
$uploadWindow.removeClass('ondrag');
|
$uploadWindow.removeClass('ondrag');
|
||||||
return;
|
return;
|
||||||
@ -193,16 +161,9 @@ $(() => {
|
|||||||
const fileSender = new FileSender(file);
|
const fileSender = new FileSender(file);
|
||||||
$('#cancel-upload').on('click', () => {
|
$('#cancel-upload').on('click', () => {
|
||||||
fileSender.cancel();
|
fileSender.cancel();
|
||||||
storage.referrer = 'cancelled-upload';
|
metrics.cancelledUpload({
|
||||||
|
size: file.size,
|
||||||
// record upload-stopped (cancelled) by sender
|
type: clickOrDrop
|
||||||
sendEvent('sender', 'upload-stopped', {
|
|
||||||
cm1: file.size,
|
|
||||||
cm5: storage.totalUploads,
|
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads,
|
|
||||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
|
||||||
cd2: 'cancelled'
|
|
||||||
});
|
});
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
@ -245,18 +206,10 @@ $(() => {
|
|||||||
|
|
||||||
let t;
|
let t;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const unexpiredFiles = storage.numFiles + 1;
|
metrics.startedUpload({
|
||||||
|
size: file.size,
|
||||||
// record upload-started event by sender
|
type: clickOrDrop
|
||||||
sendEvent('sender', 'upload-started', {
|
|
||||||
cm1: file.size,
|
|
||||||
cm5: storage.totalUploads,
|
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads,
|
|
||||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
|
||||||
cd5: window.referrer
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// For large files we need to give the ui a tick to breathe and update
|
// For large files we need to give the ui a tick to breathe and update
|
||||||
// before we kick off the FileSender
|
// before we kick off the FileSender
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -264,21 +217,16 @@ $(() => {
|
|||||||
.upload()
|
.upload()
|
||||||
.then(info => {
|
.then(info => {
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
const totalTime = endTime - startTime;
|
const time = endTime - startTime;
|
||||||
const uploadTime = endTime - uploadStart;
|
const uploadTime = endTime - uploadStart;
|
||||||
const uploadSpeed = file.size / (uploadTime / 1000);
|
const speed = file.size / (uploadTime / 1000);
|
||||||
const expiration = EXPIRE_SECONDS * 1000;
|
const expiration = EXPIRE_SECONDS * 1000;
|
||||||
|
|
||||||
// record upload-stopped (completed) by sender
|
metrics.completedUpload({
|
||||||
sendEvent('sender', 'upload-stopped', {
|
size: file.size,
|
||||||
cm1: file.size,
|
time,
|
||||||
cm2: totalTime,
|
speed,
|
||||||
cm3: uploadSpeed,
|
type: clickOrDrop
|
||||||
cm5: storage.totalUploads,
|
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads,
|
|
||||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
|
||||||
cd2: 'completed'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fileData = {
|
const fileData = {
|
||||||
@ -290,9 +238,9 @@ $(() => {
|
|||||||
deleteToken: info.deleteToken,
|
deleteToken: info.deleteToken,
|
||||||
creationDate: new Date(),
|
creationDate: new Date(),
|
||||||
expiry: expiration,
|
expiry: expiration,
|
||||||
totalTime: totalTime,
|
totalTime: time,
|
||||||
typeOfUpload: event.type === 'drop' ? 'drop' : 'click',
|
typeOfUpload: clickOrDrop,
|
||||||
uploadSpeed: uploadSpeed
|
uploadSpeed: speed
|
||||||
};
|
};
|
||||||
|
|
||||||
storage.addFile(info.fileId, fileData);
|
storage.addFile(info.fileId, fileData);
|
||||||
@ -324,15 +272,10 @@ $(() => {
|
|||||||
$uploadError.removeAttr('hidden');
|
$uploadError.removeAttr('hidden');
|
||||||
window.clearTimeout(t);
|
window.clearTimeout(t);
|
||||||
|
|
||||||
// record upload-stopped (errored) by sender
|
metrics.stoppedUpload({
|
||||||
sendEvent('sender', 'upload-stopped', {
|
size: file.size,
|
||||||
cm1: file.size,
|
type: clickOrDrop,
|
||||||
cm5: storage.totalUploads,
|
err
|
||||||
cm6: unexpiredFiles,
|
|
||||||
cm7: storage.totalDownloads,
|
|
||||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
|
||||||
cd2: 'errored',
|
|
||||||
cd6: err
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, 10);
|
}, 10);
|
||||||
@ -363,7 +306,7 @@ $(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//update file table with current files in storage
|
//update file table with current files in storage
|
||||||
const populateFileList = (file) => {
|
const populateFileList = file => {
|
||||||
const row = document.createElement('tr');
|
const row = document.createElement('tr');
|
||||||
const name = document.createElement('td');
|
const name = document.createElement('td');
|
||||||
const link = document.createElement('td');
|
const link = document.createElement('td');
|
||||||
@ -385,7 +328,7 @@ $(() => {
|
|||||||
const cellText = document.createTextNode(file.name);
|
const cellText = document.createTextNode(file.name);
|
||||||
|
|
||||||
const url = file.url.trim() + `#${file.secretKey}`.trim();
|
const url = file.url.trim() + `#${file.secretKey}`.trim();
|
||||||
|
|
||||||
$link.attr('value', url);
|
$link.attr('value', url);
|
||||||
$('#copy-text')
|
$('#copy-text')
|
||||||
.attr('data-l10n-args', `{"filename": "${file.name}"}`)
|
.attr('data-l10n-args', `{"filename": "${file.name}"}`)
|
||||||
@ -404,9 +347,7 @@ $(() => {
|
|||||||
del.appendChild(delSpan);
|
del.appendChild(delSpan);
|
||||||
|
|
||||||
const linkSpan = document.createElement('span');
|
const linkSpan = document.createElement('span');
|
||||||
$(linkSpan)
|
$(linkSpan).addClass('icon-docs').attr('data-l10n-id', 'copyUrlHover');
|
||||||
.addClass('icon-docs')
|
|
||||||
.attr('data-l10n-id', 'copyUrlHover');
|
|
||||||
|
|
||||||
link.appendChild(linkSpan);
|
link.appendChild(linkSpan);
|
||||||
link.style.color = '#0A8DFF';
|
link.style.color = '#0A8DFF';
|
||||||
@ -414,9 +355,7 @@ $(() => {
|
|||||||
//copy link to clipboard when icon clicked
|
//copy link to clipboard when icon clicked
|
||||||
$copyIcon.on('click', () => {
|
$copyIcon.on('click', () => {
|
||||||
// record copied event from upload list
|
// record copied event from upload list
|
||||||
sendEvent('sender', 'copied', {
|
metrics.copiedLink({ location: 'upload-list' });
|
||||||
cd4: 'upload-list'
|
|
||||||
});
|
|
||||||
copyToClipboard(url);
|
copyToClipboard(url);
|
||||||
document.l10n.formatValue('copiedUrl').then(translated => {
|
document.l10n.formatValue('copiedUrl').then(translated => {
|
||||||
link.innerHTML = translated;
|
link.innerHTML = translated;
|
||||||
@ -468,7 +407,7 @@ $(() => {
|
|||||||
window.clearTimeout(t);
|
window.clearTimeout(t);
|
||||||
toggleHeader();
|
toggleHeader();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
poll();
|
poll();
|
||||||
|
|
||||||
@ -496,59 +435,51 @@ $(() => {
|
|||||||
row.appendChild(del);
|
row.appendChild(del);
|
||||||
$('tbody').append(row); //add row to table
|
$('tbody').append(row); //add row to table
|
||||||
|
|
||||||
const unexpiredFiles = storage.numFiles;
|
|
||||||
|
|
||||||
// delete file
|
// delete file
|
||||||
$popupText.find('.popup-yes').on('click', e => {
|
$popupText.find('.popup-yes').on('click', e => {
|
||||||
FileSender.delete(file.fileId, file.deleteToken).then(() => {
|
FileSender.delete(file.fileId, file.deleteToken).then(() => {
|
||||||
$(e.target).parents('tr').remove();
|
$(e.target).parents('tr').remove();
|
||||||
const timeToExpiry =
|
const ttl =
|
||||||
ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
||||||
// record upload-deleted from file list
|
metrics
|
||||||
sendEvent('sender', 'upload-deleted', {
|
.deletedUpload({
|
||||||
cm1: file.size,
|
size: file.size,
|
||||||
cm2: file.totalTime,
|
time: file.totalTime,
|
||||||
cm3: file.uploadSpeed,
|
speed: file.uploadSpeed,
|
||||||
cm4: timeToExpiry,
|
type: file.typeOfUpload,
|
||||||
cm5: storage.totalUploads,
|
location: 'upload-list',
|
||||||
cm6: unexpiredFiles,
|
ttl
|
||||||
cm7: storage.totalDownloads,
|
})
|
||||||
cd1: file.typeOfUpload,
|
.then(() => {
|
||||||
cd4: 'upload-list'
|
storage.remove(file.fileId);
|
||||||
}).then(() => {
|
});
|
||||||
storage.remove(file.fileId);
|
|
||||||
});
|
|
||||||
toggleHeader();
|
toggleHeader();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#delete-file').on('click', () => {
|
$('#delete-file').on('click', () => {
|
||||||
FileSender.delete(file.fileId, file.deleteToken).then(() => {
|
FileSender.delete(file.fileId, file.deleteToken).then(() => {
|
||||||
const timeToExpiry =
|
const ttl =
|
||||||
ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
||||||
// record upload-deleted from success screen
|
metrics
|
||||||
sendEvent('sender', 'upload-deleted', {
|
.deletedUpload({
|
||||||
cm1: file.size,
|
size: file.size,
|
||||||
cm2: file.totalTime,
|
time: file.totalTime,
|
||||||
cm3: file.uploadSpeed,
|
speed: file.uploadSpeed,
|
||||||
cm4: timeToExpiry,
|
type: file.typeOfUpload,
|
||||||
cm5: storage.totalUploads,
|
location: 'success-screen',
|
||||||
cm6: unexpiredFiles,
|
ttl
|
||||||
cm7: storage.totalDownloads,
|
})
|
||||||
cd1: file.typeOfUpload,
|
.then(() => {
|
||||||
cd4: 'success-screen'
|
storage.remove(file.fileId);
|
||||||
}).then(() => {
|
location.reload();
|
||||||
storage.remove(file.fileId);
|
});
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// show popup
|
// show popup
|
||||||
$delIcon.on('click', () => {
|
$delIcon.on('click', () => {
|
||||||
$popupText
|
$popupText.addClass('show').focus();
|
||||||
.addClass('show')
|
|
||||||
.focus();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// hide popup
|
// hide popup
|
||||||
@ -567,12 +498,10 @@ $(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
toggleHeader();
|
toggleHeader();
|
||||||
}
|
};
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
sendEvent('sender', 'unsupported', {
|
metrics.unsupported({ err }).then(() => {
|
||||||
cd6: err
|
|
||||||
}).then(() => {
|
|
||||||
location.replace('/unsupported/gcm');
|
location.replace('/unsupported/gcm');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -143,12 +143,12 @@ app.get('/download/:id', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const filename = await storage.filename(id);
|
const filename = await storage.filename(id);
|
||||||
const contentLength = await storage.length(id);
|
const contentLength = await storage.length(id);
|
||||||
const timeToExpiry = await storage.ttl(id);
|
const ttl = await storage.ttl(id);
|
||||||
res.render('download', {
|
res.render('download', {
|
||||||
filename: decodeURIComponent(filename),
|
filename: decodeURIComponent(filename),
|
||||||
filesize: bytes(contentLength),
|
filesize: bytes(contentLength),
|
||||||
sizeInBytes: contentLength,
|
sizeInBytes: contentLength,
|
||||||
timeToExpiry: timeToExpiry
|
ttl
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(404).render('notfound');
|
res.status(404).render('notfound');
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
data-l10n-args='{"filename": "{{filename}}"}'></span>
|
data-l10n-args='{"filename": "{{filename}}"}'></span>
|
||||||
<span data-l10n-id="downloadFileSize"
|
<span data-l10n-id="downloadFileSize"
|
||||||
data-l10n-args='{"size": "{{filesize}}"}'></span>
|
data-l10n-args='{"size": "{{filesize}}"}'></span>
|
||||||
<span id="dl-bytelength" hidden="true">{{sizeInBytes}}</span>
|
<span id="dl-size" hidden="true">{{sizeInBytes}}</span>
|
||||||
<span id="dl-ttl" hidden="true">{{timeToExpiry}}</span>
|
<span id="dl-ttl" hidden="true">{{ttl}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="description" data-l10n-id="downloadMessage"></div>
|
<div class="description" data-l10n-id="downloadMessage"></div>
|
||||||
<img src="/resources/illustration_download.svg" id="download-img" data-l10n-id="downloadAltText"/>
|
<img src="/resources/illustration_download.svg" id="download-img" data-l10n-id="downloadAltText"/>
|
||||||
@ -35,5 +35,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="send-new" data-l10n-id="sendYourFilesLink" href="/"></a>
|
<a class="send-new" data-state="completed" data-l10n-id="sendYourFilesLink" href="/"></a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
<button id="copy-btn" data-l10n-id="copyUrlFormButton"></button>
|
<button id="copy-btn" data-l10n-id="copyUrlFormButton"></button>
|
||||||
</div>
|
</div>
|
||||||
<button id="delete-file" data-l10n-id="deleteFileButton"></button>
|
<button id="delete-file" data-l10n-id="deleteFileButton"></button>
|
||||||
<a class="send-new" id="send-new-completed" data-l10n-id="sendAnotherFileLink"></a>
|
<a class="send-new" data-state="completed" data-l10n-id="sendAnotherFileLink"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -69,5 +69,5 @@
|
|||||||
<div class="title" data-l10n-id="errorPageHeader"></div>
|
<div class="title" data-l10n-id="errorPageHeader"></div>
|
||||||
<div class="expired-description" data-l10n-id="errorPageMessage"></div>
|
<div class="expired-description" data-l10n-id="errorPageMessage"></div>
|
||||||
<img id="upload-error-img" data-l10n-id="errorAltText" src="/resources/illustration_error.svg"/>
|
<img id="upload-error-img" data-l10n-id="errorAltText" src="/resources/illustration_error.svg"/>
|
||||||
<a class="send-new" id="send-new-error" data-l10n-id="sendAnotherFileLink"></a>
|
<a class="send-new" data-state="errored" data-l10n-id="sendAnotherFileLink"></a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,5 +4,5 @@
|
|||||||
<img src="/resources/illustration_expired.svg" id="expired-img" data-l10n-id="linkExpiredAlt"/>
|
<img src="/resources/illustration_expired.svg" id="expired-img" data-l10n-id="linkExpiredAlt"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="expired-description" data-l10n-id="uploadPageExplainer"></div>
|
<div class="expired-description" data-l10n-id="uploadPageExplainer"></div>
|
||||||
<a class="send-new" href="/" id="expired-send-new" data-l10n-id="sendYourFilesLink"></a>
|
<a class="send-new" href="/" data-state="notfound" data-l10n-id="sendYourFilesLink"></a>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user