Merge pull request #515 from mozilla/refactor-upload
removed jquery from upload.js
This commit is contained in:
commit
856b2cdc60
|
@ -2,17 +2,15 @@ import FileSender from './fileSender';
|
||||||
import Storage from './storage';
|
import Storage from './storage';
|
||||||
import * as metrics from './metrics';
|
import * as metrics from './metrics';
|
||||||
import { allowedCopy, copyToClipboard, ONE_DAY_IN_MS } from './utils';
|
import { allowedCopy, copyToClipboard, ONE_DAY_IN_MS } from './utils';
|
||||||
import $ from 'jquery/dist/jquery.slim';
|
import bel from 'bel';
|
||||||
|
|
||||||
|
const HOUR = 1000 * 60 * 60;
|
||||||
const storage = new Storage();
|
const storage = new Storage();
|
||||||
let fileList = null;
|
let fileList = null;
|
||||||
let $link = null;
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
$link = $('#link');
|
|
||||||
fileList = document.getElementById('file-list');
|
fileList = document.getElementById('file-list');
|
||||||
toggleHeader();
|
toggleHeader();
|
||||||
// eslint-disable-next-line prefer-const
|
|
||||||
Promise.all(
|
Promise.all(
|
||||||
storage.files.map(file => {
|
storage.files.map(file => {
|
||||||
const id = file.fileId;
|
const id = file.fileId;
|
||||||
|
@ -33,180 +31,115 @@ function toggleHeader() {
|
||||||
fileList.hidden = storage.files.length === 0;
|
fileList.hidden = storage.files.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function timeLeft(milliseconds) {
|
||||||
|
const minutes = Math.floor(milliseconds / 1000 / 60);
|
||||||
|
const hours = Math.floor(minutes / 60);
|
||||||
|
const seconds = Math.floor(milliseconds / 1000 % 60);
|
||||||
|
if (hours >= 1) {
|
||||||
|
return `${hours}h ${minutes % 60}m`;
|
||||||
|
} else if (hours === 0) {
|
||||||
|
return `${minutes}m ${seconds}s`;
|
||||||
|
}
|
||||||
|
return 'Expired';
|
||||||
|
}
|
||||||
|
|
||||||
function addFile(file) {
|
function addFile(file) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const row = document.createElement('tr');
|
|
||||||
const name = document.createElement('td');
|
|
||||||
const link = document.createElement('td');
|
|
||||||
const $copyIcon = $('<img>', {
|
|
||||||
src: '/resources/copy-16.svg',
|
|
||||||
class: 'icon-copy',
|
|
||||||
'data-l10n-id': 'copyUrlHover',
|
|
||||||
disabled: !allowedCopy()
|
|
||||||
});
|
|
||||||
const expiry = document.createElement('td');
|
|
||||||
const del = document.createElement('td');
|
|
||||||
const $delIcon = $('<img>', {
|
|
||||||
src: '/resources/close-16.svg',
|
|
||||||
class: 'icon-delete',
|
|
||||||
'data-l10n-id': 'deleteButtonHover'
|
|
||||||
});
|
|
||||||
const popupDiv = document.createElement('div');
|
|
||||||
const $popupText = $('<div>', { class: 'popuptext' });
|
|
||||||
const cellText = document.createTextNode(file.name);
|
|
||||||
|
|
||||||
const url = file.url.trim() + `#${file.secretKey}`.trim();
|
|
||||||
|
|
||||||
$link.attr('value', url);
|
|
||||||
$('#copy-text')
|
|
||||||
.attr('data-l10n-args', `{"filename": "${file.name}"}`)
|
|
||||||
.attr('data-l10n-id', 'copyUrlFormLabelWithName');
|
|
||||||
|
|
||||||
$popupText.attr('tabindex', '-1');
|
|
||||||
|
|
||||||
name.appendChild(cellText);
|
|
||||||
|
|
||||||
// create delete button
|
|
||||||
|
|
||||||
const delSpan = document.createElement('span');
|
|
||||||
$(delSpan)
|
|
||||||
.addClass('icon-cancel-1')
|
|
||||||
.attr('data-l10n-id', 'deleteButtonHover');
|
|
||||||
del.appendChild(delSpan);
|
|
||||||
|
|
||||||
const linkSpan = document.createElement('span');
|
|
||||||
$(linkSpan).addClass('icon-docs').attr('data-l10n-id', 'copyUrlHover');
|
|
||||||
|
|
||||||
link.appendChild(linkSpan);
|
|
||||||
link.style.color = '#0A8DFF';
|
|
||||||
|
|
||||||
//copy link to clipboard when icon clicked
|
|
||||||
$copyIcon.on('click', () => {
|
|
||||||
// record copied event from upload list
|
|
||||||
metrics.copiedLink({ location: 'upload-list' });
|
|
||||||
copyToClipboard(url);
|
|
||||||
document.l10n.formatValue('copiedUrl').then(translated => {
|
|
||||||
link.innerHTML = translated;
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
const linkImg = document.createElement('img');
|
|
||||||
$(linkImg)
|
|
||||||
.addClass('icon-copy')
|
|
||||||
.attr('data-l10n-id', 'copyUrlHover')
|
|
||||||
.attr('src', '/resources/copy-16.svg');
|
|
||||||
|
|
||||||
$(link).html(linkImg);
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
file.creationDate = new Date(file.creationDate);
|
file.creationDate = new Date(file.creationDate);
|
||||||
|
const url = `${file.url}#${file.secretKey}`;
|
||||||
const future = new Date();
|
const future = new Date();
|
||||||
future.setTime(file.creationDate.getTime() + file.expiry);
|
future.setTime(file.creationDate.getTime() + file.expiry);
|
||||||
|
const countdown = future.getTime() - Date.now();
|
||||||
|
|
||||||
let countdown = 0;
|
const row = bel`
|
||||||
countdown = future.getTime() - Date.now();
|
<tr>
|
||||||
let minutes = Math.floor(countdown / 1000 / 60);
|
<td>${file.name}</td>
|
||||||
let hours = Math.floor(minutes / 60);
|
<td>
|
||||||
let seconds = Math.floor(countdown / 1000 % 60);
|
<span class="icon-docs" data-l10n-id="copyUrlHover"></span>
|
||||||
|
<img onclick=${copyClick} src="/resources/copy-16.svg" class="icon-copy" data-l10n-id="copyUrlHover">
|
||||||
const poll = () => {
|
<span data-l10n-id="copiedUrl" class="text-copied" hidden="true"></span>
|
||||||
countdown = future.getTime() - Date.now();
|
</td>
|
||||||
minutes = Math.floor(countdown / 1000 / 60);
|
<td>${timeLeft(countdown)}</td>
|
||||||
hours = Math.floor(minutes / 60);
|
<td>
|
||||||
seconds = Math.floor(countdown / 1000 % 60);
|
<span class="icon-cancel-1" data-l10n-id="deleteButtonHover" title="Delete"></span>
|
||||||
let t;
|
<img onclick=${showPopup} src="/resources/close-16.svg" class="icon-delete" data-l10n-id="deleteButtonHover" title="Delete">
|
||||||
|
<div class="popup">
|
||||||
if (hours >= 1) {
|
<div class="popuptext" onclick=${stopProp} onblur=${cancel} tabindex="-1">
|
||||||
expiry.innerHTML = hours + 'h ' + minutes % 60 + 'm';
|
<div class="popup-message" data-l10n-id="deletePopupText"></div>
|
||||||
t = setTimeout(() => {
|
<div class="popup-action">
|
||||||
poll();
|
<span class="popup-no" onclick=${cancel} data-l10n-id="deletePopupCancel"></span>
|
||||||
}, 60000);
|
<span class="popup-yes" onclick=${deleteFile} data-l10n-id="deletePopupYes"></span>
|
||||||
} else if (hours === 0) {
|
</div>
|
||||||
expiry.innerHTML = minutes + 'm ' + seconds + 's';
|
</div>
|
||||||
t = window.setTimeout(() => {
|
</div>
|
||||||
poll();
|
</td>
|
||||||
}, 1000);
|
</tr>
|
||||||
}
|
`;
|
||||||
//remove from list when expired
|
const popup = row.querySelector('.popuptext');
|
||||||
if (countdown <= 0) {
|
const timeCol = row.querySelectorAll('td')[2];
|
||||||
storage.remove(file.fileId);
|
if (!allowedCopy()) {
|
||||||
$(expiry).parents('tr').remove();
|
row.querySelector('.icon-copy').disabled = true;
|
||||||
window.clearTimeout(t);
|
}
|
||||||
toggleHeader();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
fileList.querySelector('tbody').appendChild(row);
|
||||||
|
toggleHeader();
|
||||||
poll();
|
poll();
|
||||||
|
|
||||||
// create popup
|
function copyClick(e) {
|
||||||
popupDiv.classList.add('popup');
|
metrics.copiedLink({ location: 'upload-list' });
|
||||||
const $popupMessage = $('<div>', { class: 'popup-message' });
|
copyToClipboard(url);
|
||||||
$popupMessage.attr('data-l10n-id', 'deletePopupText');
|
const icon = e.target;
|
||||||
const $popupAction = $('<div>', { class: 'popup-action' });
|
const text = e.target.nextSibling;
|
||||||
const $popupNvmSpan = $('<span>', { class: 'popup-no' });
|
icon.hidden = true;
|
||||||
$popupNvmSpan.attr('data-l10n-id', 'deletePopupCancel');
|
text.hidden = false;
|
||||||
const $popupDelSpan = $('<span>', { class: 'popup-yes' });
|
setTimeout(() => {
|
||||||
$popupDelSpan.attr('data-l10n-id', 'deletePopupYes');
|
icon.hidden = false;
|
||||||
|
text.hidden = true;
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
$popupText.html([$popupMessage, $popupAction]);
|
function poll() {
|
||||||
$popupAction.html([$popupNvmSpan, $popupDelSpan]);
|
const countdown = future.getTime() - Date.now();
|
||||||
|
if (countdown <= 0) {
|
||||||
// add data cells to table row
|
storage.remove(file.fileId);
|
||||||
row.appendChild(name);
|
row.parentNode.removeChild(row);
|
||||||
$(link).append($copyIcon);
|
|
||||||
row.appendChild(link);
|
|
||||||
row.appendChild(expiry);
|
|
||||||
$(popupDiv).append($popupText);
|
|
||||||
$(del).append($delIcon);
|
|
||||||
del.appendChild(popupDiv);
|
|
||||||
row.appendChild(del);
|
|
||||||
$('tbody').append(row); //add row to table
|
|
||||||
|
|
||||||
// delete file
|
|
||||||
$popupText.find('.popup-yes').on('click', e => {
|
|
||||||
FileSender.delete(file.fileId, file.deleteToken).then(() => {
|
|
||||||
$(e.target).parents('tr').remove();
|
|
||||||
const ttl = ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
|
||||||
metrics
|
|
||||||
.deletedUpload({
|
|
||||||
size: file.size,
|
|
||||||
time: file.totalTime,
|
|
||||||
speed: file.uploadSpeed,
|
|
||||||
type: file.typeOfUpload,
|
|
||||||
location: 'upload-list',
|
|
||||||
ttl
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
storage.remove(file.fileId);
|
|
||||||
});
|
|
||||||
toggleHeader();
|
toggleHeader();
|
||||||
|
}
|
||||||
|
timeCol.textContent = timeLeft(countdown);
|
||||||
|
setTimeout(poll, countdown >= HOUR ? 60000 : 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteFile() {
|
||||||
|
FileSender.delete(file.fileId, file.deleteToken);
|
||||||
|
const ttl = ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
||||||
|
metrics.deletedUpload({
|
||||||
|
size: file.size,
|
||||||
|
time: file.totalTime,
|
||||||
|
speed: file.uploadSpeed,
|
||||||
|
type: file.typeOfUpload,
|
||||||
|
location: 'upload-list',
|
||||||
|
ttl
|
||||||
});
|
});
|
||||||
});
|
row.parentNode.removeChild(row);
|
||||||
|
storage.remove(file.fileId);
|
||||||
|
toggleHeader();
|
||||||
|
}
|
||||||
|
|
||||||
// show popup
|
function showPopup() {
|
||||||
$delIcon.on('click', () => {
|
popup.classList.add('show');
|
||||||
$popupText.addClass('show').focus();
|
popup.focus();
|
||||||
});
|
}
|
||||||
|
|
||||||
// hide popup
|
function cancel(e) {
|
||||||
$popupText.find('.popup-no').on('click', e => {
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
$popupText.removeClass('show');
|
popup.classList.remove('show');
|
||||||
});
|
}
|
||||||
|
|
||||||
$popupText.on('click', e => {
|
function stopProp(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
}
|
||||||
|
|
||||||
//close when popup loses focus
|
|
||||||
$popupText.on('blur', () => {
|
|
||||||
$popupText.removeClass('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
toggleHeader();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkExistence(id) {
|
async function checkExistence(id) {
|
||||||
|
|
|
@ -7,6 +7,14 @@ export default class FileSender extends EventEmitter {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
|
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
|
||||||
this.uploadXHR = new XMLHttpRequest();
|
this.uploadXHR = new XMLHttpRequest();
|
||||||
|
this.key = window.crypto.subtle.generateKey(
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
length: 128
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['encrypt']
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static delete(fileId, token) {
|
static delete(fileId, token) {
|
||||||
|
@ -32,87 +40,79 @@ export default class FileSender extends EventEmitter {
|
||||||
this.uploadXHR.abort();
|
this.uploadXHR.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
upload() {
|
readFile() {
|
||||||
const self = this;
|
return new Promise((resolve, reject) => {
|
||||||
self.emit('loading');
|
const reader = new FileReader();
|
||||||
return Promise.all([
|
reader.readAsArrayBuffer(this.file);
|
||||||
window.crypto.subtle.generateKey(
|
reader.onload = function(event) {
|
||||||
{
|
const plaintext = new Uint8Array(this.result);
|
||||||
name: 'AES-GCM',
|
resolve(plaintext);
|
||||||
length: 128
|
};
|
||||||
},
|
reader.onerror = function(err) {
|
||||||
true,
|
reject(err);
|
||||||
['encrypt', 'decrypt']
|
};
|
||||||
),
|
});
|
||||||
new Promise((resolve, reject) => {
|
}
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsArrayBuffer(this.file);
|
|
||||||
reader.onload = function(event) {
|
|
||||||
const plaintext = new Uint8Array(this.result);
|
|
||||||
resolve(plaintext);
|
|
||||||
};
|
|
||||||
reader.onerror = function(err) {
|
|
||||||
reject(err);
|
|
||||||
};
|
|
||||||
})
|
|
||||||
])
|
|
||||||
.then(([secretKey, plaintext]) => {
|
|
||||||
self.emit('encrypting');
|
|
||||||
return Promise.all([
|
|
||||||
window.crypto.subtle.encrypt(
|
|
||||||
{
|
|
||||||
name: 'AES-GCM',
|
|
||||||
iv: this.iv,
|
|
||||||
tagLength: 128
|
|
||||||
},
|
|
||||||
secretKey,
|
|
||||||
plaintext
|
|
||||||
),
|
|
||||||
window.crypto.subtle.exportKey('jwk', secretKey)
|
|
||||||
]);
|
|
||||||
})
|
|
||||||
.then(([encrypted, keydata]) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const file = this.file;
|
|
||||||
const fileId = arrayToHex(this.iv);
|
|
||||||
const dataView = new DataView(encrypted);
|
|
||||||
const blob = new Blob([dataView], { type: file.type });
|
|
||||||
const fd = new FormData();
|
|
||||||
fd.append('data', blob, file.name);
|
|
||||||
|
|
||||||
const xhr = self.uploadXHR;
|
uploadFile(encrypted, keydata) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const file = this.file;
|
||||||
|
const fileId = arrayToHex(this.iv);
|
||||||
|
const dataView = new DataView(encrypted);
|
||||||
|
const blob = new Blob([dataView], { type: file.type });
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('data', blob, file.name);
|
||||||
|
|
||||||
xhr.upload.addEventListener('progress', e => {
|
const xhr = this.uploadXHR;
|
||||||
if (e.lengthComputable) {
|
|
||||||
self.emit('progress', [e.loaded, e.total]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.onreadystatechange = () => {
|
xhr.upload.addEventListener('progress', e => {
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
if (e.lengthComputable) {
|
||||||
if (xhr.status === 200) {
|
this.emit('progress', [e.loaded, e.total]);
|
||||||
const responseObj = JSON.parse(xhr.responseText);
|
}
|
||||||
return resolve({
|
|
||||||
url: responseObj.url,
|
|
||||||
fileId: responseObj.id,
|
|
||||||
secretKey: keydata.k,
|
|
||||||
deleteToken: responseObj.delete
|
|
||||||
});
|
|
||||||
}
|
|
||||||
reject(xhr.status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.open('post', '/upload', true);
|
|
||||||
xhr.setRequestHeader(
|
|
||||||
'X-File-Metadata',
|
|
||||||
JSON.stringify({
|
|
||||||
id: fileId,
|
|
||||||
filename: encodeURIComponent(file.name)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
xhr.send(fd);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
const responseObj = JSON.parse(xhr.responseText);
|
||||||
|
return resolve({
|
||||||
|
url: responseObj.url,
|
||||||
|
fileId: responseObj.id,
|
||||||
|
secretKey: keydata.k,
|
||||||
|
deleteToken: responseObj.delete
|
||||||
|
});
|
||||||
|
}
|
||||||
|
reject(xhr.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.open('post', '/upload', true);
|
||||||
|
xhr.setRequestHeader(
|
||||||
|
'X-File-Metadata',
|
||||||
|
JSON.stringify({
|
||||||
|
id: fileId,
|
||||||
|
filename: encodeURIComponent(file.name)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
xhr.send(fd);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async upload() {
|
||||||
|
this.emit('loading');
|
||||||
|
const key = await this.key;
|
||||||
|
const plaintext = await this.readFile();
|
||||||
|
this.emit('encrypting');
|
||||||
|
const encrypted = await window.crypto.subtle.encrypt(
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
iv: this.iv,
|
||||||
|
tagLength: 128
|
||||||
|
},
|
||||||
|
key,
|
||||||
|
plaintext
|
||||||
|
);
|
||||||
|
const keydata = await window.crypto.subtle.exportKey('jwk', key);
|
||||||
|
return this.uploadFile(encrypted, keydata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,6 +310,10 @@ tbody {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-copied {
|
||||||
|
color: #0a8dff;
|
||||||
|
}
|
||||||
|
|
||||||
/* Popup container */
|
/* Popup container */
|
||||||
.popup {
|
.popup {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -13,236 +13,230 @@ import Storage from './storage';
|
||||||
import * as metrics from './metrics';
|
import * as metrics from './metrics';
|
||||||
import * as progress from './progress';
|
import * as progress from './progress';
|
||||||
import * as fileList from './fileList';
|
import * as fileList from './fileList';
|
||||||
import $ from 'jquery/dist/jquery.slim';
|
|
||||||
|
|
||||||
const storage = new Storage();
|
const storage = new Storage();
|
||||||
|
|
||||||
$(() => {
|
async function upload(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const pageOne = document.getElementById('page-one');
|
||||||
|
const link = document.getElementById('link');
|
||||||
|
const uploadWindow = document.querySelector('.upload-window');
|
||||||
|
const uploadError = document.getElementById('upload-error');
|
||||||
|
const uploadProgress = document.getElementById('upload-progress');
|
||||||
|
const clickOrDrop = event.type === 'drop' ? 'drop' : 'click';
|
||||||
|
|
||||||
|
// don't allow upload if not on upload page
|
||||||
|
if (pageOne.hidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.totalUploads += 1;
|
||||||
|
|
||||||
|
let file = '';
|
||||||
|
if (clickOrDrop === 'drop') {
|
||||||
|
if (!event.originalEvent.dataTransfer.files[0]) {
|
||||||
|
uploadWindow.classList.remove('ondrag');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
event.originalEvent.dataTransfer.files.length > 1 ||
|
||||||
|
event.originalEvent.dataTransfer.files[0].size === 0
|
||||||
|
) {
|
||||||
|
uploadWindow.classList.remove('ondrag');
|
||||||
|
document.l10n.formatValue('uploadPageMultipleFilesAlert').then(str => {
|
||||||
|
alert(str);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file = event.originalEvent.dataTransfer.files[0];
|
||||||
|
} else {
|
||||||
|
file = event.target.files[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.size > MAXFILESIZE) {
|
||||||
|
return document.l10n
|
||||||
|
.formatValue('fileTooBig', { size: bytes(MAXFILESIZE) })
|
||||||
|
.then(alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOne.hidden = true;
|
||||||
|
uploadError.hidden = true;
|
||||||
|
uploadProgress.hidden = false;
|
||||||
|
document.l10n
|
||||||
|
.formatValue('uploadingPageProgress', {
|
||||||
|
size: bytes(file.size),
|
||||||
|
filename: file.name
|
||||||
|
})
|
||||||
|
.then(str => {
|
||||||
|
document.getElementById('upload-filename').textContent = str;
|
||||||
|
});
|
||||||
|
document.l10n.formatValue('importingFile').then(progress.setText);
|
||||||
|
//don't allow drag and drop when not on page-one
|
||||||
|
document.body.removeEventListener('drop', upload);
|
||||||
|
|
||||||
|
const fileSender = new FileSender(file);
|
||||||
|
document.getElementById('cancel-upload').addEventListener('click', () => {
|
||||||
|
fileSender.cancel();
|
||||||
|
metrics.cancelledUpload({
|
||||||
|
size: file.size,
|
||||||
|
type: clickOrDrop
|
||||||
|
});
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
|
||||||
|
let uploadStart;
|
||||||
|
fileSender.on('progress', data => {
|
||||||
|
uploadStart = uploadStart || Date.now();
|
||||||
|
progress.setProgress({
|
||||||
|
complete: data[0],
|
||||||
|
total: data[1]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fileSender.on('encrypting', () => {
|
||||||
|
document.l10n.formatValue('encryptingFile').then(progress.setText);
|
||||||
|
});
|
||||||
|
|
||||||
|
let t;
|
||||||
|
const startTime = Date.now();
|
||||||
|
metrics.startedUpload({
|
||||||
|
size: file.size,
|
||||||
|
type: clickOrDrop
|
||||||
|
});
|
||||||
|
// For large files we need to give the ui a tick to breathe and update
|
||||||
|
// before we kick off the FileSender
|
||||||
|
setTimeout(() => {
|
||||||
|
fileSender
|
||||||
|
.upload()
|
||||||
|
.then(info => {
|
||||||
|
const endTime = Date.now();
|
||||||
|
const time = endTime - startTime;
|
||||||
|
const uploadTime = endTime - uploadStart;
|
||||||
|
const speed = file.size / (uploadTime / 1000);
|
||||||
|
const expiration = EXPIRE_SECONDS * 1000;
|
||||||
|
|
||||||
|
link.setAttribute('value', `${info.url}#${info.secretKey}`);
|
||||||
|
|
||||||
|
metrics.completedUpload({
|
||||||
|
size: file.size,
|
||||||
|
time,
|
||||||
|
speed,
|
||||||
|
type: clickOrDrop
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileData = {
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
fileId: info.fileId,
|
||||||
|
url: info.url,
|
||||||
|
secretKey: info.secretKey,
|
||||||
|
deleteToken: info.deleteToken,
|
||||||
|
creationDate: new Date(),
|
||||||
|
expiry: expiration,
|
||||||
|
totalTime: time,
|
||||||
|
typeOfUpload: clickOrDrop,
|
||||||
|
uploadSpeed: speed
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('delete-file').addEventListener('click', () => {
|
||||||
|
FileSender.delete(fileData.fileId, fileData.deleteToken).then(() => {
|
||||||
|
const ttl =
|
||||||
|
ONE_DAY_IN_MS - (Date.now() - fileData.creationDate.getTime());
|
||||||
|
metrics
|
||||||
|
.deletedUpload({
|
||||||
|
size: fileData.size,
|
||||||
|
time: fileData.totalTime,
|
||||||
|
speed: fileData.uploadSpeed,
|
||||||
|
type: fileData.typeOfUpload,
|
||||||
|
location: 'success-screen',
|
||||||
|
ttl
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
storage.remove(fileData.fileId);
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
storage.addFile(info.fileId, fileData);
|
||||||
|
|
||||||
|
pageOne.hidden = true;
|
||||||
|
uploadProgress.hidden = true;
|
||||||
|
uploadError.hidden = true;
|
||||||
|
document.getElementById('share-link').hidden = false;
|
||||||
|
|
||||||
|
fileList.addFile(fileData);
|
||||||
|
document.l10n.formatValue('notifyUploadDone').then(str => {
|
||||||
|
notify(str);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// err is 0 when coming from a cancel upload event
|
||||||
|
if (err === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// only show error page when the error is anything other than user cancelling the upload
|
||||||
|
Raven.captureException(err);
|
||||||
|
pageOne.hidden = true;
|
||||||
|
uploadProgress.hidden = true;
|
||||||
|
uploadError.hidden = false;
|
||||||
|
window.clearTimeout(t);
|
||||||
|
|
||||||
|
metrics.stoppedUpload({
|
||||||
|
size: file.size,
|
||||||
|
type: clickOrDrop,
|
||||||
|
err
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
gcmCompliant()
|
gcmCompliant()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
const $pageOne = $('#page-one');
|
const pageOne = document.getElementById('page-one');
|
||||||
const $copyBtn = $('#copy-btn');
|
const copyBtn = document.getElementById('copy-btn');
|
||||||
const $link = $('#link');
|
const link = document.getElementById('link');
|
||||||
const $uploadWindow = $('.upload-window');
|
const uploadWindow = document.querySelector('.upload-window');
|
||||||
const $uploadError = $('#upload-error');
|
|
||||||
const $uploadProgress = $('#upload-progress');
|
|
||||||
|
|
||||||
$pageOne.removeAttr('hidden');
|
pageOne.hidden = false;
|
||||||
$('#file-upload').on('change', onUpload);
|
document.getElementById('file-upload').addEventListener('change', upload);
|
||||||
|
|
||||||
$(document.body).on('dragover', allowDrop).on('drop', onUpload);
|
document.body.addEventListener('dragover', allowDrop);
|
||||||
|
document.body.addEventListener('drop', upload);
|
||||||
|
|
||||||
// reset copy button
|
// reset copy button
|
||||||
$copyBtn.attr({
|
copyBtn.disabled = !allowedCopy();
|
||||||
disabled: !allowedCopy(),
|
copyBtn.setAttribute('data-l10n-id', 'copyUrlFormButton');
|
||||||
'data-l10n-id': 'copyUrlFormButton'
|
|
||||||
});
|
|
||||||
|
|
||||||
$link.attr('disabled', false);
|
link.disabled = false;
|
||||||
|
|
||||||
// copy link to clipboard
|
// copy link to clipboard
|
||||||
$copyBtn.on('click', () => {
|
copyBtn.addEventListener('click', () => {
|
||||||
if (allowedCopy() && copyToClipboard($link.attr('value'))) {
|
if (allowedCopy() && copyToClipboard(link.getAttribute('value'))) {
|
||||||
metrics.copiedLink({ location: 'success-screen' });
|
metrics.copiedLink({ location: 'success-screen' });
|
||||||
|
|
||||||
//disable button for 3s
|
//disable button for 3s
|
||||||
$copyBtn.attr('disabled', true);
|
copyBtn.disabled = true;
|
||||||
$link.attr('disabled', true);
|
link.disabled = true;
|
||||||
$copyBtn.html(
|
copyBtn.innerHtml =
|
||||||
'<img src="/resources/check-16.svg" class="icon-check"></img>'
|
'<img src="/resources/check-16.svg" class="icon-check"></img>';
|
||||||
);
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
$copyBtn.attr({
|
copyBtn.disabled = !allowedCopy();
|
||||||
disabled: false,
|
copyBtn.setAttribute('data-l10n-id', 'copyUrlFormButton');
|
||||||
'data-l10n-id': 'copyUrlFormButton'
|
link.disabled = false;
|
||||||
});
|
|
||||||
$link.attr('disabled', false);
|
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$uploadWindow
|
uploadWindow.addEventListener('dragover', () =>
|
||||||
.on('dragover', () => {
|
uploadWindow.classList.add('ondrag')
|
||||||
$uploadWindow.addClass('ondrag');
|
);
|
||||||
})
|
uploadWindow.addEventListener('dragleave', () =>
|
||||||
.on('dragleave', () => {
|
uploadWindow.classList.remove('ondrag')
|
||||||
$uploadWindow.removeClass('ondrag');
|
);
|
||||||
});
|
|
||||||
|
|
||||||
// on file upload by browse or drag & drop
|
// on file upload by browse or drag & drop
|
||||||
function onUpload(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const clickOrDrop = event.type === 'drop' ? 'drop' : 'click';
|
|
||||||
|
|
||||||
// don't allow upload if not on upload page
|
|
||||||
if ($pageOne.attr('hidden')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
storage.totalUploads += 1;
|
|
||||||
|
|
||||||
let file = '';
|
|
||||||
if (clickOrDrop === 'drop') {
|
|
||||||
if (!event.originalEvent.dataTransfer.files[0]) {
|
|
||||||
$uploadWindow.removeClass('ondrag');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
event.originalEvent.dataTransfer.files.length > 1 ||
|
|
||||||
event.originalEvent.dataTransfer.files[0].size === 0
|
|
||||||
) {
|
|
||||||
$uploadWindow.removeClass('ondrag');
|
|
||||||
document.l10n
|
|
||||||
.formatValue('uploadPageMultipleFilesAlert')
|
|
||||||
.then(str => {
|
|
||||||
alert(str);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file = event.originalEvent.dataTransfer.files[0];
|
|
||||||
} else {
|
|
||||||
file = event.target.files[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file.size > MAXFILESIZE) {
|
|
||||||
return document.l10n
|
|
||||||
.formatValue('fileTooBig', { size: bytes(MAXFILESIZE) })
|
|
||||||
.then(alert);
|
|
||||||
}
|
|
||||||
|
|
||||||
$pageOne.attr('hidden', true);
|
|
||||||
$uploadError.attr('hidden', true);
|
|
||||||
$uploadProgress.removeAttr('hidden');
|
|
||||||
document.l10n
|
|
||||||
.formatValue('uploadingPageProgress', {
|
|
||||||
size: bytes(file.size),
|
|
||||||
filename: file.name
|
|
||||||
})
|
|
||||||
.then(str => {
|
|
||||||
$('#upload-filename').text(str);
|
|
||||||
});
|
|
||||||
document.l10n.formatValue('importingFile').then(progress.setText);
|
|
||||||
//don't allow drag and drop when not on page-one
|
|
||||||
$(document.body).off('drop', onUpload);
|
|
||||||
|
|
||||||
const fileSender = new FileSender(file);
|
|
||||||
$('#cancel-upload').on('click', () => {
|
|
||||||
fileSender.cancel();
|
|
||||||
metrics.cancelledUpload({
|
|
||||||
size: file.size,
|
|
||||||
type: clickOrDrop
|
|
||||||
});
|
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
|
|
||||||
let uploadStart;
|
|
||||||
fileSender.on('progress', data => {
|
|
||||||
uploadStart = uploadStart || Date.now();
|
|
||||||
progress.setProgress({
|
|
||||||
complete: data[0],
|
|
||||||
total: data[1]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fileSender.on('encrypting', () => {
|
|
||||||
document.l10n.formatValue('encryptingFile').then(progress.setText);
|
|
||||||
});
|
|
||||||
|
|
||||||
let t;
|
|
||||||
const startTime = Date.now();
|
|
||||||
metrics.startedUpload({
|
|
||||||
size: file.size,
|
|
||||||
type: clickOrDrop
|
|
||||||
});
|
|
||||||
// For large files we need to give the ui a tick to breathe and update
|
|
||||||
// before we kick off the FileSender
|
|
||||||
setTimeout(() => {
|
|
||||||
fileSender
|
|
||||||
.upload()
|
|
||||||
.then(info => {
|
|
||||||
const endTime = Date.now();
|
|
||||||
const time = endTime - startTime;
|
|
||||||
const uploadTime = endTime - uploadStart;
|
|
||||||
const speed = file.size / (uploadTime / 1000);
|
|
||||||
const expiration = EXPIRE_SECONDS * 1000;
|
|
||||||
|
|
||||||
metrics.completedUpload({
|
|
||||||
size: file.size,
|
|
||||||
time,
|
|
||||||
speed,
|
|
||||||
type: clickOrDrop
|
|
||||||
});
|
|
||||||
|
|
||||||
const fileData = {
|
|
||||||
name: file.name,
|
|
||||||
size: file.size,
|
|
||||||
fileId: info.fileId,
|
|
||||||
url: info.url,
|
|
||||||
secretKey: info.secretKey,
|
|
||||||
deleteToken: info.deleteToken,
|
|
||||||
creationDate: new Date(),
|
|
||||||
expiry: expiration,
|
|
||||||
totalTime: time,
|
|
||||||
typeOfUpload: clickOrDrop,
|
|
||||||
uploadSpeed: speed
|
|
||||||
};
|
|
||||||
|
|
||||||
$('#delete-file').on('click', () => {
|
|
||||||
FileSender.delete(
|
|
||||||
fileData.fileId,
|
|
||||||
fileData.deleteToken
|
|
||||||
).then(() => {
|
|
||||||
const ttl =
|
|
||||||
ONE_DAY_IN_MS -
|
|
||||||
(Date.now() - fileData.creationDate.getTime());
|
|
||||||
metrics
|
|
||||||
.deletedUpload({
|
|
||||||
size: fileData.size,
|
|
||||||
time: fileData.totalTime,
|
|
||||||
speed: fileData.uploadSpeed,
|
|
||||||
type: fileData.typeOfUpload,
|
|
||||||
location: 'success-screen',
|
|
||||||
ttl
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
storage.remove(fileData.fileId);
|
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
storage.addFile(info.fileId, fileData);
|
|
||||||
|
|
||||||
$pageOne.attr('hidden', true);
|
|
||||||
$uploadProgress.attr('hidden', true);
|
|
||||||
$uploadError.attr('hidden', true);
|
|
||||||
$('#share-link').removeAttr('hidden');
|
|
||||||
|
|
||||||
fileList.addFile(fileData);
|
|
||||||
document.l10n.formatValue('notifyUploadDone').then(str => {
|
|
||||||
notify(str);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
// err is 0 when coming from a cancel upload event
|
|
||||||
if (err === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// only show error page when the error is anything other than user cancelling the upload
|
|
||||||
Raven.captureException(err);
|
|
||||||
$pageOne.attr('hidden', true);
|
|
||||||
$uploadProgress.attr('hidden', true);
|
|
||||||
$uploadError.removeAttr('hidden');
|
|
||||||
window.clearTimeout(t);
|
|
||||||
|
|
||||||
metrics.stoppedUpload({
|
|
||||||
size: file.size,
|
|
||||||
type: clickOrDrop,
|
|
||||||
err
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function allowDrop(ev) {
|
function allowDrop(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
|
@ -291,9 +291,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aws-sdk": {
|
"aws-sdk": {
|
||||||
"version": "2.95.0",
|
"version": "2.98.0",
|
||||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.95.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.98.0.tgz",
|
||||||
"integrity": "sha1-JuIdsUlEOx8GOUnch5hPDRdwDmo=",
|
"integrity": "sha1-kK0CPXM4ndFex736+TLsq2VEVxE=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"buffer": "4.9.1",
|
"buffer": "4.9.1",
|
||||||
"crypto-browserify": "1.0.9",
|
"crypto-browserify": "1.0.9",
|
||||||
|
@ -1086,6 +1086,17 @@
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
||||||
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="
|
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="
|
||||||
},
|
},
|
||||||
|
"bel": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/bel/-/bel-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-bMLvUOrKBM2zWp3Ab6UugjCjFmsZtIeKH3oMNWaUr9RA94sNeicajzptZHQWU3K8KNIL8o6JwAmKG1W3mUiwXw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"hyperx": "2.3.0",
|
||||||
|
"is-electron": "2.1.0",
|
||||||
|
"pelo": "0.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"big.js": {
|
"big.js": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz",
|
||||||
|
@ -2330,7 +2341,7 @@
|
||||||
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
|
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"es5-ext": "0.10.26"
|
"es5-ext": "0.10.27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dasherize": {
|
"dasherize": {
|
||||||
|
@ -2640,12 +2651,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dom-walk": {
|
|
||||||
"version": "0.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
|
|
||||||
"integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"domain-browser": {
|
"domain-browser": {
|
||||||
"version": "1.1.7",
|
"version": "1.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
|
||||||
|
@ -2801,9 +2806,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es5-ext": {
|
"es5-ext": {
|
||||||
"version": "0.10.26",
|
"version": "0.10.27",
|
||||||
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.26.tgz",
|
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.27.tgz",
|
||||||
"integrity": "sha1-UbISilMbcMT2dkCTpzy+u4IYY3I=",
|
"integrity": "sha512-3KXJRYzKXTd7xfFy5uZsJCXue55fAYQ035PRjyYk2PicllxIwcW9l3AbM/eGaw3vgVAUW4tl4xg9AXDEI6yw0w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"es6-iterator": "2.0.1",
|
"es6-iterator": "2.0.1",
|
||||||
|
@ -2817,7 +2822,7 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"d": "1.0.0",
|
"d": "1.0.0",
|
||||||
"es5-ext": "0.10.26",
|
"es5-ext": "0.10.27",
|
||||||
"es6-symbol": "3.1.1"
|
"es6-symbol": "3.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2828,7 +2833,7 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"d": "1.0.0",
|
"d": "1.0.0",
|
||||||
"es5-ext": "0.10.26",
|
"es5-ext": "0.10.27",
|
||||||
"es6-iterator": "2.0.1",
|
"es6-iterator": "2.0.1",
|
||||||
"es6-set": "0.1.5",
|
"es6-set": "0.1.5",
|
||||||
"es6-symbol": "3.1.1",
|
"es6-symbol": "3.1.1",
|
||||||
|
@ -2848,7 +2853,7 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"d": "1.0.0",
|
"d": "1.0.0",
|
||||||
"es5-ext": "0.10.26",
|
"es5-ext": "0.10.27",
|
||||||
"es6-iterator": "2.0.1",
|
"es6-iterator": "2.0.1",
|
||||||
"es6-symbol": "3.1.1",
|
"es6-symbol": "3.1.1",
|
||||||
"event-emitter": "0.3.5"
|
"event-emitter": "0.3.5"
|
||||||
|
@ -2861,7 +2866,7 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"d": "1.0.0",
|
"d": "1.0.0",
|
||||||
"es5-ext": "0.10.26"
|
"es5-ext": "0.10.27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es6-weak-map": {
|
"es6-weak-map": {
|
||||||
|
@ -2871,7 +2876,7 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"d": "1.0.0",
|
"d": "1.0.0",
|
||||||
"es5-ext": "0.10.26",
|
"es5-ext": "0.10.27",
|
||||||
"es6-iterator": "2.0.1",
|
"es6-iterator": "2.0.1",
|
||||||
"es6-symbol": "3.1.1"
|
"es6-symbol": "3.1.1"
|
||||||
}
|
}
|
||||||
|
@ -3142,7 +3147,7 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"d": "1.0.0",
|
"d": "1.0.0",
|
||||||
"es5-ext": "0.10.26"
|
"es5-ext": "0.10.27"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"event-stream": {
|
"event-stream": {
|
||||||
|
@ -4520,24 +4525,6 @@
|
||||||
"is-glob": "2.0.1"
|
"is-glob": "2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"global": {
|
|
||||||
"version": "4.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
|
|
||||||
"integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"min-document": "2.19.0",
|
|
||||||
"process": "0.5.2"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"process": {
|
|
||||||
"version": "0.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
|
|
||||||
"integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"globals": {
|
"globals": {
|
||||||
"version": "9.18.0",
|
"version": "9.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
|
||||||
|
@ -4784,6 +4771,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hyperscript-attribute-to-property": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hyperscript-attribute-to-property/-/hyperscript-attribute-to-property-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-glMI1Ju44pV5I/cxmBvMgRytev8=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"hyperx": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hyperx/-/hyperx-2.3.0.tgz",
|
||||||
|
"integrity": "sha1-cPRz1m1K1VDd0cg+S+JlEna78eI=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"hyperscript-attribute-to-property": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.4.15",
|
"version": "0.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz",
|
||||||
|
@ -5064,6 +5066,12 @@
|
||||||
"integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
|
"integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"is-electron": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-dkg5xT383+M6zIbbXW/z7n2nz4SFUi2OSyhntnFYkRdtV+HVEfdjEK+5AWisfYgkpe3WYjTIuh7toaKmSfFVWw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"is-equal-shallow": {
|
"is-equal-shallow": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
|
||||||
|
@ -5260,12 +5268,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
|
||||||
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
|
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
|
||||||
},
|
},
|
||||||
"jquery": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz",
|
|
||||||
"integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"js-base64": {
|
"js-base64": {
|
||||||
"version": "2.1.9",
|
"version": "2.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz",
|
||||||
|
@ -6324,15 +6326,6 @@
|
||||||
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=",
|
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"min-document": {
|
|
||||||
"version": "2.19.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
|
|
||||||
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"dom-walk": "0.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"minimalistic-assert": {
|
"minimalistic-assert": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
|
||||||
|
@ -6574,7 +6567,7 @@
|
||||||
"stream-browserify": "2.0.1",
|
"stream-browserify": "2.0.1",
|
||||||
"stream-http": "2.7.2",
|
"stream-http": "2.7.2",
|
||||||
"string_decoder": "0.10.31",
|
"string_decoder": "0.10.31",
|
||||||
"timers-browserify": "2.0.3",
|
"timers-browserify": "2.0.4",
|
||||||
"tty-browserify": "0.0.0",
|
"tty-browserify": "0.0.0",
|
||||||
"url": "0.11.0",
|
"url": "0.11.0",
|
||||||
"util": "0.10.3",
|
"util": "0.10.3",
|
||||||
|
@ -6638,12 +6631,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"timers-browserify": {
|
"timers-browserify": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz",
|
||||||
"integrity": "sha512-+JAqyNgg+M8+gXIrq2EeUr4kZqRz47Ysco7X5QKRGScRE9HIHckyHD1asozSFGeqx2nmPCgA8T5tIGVO0ML7/w==",
|
"integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"global": "4.3.2",
|
|
||||||
"setimmediate": "1.0.5"
|
"setimmediate": "1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7046,6 +7038,12 @@
|
||||||
"sha.js": "2.4.8"
|
"sha.js": "2.4.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pelo": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/pelo/-/pelo-0.0.3.tgz",
|
||||||
|
"integrity": "sha1-+2smsGEgNtsCuRj+qrPowMTLWXw=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||||
|
@ -10560,9 +10558,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"webpack": {
|
"webpack": {
|
||||||
"version": "3.5.2",
|
"version": "3.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-3.5.4.tgz",
|
||||||
"integrity": "sha1-qWAQZuI688gPO/l1j9eUypd48lE=",
|
"integrity": "sha1-VYPrJj7Se3i1vRe/37DrGxzRv4E=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"acorn": "5.1.1",
|
"acorn": "5.1.1",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"author": "Mozilla (https://mozilla.org)",
|
"author": "Mozilla (https://mozilla.org)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-sdk": "^2.95.0",
|
"aws-sdk": "^2.98.0",
|
||||||
"body-parser": "^1.17.2",
|
"body-parser": "^1.17.2",
|
||||||
"connect-busboy": "0.0.2",
|
"connect-busboy": "0.0.2",
|
||||||
"convict": "^3.0.0",
|
"convict": "^3.0.0",
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
"babel-polyfill": "^6.23.0",
|
"babel-polyfill": "^6.23.0",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-stage-2": "^6.24.1",
|
"babel-preset-stage-2": "^6.24.1",
|
||||||
|
"bel": "^5.0.3",
|
||||||
"browserify": "^14.4.0",
|
"browserify": "^14.4.0",
|
||||||
"cross-env": "^5.0.5",
|
"cross-env": "^5.0.5",
|
||||||
"css-mqpacker": "^6.0.1",
|
"css-mqpacker": "^6.0.1",
|
||||||
|
@ -33,7 +34,6 @@
|
||||||
"eslint-plugin-security": "^1.4.0",
|
"eslint-plugin-security": "^1.4.0",
|
||||||
"git-rev-sync": "^1.9.1",
|
"git-rev-sync": "^1.9.1",
|
||||||
"husky": "^0.14.3",
|
"husky": "^0.14.3",
|
||||||
"jquery": "^3.2.1",
|
|
||||||
"l20n": "^5.0.0",
|
"l20n": "^5.0.0",
|
||||||
"lint-staged": "^4.0.3",
|
"lint-staged": "^4.0.3",
|
||||||
"mocha": "^3.4.2",
|
"mocha": "^3.4.2",
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
"supertest": "^3.0.0",
|
"supertest": "^3.0.0",
|
||||||
"testpilot-ga": "^0.3.0",
|
"testpilot-ga": "^0.3.0",
|
||||||
"webcrypto-liner": "^0.1.25",
|
"webcrypto-liner": "^0.1.25",
|
||||||
"webpack": "^3.5.2",
|
"webpack": "^3.5.4",
|
||||||
"webpack-dev-middleware": "^1.12.0"
|
"webpack-dev-middleware": "^1.12.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -11,15 +11,15 @@ module.exports = {
|
||||||
publicPath: '/'
|
publicPath: '/'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
loaders: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
include: [
|
include: [
|
||||||
path.resolve(__dirname, 'frontend'),
|
path.resolve(__dirname, 'frontend'),
|
||||||
path.resolve(__dirname, 'node_modules/testpilot-ga/src')
|
path.resolve(__dirname, 'node_modules/testpilot-ga/src')
|
||||||
],
|
],
|
||||||
query: {
|
options: {
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
presets: [['es2015', { modules: false }], 'stage-2']
|
presets: [['es2015', { modules: false }], 'stage-2']
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue