/* global MAXFILESIZE EXPIRE_SECONDS */ const { Raven, findMetric, sendEvent } = require('./common'); const FileSender = require('./fileSender'); const { copyToClipboard, notify, gcmCompliant, ONE_DAY_IN_MS } = require('./utils'); const bytes = require('bytes'); const Storage = require('./storage'); const storage = new Storage(localStorage); const $ = require('jquery'); require('jquery-circle-progress'); if (storage.has('referrer')) { window.referrer = storage.referrer; storage.remove('referrer'); } else { window.referrer = 'external'; } const allowedCopy = () => { const support = !!document.queryCommandSupported; return support ? document.queryCommandSupported('copy') : false; }; $(() => { gcmCompliant() .then(function () { const $pageOne = $('#page-one'); const $copyBtn = $('#copy-btn'); const $link = $('#link'); const $uploadWindow = $('.upload-window'); const $ulProgress = $('#ul-progress'); const $uploadError = $('#upload-error'); const $uploadProgress = $('#upload-progress'); const $progressText = $('.progress-text'); const $fileList = $('#file-list'); $pageOne.removeAttr('hidden'); $('#file-upload').on('change', onUpload); $('.legal-links a, .social-links a, #dl-firefox').on('click', function(target) { // 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 $copyBtn.attr({ disabled: !allowedCopy(), 'data-l10n-id': 'copyUrlFormButton' }) $link.attr('disabled', false); const toggleHeader = () => { //hide table header if empty list if (document.querySelector('tbody').childNodes.length === 1) { $fileList.attr('hidden', true); } else { $fileList.removeAttr('hidden'); } } const files = storage.files; if (files.length === 0) { toggleHeader(); } else { // eslint-disable-next-line prefer-const for (let index in files) { const id = files[index].fileId; //check if file still exists before adding to list checkExistence(id, files[index], true); } } // copy link to clipboard $copyBtn.on('click', () => { if (allowedCopy() && copyToClipboard($link.attr('value'))) { // record copied event from success screen sendEvent('sender', 'copied', { cd4: 'success-screen' }); //disable button for 3s $copyBtn.attr('disabled', true); $link.attr('disabled', true); $copyBtn.html( '' ); setTimeout(() => { $copyBtn.attr({ disabled: false, 'data-l10n-id': 'copyUrlFormButton' }); $link.attr('disabled', false); }, 3000); } }); $uploadWindow.on('dragover', () => { $uploadWindow.addClass('ondrag'); }) .on('dragleave', () => { $uploadWindow.removeClass('ondrag'); }); //initiate progress bar $ulProgress.circleProgress({ value: 0.0, startAngle: -Math.PI / 2, fill: '#3B9DFF', size: 158, animation: { duration: 300 } }); //link back to homepage $('.send-new').attr('href', window.location); // on file upload by browse or drag & drop function onUpload(event) { event.preventDefault(); // don't allow upload if not on upload page if ($pageOne.attr('hidden')) { return; } storage.totalUploads += 1; let file = ''; if (event.type === '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('importingFile').then(importingFile => { $progressText.text(importingFile); }); //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(); storage.referrer = 'cancelled-upload'; // record upload-stopped (cancelled) by sender 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(); }); fileSender.on('progress', progress => { const percent = progress[0] / progress[1]; // update progress bar $ulProgress.circleProgress('value', percent); $ulProgress.circleProgress().on('circle-animation-end', function() { $('.percent-number').text(`${Math.floor(percent * 100)}`); }); $progressText.text( `${file.name} (${bytes(progress[0], { decimalPlaces: 1, fixedDecimals: true })} of ${bytes(progress[1], { decimalPlaces: 1 })})` ); }); fileSender.on('hashing', isStillHashing => { // The file is being hashed if (isStillHashing) { document.l10n.formatValue('verifyingFile').then(verifyingFile => { $progressText.text(verifyingFile); }); } }); let uploadStart; fileSender.on('encrypting', isStillEncrypting => { // The file is being encrypted if (isStillEncrypting) { document.l10n.formatValue('encryptingFile').then(encryptingFile => { $progressText.text(encryptingFile); }); } else { uploadStart = Date.now(); } }); let t; const startTime = Date.now(); const unexpiredFiles = storage.numFiles + 1; // record upload-started event by sender 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 // before we kick off the FileSender setTimeout(() => { fileSender .upload() .then(info => { const endTime = Date.now(); const totalTime = endTime - startTime; const uploadTime = endTime - uploadStart; const uploadSpeed = file.size / (uploadTime / 1000); const expiration = EXPIRE_SECONDS * 1000; // record upload-stopped (completed) by sender sendEvent('sender', 'upload-stopped', { cm1: file.size, cm2: totalTime, cm3: uploadSpeed, cm5: storage.totalUploads, cm6: unexpiredFiles, cm7: storage.totalDownloads, cd1: event.type === 'drop' ? 'drop' : 'click', cd2: 'completed' }); 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: totalTime, typeOfUpload: event.type === 'drop' ? 'drop' : 'click', uploadSpeed: uploadSpeed }; storage.addFile(info.fileId, fileData); $('#upload-filename').attr( 'data-l10n-id', 'uploadSuccessConfirmHeader' ); t = window.setTimeout(() => { $pageOne.attr('hidden', true); $uploadProgress.attr('hidden', true); $uploadError.attr('hidden', true); $('#share-link').removeAttr('hidden'); }, 1000); populateFileList(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); // record upload-stopped (errored) by sender sendEvent('sender', 'upload-stopped', { cm1: file.size, cm5: storage.totalUploads, cm6: unexpiredFiles, cm7: storage.totalDownloads, cd1: event.type === 'drop' ? 'drop' : 'click', cd2: 'errored', cd6: err }); }); }, 10); } function allowDrop(ev) { ev.preventDefault(); } function checkExistence(id, file, populate) { const xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { if (populate) { populateFileList(file); } } else if (xhr.status === 404) { storage.remove(id); if (storage.numFiles === 0) { toggleHeader(); } } } }; xhr.open('get', '/exists/' + id, true); xhr.send(); } //update file table with current files in storage const populateFileList = (file) => { const row = document.createElement('tr'); const name = document.createElement('td'); const link = document.createElement('td'); const $copyIcon = $('', { 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 = $('', { src: '/resources/close-16.svg', class: 'icon-delete', 'data-l10n-id': 'deleteButtonHover' }); const popupDiv = document.createElement('div'); const $popupText = $('