mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-07 22:50:53 +03:00
Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bf8481fd0 | ||
|
|
ae0758ac14 | ||
|
|
e9405f49ee | ||
|
|
a1d0eef8a5 | ||
|
|
254b806fb4 | ||
|
|
a7aee1450f | ||
|
|
fa5573a5ff | ||
|
|
9714bb0a0a | ||
|
|
ad82d30dd9 | ||
|
|
757ac14d1a | ||
|
|
3e066258c4 | ||
|
|
127f73b4fe | ||
|
|
ae5009e1e3 | ||
|
|
0ab8ddc894 | ||
|
|
b429841534 | ||
|
|
279f6df6f4 | ||
|
|
634e6b2834 | ||
|
|
856b2cdc60 | ||
|
|
41351f877c | ||
|
|
afbb89fbe8 | ||
|
|
b40b45273d | ||
|
|
f1fb877c7f | ||
|
|
9d7ad06b1a | ||
|
|
c6a4b089d9 | ||
|
|
24917f8aa5 | ||
|
|
eada94b262 | ||
|
|
43fa551a64 | ||
|
|
e1137db946 | ||
|
|
c1878649b3 | ||
|
|
30b86b14ed | ||
|
|
e91b341f8a | ||
|
|
70148232c6 | ||
|
|
56e3d5766c | ||
|
|
350e31ae4a | ||
|
|
0794bcc458 | ||
|
|
a6aee8ad62 | ||
|
|
8305d13dab | ||
|
|
441a520765 | ||
|
|
ba84e59f39 | ||
|
|
22a316ab58 | ||
|
|
6b9502d252 | ||
|
|
cdc3a5340d | ||
|
|
f03f7a0286 | ||
|
|
d8a5789701 | ||
|
|
8d26e0e742 | ||
|
|
e142d76cb4 | ||
|
|
c488c1d724 | ||
|
|
bed57af6c5 | ||
|
|
7500bd8326 | ||
|
|
0250924961 | ||
|
|
70813556ad | ||
|
|
2bb9af1943 | ||
|
|
55bd44a8f5 | ||
|
|
d83900f272 | ||
|
|
fa4f9299b2 | ||
|
|
0f7b19c385 | ||
|
|
a9c1dd0180 | ||
|
|
c468e2f34e | ||
|
|
718f42897f | ||
|
|
fb468bd1bc | ||
|
|
dafe00cabb | ||
|
|
98aebb7f70 | ||
|
|
a990d78bc0 | ||
|
|
9b4069be3e | ||
|
|
ff3bc0dd62 | ||
|
|
b39b131928 | ||
|
|
2646fb9b3c | ||
|
|
c2b84650e2 | ||
|
|
fecf938ae7 | ||
|
|
8abf631430 | ||
|
|
d69c535dda | ||
|
|
082ca6c57b | ||
|
|
b263231068 | ||
|
|
947a6d9992 | ||
|
|
1ad7edf5a9 | ||
|
|
0c26204ea1 | ||
|
|
1e3bbee7f1 | ||
|
|
ec80e8e622 | ||
|
|
61e2c0d85b | ||
|
|
80db74fc3a | ||
|
|
30936eb2fa | ||
|
|
31e29d58b9 | ||
|
|
702134b3b1 | ||
|
|
11ae7f857c | ||
|
|
8827556974 | ||
|
|
21b7f16b1e | ||
|
|
314ab237ec | ||
|
|
0fa0416c3f | ||
|
|
09faedf059 | ||
|
|
16aa7983ed | ||
|
|
493bf8dc89 | ||
|
|
46432b9649 | ||
|
|
193664a8e8 | ||
|
|
626e578acb | ||
|
|
51bffe11a8 | ||
|
|
08e2c6c112 | ||
|
|
c38d91db98 | ||
|
|
c13839a522 | ||
|
|
4894d5162f | ||
|
|
77b6fb138f | ||
|
|
9dab74891d | ||
|
|
393d2a0052 | ||
|
|
44ac783f6a | ||
|
|
7ea8712538 | ||
|
|
fb92a793e4 | ||
|
|
87eaba6337 | ||
|
|
7e13f2ab32 | ||
|
|
3214d293ca | ||
|
|
1437116cf3 | ||
|
|
740001ddde | ||
|
|
24af3207e9 | ||
|
|
38746078ed | ||
|
|
fcea981127 |
@@ -6,3 +6,7 @@ test
|
|||||||
scripts
|
scripts
|
||||||
docs
|
docs
|
||||||
firefox
|
firefox
|
||||||
|
public
|
||||||
|
views
|
||||||
|
webpack
|
||||||
|
frontend
|
||||||
|
|||||||
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{js,html,yml,json,handlebars}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.toml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,10 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
|
dist
|
||||||
node_modules
|
node_modules
|
||||||
public/upload.js
|
|
||||||
public/download.js
|
|
||||||
public/version.json
|
|
||||||
public/l20n.min.js
|
|
||||||
public/polyfill.min.js
|
|
||||||
static/*
|
static/*
|
||||||
!static/info.txt
|
!static/info.txt
|
||||||
test/frontend/bundle.js
|
test/frontend/bundle.js
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
extends: stylelint-config-standard
|
extends: stylelint-config-standard
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- stylelint-no-unsupported-browser-features
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
|
plugin/no-unsupported-browser-features: [true, {severity: warning}]
|
||||||
|
|
||||||
color-hex-case: lower
|
color-hex-case: lower
|
||||||
declaration-colon-newline-after: null
|
declaration-colon-newline-after: null
|
||||||
selector-list-comma-newline-after: null
|
selector-list-comma-newline-after: null
|
||||||
|
|||||||
5
browserslist
Normal file
5
browserslist
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
last 2 chrome versions
|
||||||
|
last 2 firefox versions
|
||||||
|
firefox esr
|
||||||
|
ie >= 9
|
||||||
|
safari >= 9
|
||||||
@@ -16,7 +16,6 @@ deployment:
|
|||||||
latest:
|
latest:
|
||||||
branch: master
|
branch: master
|
||||||
commands:
|
commands:
|
||||||
- npm run build
|
|
||||||
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
- docker build -t mozilla/send:latest .
|
- docker build -t mozilla/send:latest .
|
||||||
- docker push mozilla/send:latest
|
- docker push mozilla/send:latest
|
||||||
@@ -24,14 +23,13 @@ deployment:
|
|||||||
tag: /.*/
|
tag: /.*/
|
||||||
owner: mozilla
|
owner: mozilla
|
||||||
commands:
|
commands:
|
||||||
- npm run build
|
|
||||||
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
- docker build -t mozilla/send:$CIRCLE_TAG .
|
- docker build -t mozilla/send:$CIRCLE_TAG .
|
||||||
- docker push mozilla/send:$CIRCLE_TAG
|
- docker push mozilla/send:$CIRCLE_TAG
|
||||||
|
|
||||||
test:
|
test:
|
||||||
override:
|
override:
|
||||||
- npm run build:version
|
- npm run build
|
||||||
- npm run lint
|
- npm run lint
|
||||||
- npm test
|
- npm test
|
||||||
- nsp check
|
- nsp check
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ services:
|
|||||||
- "1443:1443"
|
- "1443:1443"
|
||||||
environment:
|
environment:
|
||||||
- REDIS_HOST=redis
|
- REDIS_HOST=redis
|
||||||
|
- NODE_ENV=production
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
env:
|
env:
|
||||||
browser: true
|
browser: true
|
||||||
jquery: true
|
node: false
|
||||||
|
|
||||||
|
parserOptions:
|
||||||
|
sourceType: module
|
||||||
|
|
||||||
|
rules:
|
||||||
|
node/no-unsupported-features: off
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const Raven = require('raven-js');
|
import Raven from 'raven-js';
|
||||||
const { unsupported } = require('./metrics');
|
import { unsupported } from './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();
|
||||||
@@ -17,6 +17,4 @@ if (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export { Raven };
|
||||||
Raven
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,30 +1,33 @@
|
|||||||
const { Raven } = require('./common');
|
import { Raven } from './common';
|
||||||
const FileReceiver = require('./fileReceiver');
|
import FileReceiver from './fileReceiver';
|
||||||
const { bytes, notify, gcmCompliant } = require('./utils');
|
import { bytes, notify, gcmCompliant } from './utils';
|
||||||
const Storage = require('./storage');
|
import Storage from './storage';
|
||||||
const storage = new Storage(localStorage);
|
import * as links from './links';
|
||||||
const links = require('./links');
|
import * as metrics from './metrics';
|
||||||
const metrics = require('./metrics');
|
import * as progress from './progress';
|
||||||
const progress = require('./progress');
|
|
||||||
const $ = require('jquery');
|
|
||||||
|
|
||||||
|
const storage = new Storage();
|
||||||
function onUnload(size) {
|
function onUnload(size) {
|
||||||
metrics.cancelledDownload({ size });
|
metrics.cancelledDownload({ size });
|
||||||
}
|
}
|
||||||
|
|
||||||
function download() {
|
async function download() {
|
||||||
const $downloadBtn = $('#download-btn');
|
const downloadBtn = document.getElementById('download-btn');
|
||||||
const $title = $('.title');
|
const downloadPanel = document.getElementById('download-page-one');
|
||||||
const $file = $('#dl-file');
|
const progressPanel = document.getElementById('download-progress');
|
||||||
const size = Number($file.attr('data-size'));
|
const file = document.getElementById('dl-file');
|
||||||
const ttl = Number($file.attr('data-ttl'));
|
const size = Number(file.getAttribute('data-size'));
|
||||||
|
const ttl = Number(file.getAttribute('data-ttl'));
|
||||||
const unloadHandler = onUnload.bind(null, size);
|
const unloadHandler = onUnload.bind(null, size);
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const fileReceiver = new FileReceiver();
|
const fileReceiver = new FileReceiver(
|
||||||
|
'/assets' + location.pathname.slice(0, -1),
|
||||||
|
location.hash.slice(1)
|
||||||
|
);
|
||||||
|
|
||||||
$downloadBtn.attr('disabled', 'disabled');
|
downloadBtn.disabled = true;
|
||||||
$('#download-page-one').attr('hidden', true);
|
downloadPanel.hidden = true;
|
||||||
$('#download-progress').removeAttr('hidden');
|
progressPanel.hidden = false;
|
||||||
metrics.startedDownload({ size, ttl });
|
metrics.startedDownload({ size, ttl });
|
||||||
links.setOpenInNewTab(true);
|
links.setOpenInNewTab(true);
|
||||||
window.addEventListener('unload', unloadHandler);
|
window.addEventListener('unload', unloadHandler);
|
||||||
@@ -41,74 +44,72 @@ function download() {
|
|||||||
document.l10n.formatValue('decryptingFile').then(progress.setText);
|
document.l10n.formatValue('decryptingFile').then(progress.setText);
|
||||||
});
|
});
|
||||||
|
|
||||||
fileReceiver
|
try {
|
||||||
.download()
|
const file = await fileReceiver.download();
|
||||||
.catch(err => {
|
const endTime = Date.now();
|
||||||
metrics.stoppedDownload({ size, err });
|
const time = endTime - startTime;
|
||||||
|
const downloadTime = endTime - downloadEnd;
|
||||||
|
const speed = size / (downloadTime / 1000);
|
||||||
|
|
||||||
if (err.message === 'notfound') {
|
links.setOpenInNewTab(false);
|
||||||
location.reload();
|
storage.totalDownloads += 1;
|
||||||
} else {
|
metrics.completedDownload({ size, time, speed });
|
||||||
document.l10n.formatValue('errorPageHeader').then(translated => {
|
progress.setText(' ');
|
||||||
$title.text(translated);
|
document.l10n
|
||||||
});
|
.formatValues('downloadNotification', 'downloadFinish')
|
||||||
$downloadBtn.attr('hidden', true);
|
.then(translated => {
|
||||||
$('#expired-img').removeAttr('hidden');
|
notify(translated[0]);
|
||||||
}
|
document.getElementById('dl-title').textContent = translated[1];
|
||||||
throw err;
|
document.querySelector('#download-progress .description').textContent =
|
||||||
})
|
' ';
|
||||||
.then(([decrypted, fname]) => {
|
});
|
||||||
const endTime = Date.now();
|
const dataView = new DataView(file.plaintext);
|
||||||
const time = endTime - startTime;
|
const blob = new Blob([dataView], { type: file.type });
|
||||||
const downloadTime = endTime - downloadEnd;
|
const downloadUrl = URL.createObjectURL(blob);
|
||||||
const speed = size / (downloadTime / 1000);
|
|
||||||
storage.totalDownloads += 1;
|
|
||||||
metrics.completedDownload({ size, time, speed });
|
|
||||||
progress.setText(' ');
|
|
||||||
document.l10n
|
|
||||||
.formatValues('downloadNotification', 'downloadFinish')
|
|
||||||
.then(translated => {
|
|
||||||
notify(translated[0]);
|
|
||||||
$title.text(translated[1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const dataView = new DataView(decrypted);
|
const a = document.createElement('a');
|
||||||
const blob = new Blob([dataView]);
|
a.href = downloadUrl;
|
||||||
const downloadUrl = URL.createObjectURL(blob);
|
if (window.navigator.msSaveBlob) {
|
||||||
|
window.navigator.msSaveBlob(blob, file.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a.download = file.name;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(downloadUrl);
|
||||||
|
} catch (err) {
|
||||||
|
metrics.stoppedDownload({ size, err });
|
||||||
|
|
||||||
const a = document.createElement('a');
|
if (err.message === 'notfound') {
|
||||||
a.href = downloadUrl;
|
location.reload();
|
||||||
if (window.navigator.msSaveBlob) {
|
} else {
|
||||||
// if we are in microsoft edge or IE
|
progressPanel.hidden = true;
|
||||||
window.navigator.msSaveBlob(blob, fname);
|
downloadPanel.hidden = true;
|
||||||
return;
|
document.getElementById('upload-error').hidden = false;
|
||||||
}
|
}
|
||||||
a.download = fname;
|
Raven.captureException(err);
|
||||||
document.body.appendChild(a);
|
}
|
||||||
a.click();
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
Raven.captureException(err);
|
|
||||||
return Promise.reject(err);
|
|
||||||
})
|
|
||||||
.then(() => links.setOpenInNewTab(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$(() => {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const $file = $('#dl-file');
|
const file = document.getElementById('dl-file');
|
||||||
const filename = $file.attr('data-filename');
|
const filename = file.getAttribute('data-filename');
|
||||||
const b = Number($file.attr('data-size'));
|
const b = Number(file.getAttribute('data-size'));
|
||||||
const size = bytes(b);
|
const size = bytes(b);
|
||||||
document.l10n
|
document.l10n.formatValue('downloadFileSize', { size }).then(str => {
|
||||||
.formatValue('downloadFileSize', { size })
|
document.getElementById('dl-filesize').textContent = str;
|
||||||
.then(str => $('#dl-filesize').text(str));
|
});
|
||||||
document.l10n
|
document.l10n
|
||||||
.formatValue('downloadingPageProgress', { filename, size })
|
.formatValue('downloadingPageProgress', { filename, size })
|
||||||
.then(str => $('#dl-title').text(str));
|
.then(str => {
|
||||||
|
document.getElementById('dl-title').textContent = str;
|
||||||
|
});
|
||||||
|
|
||||||
gcmCompliant()
|
gcmCompliant()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
$('#download-btn').on('click', download);
|
document
|
||||||
|
.getElementById('download-btn')
|
||||||
|
.addEventListener('click', download);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
metrics.unsupported({ err }).then(() => {
|
metrics.unsupported({ err }).then(() => {
|
||||||
|
|||||||
163
frontend/src/fileList.js
Normal file
163
frontend/src/fileList.js
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
import FileSender from './fileSender';
|
||||||
|
import Storage from './storage';
|
||||||
|
import * as metrics from './metrics';
|
||||||
|
import { allowedCopy, copyToClipboard, ONE_DAY_IN_MS } from './utils';
|
||||||
|
import bel from 'bel';
|
||||||
|
import copyImg from '../../public/resources/copy-16.svg';
|
||||||
|
import closeImg from '../../public/resources/close-16.svg';
|
||||||
|
|
||||||
|
const HOUR = 1000 * 60 * 60;
|
||||||
|
const storage = new Storage();
|
||||||
|
let fileList = null;
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
fileList = document.getElementById('file-list');
|
||||||
|
toggleHeader();
|
||||||
|
Promise.all(
|
||||||
|
storage.files.map(file => {
|
||||||
|
const id = file.fileId;
|
||||||
|
return checkExistence(id).then(exists => {
|
||||||
|
if (exists) {
|
||||||
|
addFile(storage.getFileById(id));
|
||||||
|
} else {
|
||||||
|
storage.remove(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.catch(err => console.error(err))
|
||||||
|
.then(toggleHeader);
|
||||||
|
});
|
||||||
|
|
||||||
|
function toggleHeader() {
|
||||||
|
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) {
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file.creationDate = new Date(file.creationDate);
|
||||||
|
const url = `${file.url}#${file.secretKey}`;
|
||||||
|
const future = new Date();
|
||||||
|
future.setTime(file.creationDate.getTime() + file.expiry);
|
||||||
|
const countdown = future.getTime() - Date.now();
|
||||||
|
|
||||||
|
const row = bel`
|
||||||
|
<tr>
|
||||||
|
<td>${file.name}</td>
|
||||||
|
<td>
|
||||||
|
<span class="icon-docs" data-l10n-id="copyUrlHover"></span>
|
||||||
|
<img onclick=${copyClick} src="${copyImg}" class="icon-copy" data-l10n-id="copyUrlHover">
|
||||||
|
<span data-l10n-id="copiedUrl" class="text-copied" hidden="true"></span>
|
||||||
|
</td>
|
||||||
|
<td>${timeLeft(countdown)}</td>
|
||||||
|
<td>
|
||||||
|
<span class="icon-cancel-1" data-l10n-id="deleteButtonHover" title="Delete"></span>
|
||||||
|
<img onclick=${showPopup} src="${closeImg}" class="icon-delete" data-l10n-id="deleteButtonHover" title="Delete">
|
||||||
|
<div class="popup">
|
||||||
|
<div class="popuptext" onclick=${stopProp} onblur=${cancel} tabindex="-1">
|
||||||
|
<div class="popup-message" data-l10n-id="deletePopupText"></div>
|
||||||
|
<div class="popup-action">
|
||||||
|
<span class="popup-no" onclick=${cancel} data-l10n-id="deletePopupCancel"></span>
|
||||||
|
<span class="popup-yes" onclick=${deleteFile} data-l10n-id="deletePopupYes"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
const popup = row.querySelector('.popuptext');
|
||||||
|
const timeCol = row.querySelectorAll('td')[2];
|
||||||
|
if (!allowedCopy()) {
|
||||||
|
row.querySelector('.icon-copy').disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileList.querySelector('tbody').appendChild(row);
|
||||||
|
toggleHeader();
|
||||||
|
poll();
|
||||||
|
|
||||||
|
function copyClick(e) {
|
||||||
|
metrics.copiedLink({ location: 'upload-list' });
|
||||||
|
copyToClipboard(url);
|
||||||
|
const icon = e.target;
|
||||||
|
const text = e.target.nextSibling;
|
||||||
|
icon.hidden = true;
|
||||||
|
text.hidden = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
icon.hidden = false;
|
||||||
|
text.hidden = true;
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function poll() {
|
||||||
|
const countdown = future.getTime() - Date.now();
|
||||||
|
if (countdown <= 0) {
|
||||||
|
storage.remove(file.fileId);
|
||||||
|
row.parentNode.removeChild(row);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPopup() {
|
||||||
|
popup.classList.add('show');
|
||||||
|
popup.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
popup.classList.remove('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopProp(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkExistence(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
|
||||||
|
resolve(xhr.status === 200);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.onerror = reject;
|
||||||
|
xhr.ontimeout = reject;
|
||||||
|
xhr.open('get', '/exists/' + id);
|
||||||
|
xhr.timeout = 2000;
|
||||||
|
xhr.send();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { addFile };
|
||||||
@@ -1,85 +1,80 @@
|
|||||||
const EventEmitter = require('events');
|
import EventEmitter from 'events';
|
||||||
const { hexToArray } = require('./utils');
|
import { hexToArray } from './utils';
|
||||||
|
|
||||||
class FileReceiver extends EventEmitter {
|
export default class FileReceiver extends EventEmitter {
|
||||||
constructor() {
|
constructor(url, k) {
|
||||||
super();
|
super();
|
||||||
|
this.key = window.crypto.subtle.importKey(
|
||||||
|
'jwk',
|
||||||
|
{
|
||||||
|
k,
|
||||||
|
kty: 'oct',
|
||||||
|
alg: 'A128GCM',
|
||||||
|
ext: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'AES-GCM'
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['decrypt']
|
||||||
|
);
|
||||||
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
download() {
|
downloadFile() {
|
||||||
return window.crypto.subtle
|
return new Promise((resolve, reject) => {
|
||||||
.importKey(
|
const xhr = new XMLHttpRequest();
|
||||||
'jwk',
|
|
||||||
{
|
|
||||||
kty: 'oct',
|
|
||||||
k: location.hash.slice(1),
|
|
||||||
alg: 'A128GCM',
|
|
||||||
ext: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'AES-GCM'
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['encrypt', 'decrypt']
|
|
||||||
)
|
|
||||||
.then(key => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
|
|
||||||
xhr.onprogress = event => {
|
xhr.onprogress = event => {
|
||||||
if (event.lengthComputable && event.target.status !== 404) {
|
if (event.lengthComputable && event.target.status !== 404) {
|
||||||
this.emit('progress', [event.loaded, event.total]);
|
this.emit('progress', [event.loaded, event.total]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onload = function(event) {
|
xhr.onload = function(event) {
|
||||||
if (xhr.status === 404) {
|
if (xhr.status === 404) {
|
||||||
reject(new Error('notfound'));
|
reject(new Error('notfound'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const blob = new Blob([this.response]);
|
const blob = new Blob([this.response]);
|
||||||
const fileReader = new FileReader();
|
const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
|
||||||
fileReader.onload = function() {
|
const fileReader = new FileReader();
|
||||||
const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
|
fileReader.onload = function() {
|
||||||
resolve([
|
resolve({
|
||||||
{
|
data: this.result,
|
||||||
data: this.result,
|
name: meta.filename,
|
||||||
filename: meta.filename,
|
type: meta.mimeType,
|
||||||
iv: meta.id
|
iv: meta.id
|
||||||
},
|
});
|
||||||
key
|
};
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
fileReader.readAsArrayBuffer(blob);
|
fileReader.readAsArrayBuffer(blob);
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.open('get', '/assets' + location.pathname.slice(0, -1), true);
|
xhr.open('get', this.url);
|
||||||
xhr.responseType = 'blob';
|
xhr.responseType = 'blob';
|
||||||
xhr.send();
|
xhr.send();
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
.then(([fdata, key]) => {
|
|
||||||
this.emit('decrypting');
|
async download() {
|
||||||
return Promise.all([
|
const key = await this.key;
|
||||||
window.crypto.subtle
|
const file = await this.downloadFile();
|
||||||
.decrypt(
|
this.emit('decrypting');
|
||||||
{
|
const plaintext = await window.crypto.subtle.decrypt(
|
||||||
name: 'AES-GCM',
|
{
|
||||||
iv: hexToArray(fdata.iv),
|
name: 'AES-GCM',
|
||||||
tagLength: 128
|
iv: hexToArray(file.iv),
|
||||||
},
|
tagLength: 128
|
||||||
key,
|
},
|
||||||
fdata.data
|
key,
|
||||||
)
|
file.data
|
||||||
.then(decrypted => {
|
);
|
||||||
return Promise.resolve(decrypted);
|
return {
|
||||||
}),
|
plaintext,
|
||||||
decodeURIComponent(fdata.filename)
|
name: decodeURIComponent(file.name),
|
||||||
]);
|
type: file.type
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FileReceiver;
|
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
const EventEmitter = require('events');
|
import EventEmitter from 'events';
|
||||||
const { arrayToHex } = require('./utils');
|
import { arrayToHex } from './utils';
|
||||||
|
|
||||||
class FileSender extends EventEmitter {
|
export default class FileSender extends EventEmitter {
|
||||||
constructor(file) {
|
constructor(file) {
|
||||||
super();
|
super();
|
||||||
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,89 +40,79 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FileSender;
|
|
||||||
|
|||||||
@@ -18,6 +18,4 @@ function setOpenInNewTab(bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export { setOpenInNewTab };
|
||||||
setOpenInNewTab
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*** index.html ***/
|
/*** index.html ***/
|
||||||
html {
|
html {
|
||||||
background: url('resources/send_bg.svg');
|
background: url('../../public/resources/send_bg.svg');
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'segoe ui',
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'segoe ui',
|
||||||
'helvetica neue', helvetica, ubuntu, roboto, noto, arial, sans-serif;
|
'helvetica neue', helvetica, ubuntu, roboto, noto, arial, sans-serif;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
@@ -22,6 +22,16 @@ body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#progress circle {
|
||||||
|
stroke: #eee;
|
||||||
|
stroke-width: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#progress #bar {
|
||||||
|
transition: stroke-dashoffset 300ms linear;
|
||||||
|
stroke: #3b9dff;
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -79,7 +89,7 @@ body {
|
|||||||
|
|
||||||
.feedback {
|
.feedback {
|
||||||
background-color: #0297f8;
|
background-color: #0297f8;
|
||||||
background-image: url('resources/feedback.svg');
|
background-image: url('../../public/resources/feedback.svg');
|
||||||
background-position: 2px 4px;
|
background-position: 2px 4px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 18px;
|
background-size: 18px;
|
||||||
@@ -138,6 +148,10 @@ a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
/** page-one **/
|
/** page-one **/
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
@@ -208,12 +222,13 @@ a {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
width: 240px;
|
min-width: 240px;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#browse:hover {
|
#browse:hover {
|
||||||
@@ -295,6 +310,10 @@ tbody {
|
|||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-copied {
|
||||||
|
color: #0a8dff;
|
||||||
|
}
|
||||||
|
|
||||||
/* Popup container */
|
/* Popup container */
|
||||||
.popup {
|
.popup {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -415,7 +434,7 @@ tbody {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
letter-spacing: -0.78px;
|
letter-spacing: -0.78px;
|
||||||
font-family: 'Segoe UI', 'SF Pro Text', sans-serif;
|
font-family: 'Segoe UI', 'SF Pro Text', sans-serif;
|
||||||
top: 53px;
|
top: 58px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
@@ -644,7 +663,6 @@ tbody {
|
|||||||
background: #0297f8;
|
background: #0297f8;
|
||||||
border: 1px solid #0297f8;
|
border: 1px solid #0297f8;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
font-weight: 300;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
const testPilotGA = require('testpilot-ga/src/TestPilotGA');
|
import testPilotGA from 'testpilot-ga/src/TestPilotGA';
|
||||||
const Storage = require('./storage');
|
import Storage from './storage';
|
||||||
const storage = new Storage(localStorage);
|
const storage = new Storage();
|
||||||
|
|
||||||
|
let hasLocalStorage = false;
|
||||||
|
try {
|
||||||
|
hasLocalStorage = !!localStorage;
|
||||||
|
} catch (e) {
|
||||||
|
// don't care
|
||||||
|
}
|
||||||
|
|
||||||
const analytics = new testPilotGA({
|
const analytics = new testPilotGA({
|
||||||
an: 'Firefox Send',
|
an: 'Firefox Send',
|
||||||
@@ -18,7 +25,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function sendEvent() {
|
function sendEvent() {
|
||||||
return analytics.sendEvent.apply(analytics, arguments).catch(() => 0);
|
return (
|
||||||
|
hasLocalStorage &&
|
||||||
|
analytics.sendEvent.apply(analytics, arguments).catch(() => 0)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function urlToMetric(url) {
|
function urlToMetric(url) {
|
||||||
@@ -41,6 +51,11 @@ function urlToMetric(url) {
|
|||||||
return 'twitter';
|
return 'twitter';
|
||||||
case 'https://www.mozilla.org/firefox/new/?scene=2':
|
case 'https://www.mozilla.org/firefox/new/?scene=2':
|
||||||
return 'download-firefox';
|
return 'download-firefox';
|
||||||
|
case 'https://qsurvey.mozilla.com/s3/txp-firefox-send':
|
||||||
|
return 'survey';
|
||||||
|
case 'https://testpilot.firefox.com/':
|
||||||
|
case 'https://testpilot.firefox.com/experiments/send':
|
||||||
|
return 'testpilot';
|
||||||
default:
|
default:
|
||||||
return 'other';
|
return 'other';
|
||||||
}
|
}
|
||||||
@@ -198,7 +213,7 @@ function exitEvent(target) {
|
|||||||
function addExitHandlers() {
|
function addExitHandlers() {
|
||||||
const links = Array.from(document.querySelectorAll('a'));
|
const links = Array.from(document.querySelectorAll('a'));
|
||||||
links.forEach(l => {
|
links.forEach(l => {
|
||||||
if (/^http/.test(l.href)) {
|
if (/^http/.test(l.getAttribute('href'))) {
|
||||||
l.addEventListener('click', exitEvent);
|
l.addEventListener('click', exitEvent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -219,7 +234,7 @@ function addRestartHandlers() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
copiedLink,
|
copiedLink,
|
||||||
startedUpload,
|
startedUpload,
|
||||||
cancelledUpload,
|
cancelledUpload,
|
||||||
|
|||||||
@@ -1,28 +1,37 @@
|
|||||||
const { bytes } = require('./utils');
|
import { bytes, percent } from './utils';
|
||||||
const $ = require('jquery');
|
|
||||||
require('jquery-circle-progress');
|
|
||||||
|
|
||||||
let $progress = null;
|
let percentText = null;
|
||||||
let $percent = null;
|
let text = null;
|
||||||
let $text = null;
|
let title = null;
|
||||||
|
let bar = null;
|
||||||
|
let updateTitle = false;
|
||||||
|
|
||||||
|
const radius = 73;
|
||||||
|
const circumference = 2 * Math.PI * radius;
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
$percent = $('.percent-number');
|
percentText = document.querySelector('.percent-number');
|
||||||
$text = $('.progress-text');
|
text = document.querySelector('.progress-text');
|
||||||
$progress = $('.progress-bar');
|
bar = document.getElementById('bar');
|
||||||
$progress.circleProgress({
|
title = document.querySelector('title');
|
||||||
value: 0.0,
|
});
|
||||||
startAngle: -Math.PI / 2,
|
|
||||||
fill: '#3B9DFF',
|
document.addEventListener('blur', function() {
|
||||||
size: 158,
|
updateTitle = true;
|
||||||
animation: { duration: 300 }
|
});
|
||||||
});
|
|
||||||
|
document.addEventListener('focus', function() {
|
||||||
|
updateTitle = false;
|
||||||
|
return title && (title.textContent = 'Firefox Send');
|
||||||
});
|
});
|
||||||
|
|
||||||
function setProgress(params) {
|
function setProgress(params) {
|
||||||
const percent = params.complete / params.total;
|
const ratio = params.complete / params.total;
|
||||||
$progress.circleProgress('value', percent);
|
bar.setAttribute('stroke-dashoffset', (1 - ratio) * circumference);
|
||||||
$percent.text(`${Math.floor(percent * 100)}`);
|
percentText.textContent = Math.floor(ratio * 100);
|
||||||
|
if (updateTitle) {
|
||||||
|
title.textContent = percent(ratio);
|
||||||
|
}
|
||||||
document.l10n
|
document.l10n
|
||||||
.formatValue('fileSizeProgress', {
|
.formatValue('fileSizeProgress', {
|
||||||
partialSize: bytes(params.complete),
|
partialSize: bytes(params.complete),
|
||||||
@@ -32,10 +41,7 @@ function setProgress(params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setText(str) {
|
function setText(str) {
|
||||||
$text.text(str);
|
text.textContent = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export { setProgress, setText };
|
||||||
setProgress,
|
|
||||||
setText
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,8 +1,38 @@
|
|||||||
const { isFile } = require('./utils');
|
import { isFile } from './utils';
|
||||||
|
|
||||||
class Storage {
|
class Mem {
|
||||||
constructor(engine) {
|
constructor() {
|
||||||
this.engine = engine;
|
this.items = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
get length() {
|
||||||
|
return this.items.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(key) {
|
||||||
|
return this.items.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
setItem(key, value) {
|
||||||
|
return this.items.set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem(key) {
|
||||||
|
return this.items.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
key(i) {
|
||||||
|
return this.items.keys()[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Storage {
|
||||||
|
constructor() {
|
||||||
|
try {
|
||||||
|
this.engine = localStorage || new Mem();
|
||||||
|
} catch (e) {
|
||||||
|
this.engine = new Mem();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get totalDownloads() {
|
get totalDownloads() {
|
||||||
@@ -56,11 +86,11 @@ class Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFileById(id) {
|
getFileById(id) {
|
||||||
return this.engine.getItem(id);
|
try {
|
||||||
}
|
return JSON.parse(this.engine.getItem(id));
|
||||||
|
} catch (e) {
|
||||||
has(property) {
|
return null;
|
||||||
return this.engine.hasOwnProperty(property);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(property) {
|
remove(property) {
|
||||||
@@ -71,5 +101,3 @@ class Storage {
|
|||||||
this.engine.setItem(id, JSON.stringify(file));
|
this.engine.setItem(id, JSON.stringify(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Storage;
|
|
||||||
|
|||||||
@@ -1,472 +1,253 @@
|
|||||||
/* global MAXFILESIZE EXPIRE_SECONDS */
|
/* global MAXFILESIZE EXPIRE_SECONDS */
|
||||||
const { Raven } = require('./common');
|
import { Raven } from './common';
|
||||||
const FileSender = require('./fileSender');
|
import FileSender from './fileSender';
|
||||||
const {
|
import {
|
||||||
|
allowedCopy,
|
||||||
bytes,
|
bytes,
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
notify,
|
notify,
|
||||||
gcmCompliant,
|
gcmCompliant,
|
||||||
ONE_DAY_IN_MS
|
ONE_DAY_IN_MS
|
||||||
} = require('./utils');
|
} from './utils';
|
||||||
const Storage = require('./storage');
|
import Storage from './storage';
|
||||||
const storage = new Storage(localStorage);
|
import * as metrics from './metrics';
|
||||||
const metrics = require('./metrics');
|
import * as progress from './progress';
|
||||||
const progress = require('./progress');
|
import * as fileList from './fileList';
|
||||||
|
import checkImg from '../../public/resources/check-16.svg';
|
||||||
|
|
||||||
const $ = require('jquery');
|
const storage = new Storage();
|
||||||
|
|
||||||
const allowedCopy = () => {
|
async function upload(event) {
|
||||||
const support = !!document.queryCommandSupported;
|
event.preventDefault();
|
||||||
return support ? document.queryCommandSupported('copy') : false;
|
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.dataTransfer.files[0]) {
|
||||||
|
uploadWindow.classList.remove('ondrag');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
event.dataTransfer.files.length > 1 ||
|
||||||
|
event.dataTransfer.files[0].size === 0
|
||||||
|
) {
|
||||||
|
uploadWindow.classList.remove('ondrag');
|
||||||
|
document.l10n.formatValue('uploadPageMultipleFilesAlert').then(str => {
|
||||||
|
alert(str);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
file = event.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}`);
|
||||||
|
|
||||||
|
const copyText = document.getElementById('copy-text');
|
||||||
|
copyText.setAttribute(
|
||||||
|
'data-l10n-args',
|
||||||
|
JSON.stringify({ filename: file.name })
|
||||||
|
);
|
||||||
|
copyText.setAttribute('data-l10n-id', 'copyUrlFormLabelWithName');
|
||||||
|
|
||||||
|
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');
|
|
||||||
const $fileList = $('#file-list');
|
|
||||||
|
|
||||||
$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;
|
||||||
|
|
||||||
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
|
// 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="${checkImg}" 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');
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
metrics.stoppedUpload({
|
|
||||||
size: file.size,
|
|
||||||
type: clickOrDrop,
|
|
||||||
err
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function allowDrop(ev) {
|
function allowDrop(ev) {
|
||||||
ev.preventDefault();
|
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 = $('<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', JSON.stringify({ 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);
|
|
||||||
|
|
||||||
const future = new Date();
|
|
||||||
future.setTime(file.creationDate.getTime() + file.expiry);
|
|
||||||
|
|
||||||
let countdown = 0;
|
|
||||||
countdown = future.getTime() - Date.now();
|
|
||||||
let minutes = Math.floor(countdown / 1000 / 60);
|
|
||||||
let hours = Math.floor(minutes / 60);
|
|
||||||
let seconds = Math.floor(countdown / 1000 % 60);
|
|
||||||
|
|
||||||
const poll = () => {
|
|
||||||
countdown = future.getTime() - Date.now();
|
|
||||||
minutes = Math.floor(countdown / 1000 / 60);
|
|
||||||
hours = Math.floor(minutes / 60);
|
|
||||||
seconds = Math.floor(countdown / 1000 % 60);
|
|
||||||
let t;
|
|
||||||
|
|
||||||
if (hours >= 1) {
|
|
||||||
expiry.innerHTML = hours + 'h ' + minutes % 60 + 'm';
|
|
||||||
t = setTimeout(() => {
|
|
||||||
poll();
|
|
||||||
}, 60000);
|
|
||||||
} else if (hours === 0) {
|
|
||||||
expiry.innerHTML = minutes + 'm ' + seconds + 's';
|
|
||||||
t = window.setTimeout(() => {
|
|
||||||
poll();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
//remove from list when expired
|
|
||||||
if (countdown <= 0) {
|
|
||||||
storage.remove(file.fileId);
|
|
||||||
$(expiry).parents('tr').remove();
|
|
||||||
window.clearTimeout(t);
|
|
||||||
toggleHeader();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
poll();
|
|
||||||
|
|
||||||
// create popup
|
|
||||||
popupDiv.classList.add('popup');
|
|
||||||
const $popupMessage = $('<div>', { class: 'popup-message' });
|
|
||||||
$popupMessage.attr('data-l10n-id', 'deletePopupText');
|
|
||||||
const $popupAction = $('<div>', { class: 'popup-action' });
|
|
||||||
const $popupNvmSpan = $('<span>', { class: 'popup-no' });
|
|
||||||
$popupNvmSpan.attr('data-l10n-id', 'deletePopupCancel');
|
|
||||||
const $popupDelSpan = $('<span>', { class: 'popup-yes' });
|
|
||||||
$popupDelSpan.attr('data-l10n-id', 'deletePopupYes');
|
|
||||||
|
|
||||||
$popupText.html([$popupMessage, $popupAction]);
|
|
||||||
$popupAction.html([$popupNvmSpan, $popupDelSpan]);
|
|
||||||
|
|
||||||
// add data cells to table row
|
|
||||||
row.appendChild(name);
|
|
||||||
$(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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// show popup
|
|
||||||
$delIcon.on('click', () => {
|
|
||||||
$popupText.addClass('show').focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
// hide popup
|
|
||||||
$popupText.find('.popup-no').on('click', e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
$popupText.removeClass('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
$popupText.on('click', e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
|
|
||||||
//close when popup loses focus
|
|
||||||
$popupText.on('blur', () => {
|
|
||||||
$popupText.removeClass('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
toggleHeader();
|
|
||||||
};
|
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
metrics.unsupported({ err }).then(() => {
|
metrics.unsupported({ err }).then(() => {
|
||||||
|
|||||||
@@ -123,10 +123,23 @@ function bytes(num) {
|
|||||||
return `${nStr}${UNITS[exponent]}`;
|
return `${nStr}${UNITS[exponent]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function percent(ratio) {
|
||||||
|
return LOCALIZE_NUMBERS
|
||||||
|
? ratio.toLocaleString(navigator.languages, { style: 'percent' })
|
||||||
|
: `${Math.floor(ratio * 100)}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function allowedCopy() {
|
||||||
|
const support = !!document.queryCommandSupported;
|
||||||
|
return support ? document.queryCommandSupported('copy') : false;
|
||||||
|
}
|
||||||
|
|
||||||
const ONE_DAY_IN_MS = 86400000;
|
const ONE_DAY_IN_MS = 86400000;
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
|
allowedCopy,
|
||||||
bytes,
|
bytes,
|
||||||
|
percent,
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
arrayToHex,
|
arrayToHex,
|
||||||
hexToArray,
|
hexToArray,
|
||||||
|
|||||||
6100
package-lock.json
generated
6100
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
55
package.json
55
package.json
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "firefox-send",
|
"name": "firefox-send",
|
||||||
"description": "File Sharing Experiment",
|
"description": "File Sharing Experiment",
|
||||||
"version": "1.1.0",
|
"version": "1.1.2",
|
||||||
"author": "Mozilla (https://mozilla.org)",
|
"author": "Mozilla (https://mozilla.org)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-sdk": "^2.89.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",
|
||||||
@@ -13,38 +13,54 @@
|
|||||||
"helmet": "^3.8.0",
|
"helmet": "^3.8.0",
|
||||||
"mozlog": "^2.1.1",
|
"mozlog": "^2.1.1",
|
||||||
"raven": "^2.1.0",
|
"raven": "^2.1.0",
|
||||||
"redis": "^2.7.1"
|
"redis": "^2.8.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"asmcrypto.js": "0.0.11",
|
"asmcrypto.js": "0.0.11",
|
||||||
|
"autoprefixer": "^7.1.2",
|
||||||
"babel-core": "^6.25.0",
|
"babel-core": "^6.25.0",
|
||||||
"babel-loader": "^7.1.1",
|
"babel-loader": "^7.1.1",
|
||||||
"babel-plugin-add-module-exports": "^0.2.1",
|
|
||||||
"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",
|
||||||
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
|
"cross-env": "^5.0.5",
|
||||||
|
"css-loader": "^0.28.4",
|
||||||
|
"css-mqpacker": "^6.0.1",
|
||||||
|
"cssnano": "^3.10.0",
|
||||||
"eslint": "^4.3.0",
|
"eslint": "^4.3.0",
|
||||||
"eslint-plugin-mocha": "^4.11.0",
|
"eslint-plugin-mocha": "^4.11.0",
|
||||||
"eslint-plugin-node": "^5.1.1",
|
"eslint-plugin-node": "^5.1.1",
|
||||||
"eslint-plugin-security": "^1.4.0",
|
"eslint-plugin-security": "^1.4.0",
|
||||||
|
"extract-loader": "^1.0.0",
|
||||||
|
"file-loader": "^0.11.2",
|
||||||
"git-rev-sync": "^1.9.1",
|
"git-rev-sync": "^1.9.1",
|
||||||
"jquery": "^3.2.1",
|
"html-loader": "^0.5.1",
|
||||||
"jquery-circle-progress": "^1.2.2",
|
"html-webpack-plugin": "^2.30.1",
|
||||||
|
"husky": "^0.14.3",
|
||||||
"l20n": "^5.0.0",
|
"l20n": "^5.0.0",
|
||||||
|
"lint-staged": "^4.0.3",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
"mocha": "^3.4.2",
|
"mocha": "^3.4.2",
|
||||||
"npm-run-all": "^4.0.2",
|
"npm-run-all": "^4.0.2",
|
||||||
|
"postcss-cli": "^4.1.0",
|
||||||
|
"postcss-loader": "^2.0.6",
|
||||||
"prettier": "^1.5.3",
|
"prettier": "^1.5.3",
|
||||||
"proxyquire": "^1.8.0",
|
"proxyquire": "^1.8.0",
|
||||||
"raven-js": "^3.17.0",
|
"raven-js": "^3.17.0",
|
||||||
|
"rimraf": "^2.6.1",
|
||||||
"selenium-webdriver": "^3.5.0",
|
"selenium-webdriver": "^3.5.0",
|
||||||
"sinon": "^2.3.8",
|
"sinon": "^2.3.8",
|
||||||
"stylelint": "^8.0.0",
|
"stylelint": "^8.0.0",
|
||||||
"stylelint-config-standard": "^17.0.0",
|
"stylelint-config-standard": "^17.0.0",
|
||||||
|
"stylelint-no-unsupported-browser-features": "^1.0.0",
|
||||||
"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.4.1"
|
"webpack": "^3.5.4",
|
||||||
|
"webpack-dev-middleware": "^1.12.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.2.0"
|
"node": ">=8.2.0"
|
||||||
@@ -53,6 +69,7 @@
|
|||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"repository": "mozilla/send",
|
"repository": "mozilla/send",
|
||||||
"availableLanguages": [
|
"availableLanguages": [
|
||||||
|
"ast",
|
||||||
"az",
|
"az",
|
||||||
"ca",
|
"ca",
|
||||||
"cs",
|
"cs",
|
||||||
@@ -61,6 +78,7 @@
|
|||||||
"dsb",
|
"dsb",
|
||||||
"el",
|
"el",
|
||||||
"en-US",
|
"en-US",
|
||||||
|
"es-AR",
|
||||||
"es-CL",
|
"es-CL",
|
||||||
"es-ES",
|
"es-ES",
|
||||||
"es-MX",
|
"es-MX",
|
||||||
@@ -91,25 +109,38 @@
|
|||||||
"zh-TW"
|
"zh-TW"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"precommit": "lint-staged",
|
||||||
|
"clean": "rimraf dist",
|
||||||
"build": "npm-run-all build:*",
|
"build": "npm-run-all build:*",
|
||||||
"build:js": "webpack -p",
|
"build:js": "webpack -p",
|
||||||
"build:version": "node scripts/version",
|
"build:version": "node scripts/version",
|
||||||
"build:vendor": "cp node_modules/l20n/dist/web/l20n.min.js node_modules/babel-polyfill/dist/polyfill.min.js public",
|
|
||||||
"contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS",
|
"contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS",
|
||||||
"dev": "npm run build && npm start",
|
"dev": "npm run clean && npm run build && npm start",
|
||||||
"format": "prettier '{frontend/src/,scripts/,server/,test/**/!(bundle)}*.js' 'public/*.css' --single-quote --write",
|
"format": "prettier '{,frontend/src/,scripts/,server/,test/**/!(bundle)}*.{js,css}' --single-quote --write",
|
||||||
"get-prod-locales": "node scripts/get-prod-locales",
|
"get-prod-locales": "node scripts/get-prod-locales",
|
||||||
"get-prod-locales:write": "npm run get-prod-locales -- --write",
|
"get-prod-locales:write": "npm run get-prod-locales -- --write",
|
||||||
"lint": "npm-run-all lint:*",
|
"lint": "npm-run-all lint:*",
|
||||||
"lint:css": "stylelint 'public/*.css'",
|
"lint:css": "stylelint 'frontend/src/*.css'",
|
||||||
"lint:js": "eslint .",
|
"lint:js": "eslint .",
|
||||||
"lint-locales": "node scripts/lint-locales",
|
"lint-locales": "node scripts/lint-locales",
|
||||||
"lint-locales:dev": "npm run lint-locales",
|
"lint-locales:dev": "npm run lint-locales",
|
||||||
"lint-locales:prod": "npm run lint-locales -- --production",
|
"lint-locales:prod": "npm run lint-locales -- --production",
|
||||||
"start": "node server/server",
|
"start": "node server/server",
|
||||||
"test": "npm-run-all test:*",
|
"test": "cross-env NODE_ENV=test npm-run-all test:*",
|
||||||
"test:unit": "mocha test/unit",
|
"test:unit": "mocha test/unit",
|
||||||
"test:server": "mocha test/server",
|
"test:server": "mocha test/server",
|
||||||
"test--browser": "browserify test/frontend/frontend.bundle.js -o test/frontend/bundle.js -d && node test/frontend/driver.js"
|
"test--browser": "browserify test/frontend/frontend.bundle.js -o test/frontend/bundle.js -d && node test/frontend/driver.js"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.js": [
|
||||||
|
"prettier --single-quote --write",
|
||||||
|
"eslint",
|
||||||
|
"git add"
|
||||||
|
],
|
||||||
|
"*.css": [
|
||||||
|
"prettier --single-quote --write",
|
||||||
|
"stylelint",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
postcss.config.js
Normal file
15
postcss.config.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
const autoprefixer = require('autoprefixer');
|
||||||
|
const cssnano = require('cssnano');
|
||||||
|
const mqpacker = require('css-mqpacker');
|
||||||
|
|
||||||
|
const conf = require('./server/config');
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
plugins: [autoprefixer, mqpacker, cssnano]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (conf.env === 'development') {
|
||||||
|
options.map = { inline: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = options;
|
||||||
99
public/locales/ast/send.ftl
Normal file
99
public/locales/ast/send.ftl
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
title = Firefox Send
|
||||||
|
siteSubtitle = esperimentu web
|
||||||
|
siteFeedback = Feedback
|
||||||
|
uploadPageHeader = Compartición privada y cifrada de ficheros
|
||||||
|
uploadPageExplainer = Unvia ficheros pente un enllaz seguru, priváu y cifráu que caduca automáticamente p'asegurar que les tos coses nun queden siempres na rede.
|
||||||
|
uploadPageLearnMore = Deprendi más
|
||||||
|
uploadPageDropMessage = Suelta equí'l to ficheru p'aniciar la xuba
|
||||||
|
uploadPageSizeMessage = Pal meyor funcionamientu, lo meyor ye que'l to ficheru seya menor de 1GB
|
||||||
|
uploadPageBrowseButton = Esbilla un ficheru nel to ordenador
|
||||||
|
.title = Esbilla un ficheru nel to ordenador
|
||||||
|
uploadPageBrowseButton1 = Esbilla un ficheru pa unviar
|
||||||
|
.title = Esbilla un ficheru pa unviar
|
||||||
|
uploadPageMultipleFilesAlert = Anguaño nun se sofita la xuba múltiple de ficheros o carpetes.
|
||||||
|
uploadPageBrowseButtonTitle = Xubir ficheru
|
||||||
|
uploadingPageProgress = Xubiendo { $filename } ({ $size })
|
||||||
|
importingFile = Importando...
|
||||||
|
verifyingFile = Verificando...
|
||||||
|
encryptingFile = Cifrando...
|
||||||
|
decryptingFile = Descifrando...
|
||||||
|
notifyUploadDone = Finó la to xuba.
|
||||||
|
uploadingPageMessage = Namái que'l ficheru xuba, sedrás a afitar les opciones de caducidá.
|
||||||
|
uploadingPageCancel = Encaboxar xuba
|
||||||
|
.title = Encaboxar xuba
|
||||||
|
uploadCancelNotification = Encaboxóse la to xuba.
|
||||||
|
uploadingPageLargeFileMessage = Esti ficheru ye grande y pue entardar daqué en xubir. ¡Paciencia!
|
||||||
|
uploadingFileNotification = Avísame cuando se complete la xuba.
|
||||||
|
uploadSuccessConfirmHeader = Preparáu pa unviar
|
||||||
|
uploadSvgAlt
|
||||||
|
.alt = Xubir
|
||||||
|
uploadSuccessTimingHeader = L'enllaz del to ficheru caducará dempués d'una descarga o en 24 hores.
|
||||||
|
copyUrlFormLabelWithName = Copia y comparti l'enllaz pa unviar el to ficheru: { $filename }
|
||||||
|
// Note: Title text for button should be the same.
|
||||||
|
copyUrlFormButton = Copiar al cartafueyu
|
||||||
|
.title = Copiar al cartafueyu
|
||||||
|
copiedUrl = ¡Copióse!
|
||||||
|
// Note: Title text for button should be the same.
|
||||||
|
deleteFileButton = Desaniciar ficheru
|
||||||
|
.title = Desaniciar ficheru
|
||||||
|
// Note: Title text for button should be the same.
|
||||||
|
sendAnotherFileLink = Unviar otru ficheru
|
||||||
|
.title = Unviar otru ficheru
|
||||||
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
|
downloadAltText
|
||||||
|
.alt = Baxar
|
||||||
|
downloadFileName = Baxar { $filename }
|
||||||
|
downloadFileSize = ({ $size })
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
downloadMessage = El to collaciu unvióte un ficheru usando Firefox Send, un serviciu que te permite compartir ficheros con un enllaz seguru, priváu y cifráu que caduca automáticamente p'asegurar que les to coses nun queden siempres na rede.
|
||||||
|
// Text and title used on the download link/button (indicates an action).
|
||||||
|
downloadButtonLabel = Baxar
|
||||||
|
.title = Baxar
|
||||||
|
downloadNotification = Completóse la to descarga.
|
||||||
|
downloadFinish = Descarga completada
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
|
sendYourFilesLink = Prueba Firefox Send
|
||||||
|
.title = Prueba Firefox Send
|
||||||
|
downloadingPageProgress = Baxando { $filename } ({ $size })
|
||||||
|
downloadingPageMessage = Dexa esta llingüeta abierta entrín vamos en cata del to ficheru y lu desciframos, por favor.
|
||||||
|
errorAltText
|
||||||
|
.alt = Fallu de xuba
|
||||||
|
errorPageHeader = ¡Daqué foi mal!
|
||||||
|
errorPageMessage = Hebo un fallu xubiendo'l ficheru.
|
||||||
|
errorPageLink = Unviar otru ficheru
|
||||||
|
fileTooBig = Esti ficheru ye mui grande como pa xubilu. Debería tener menos de { $size }.
|
||||||
|
linkExpiredAlt
|
||||||
|
.alt = Enllaz caducáu
|
||||||
|
expiredPageHeader = ¡Esti enllaz caducó o enxamás nun esistó!
|
||||||
|
notSupportedHeader = El to restolador nun ta sofitáu.
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
notSupportedDetail = Desafortunadamente esti restolador nun sofita la teunoloxía web qu'usa Firefox Send. Precisarás d'usar otru restolador. ¡Aconseyámoste Firefox!
|
||||||
|
notSupportedLink = ¿Por qué'l mio restolador nun ta sofitáu?
|
||||||
|
notSupportedOutdatedDetail = Desafortunadamente esta versión de Firefox nun sofita la teunoloxía web qu'usa Firefox Send. Precisarás d'anovar Firefox.
|
||||||
|
updateFirefox = Anovar Firefox
|
||||||
|
downloadFirefoxButtonSub = Descarga de baldre
|
||||||
|
uploadedFile = Ficheru
|
||||||
|
copyFileList = Copiar URL
|
||||||
|
// expiryFileList is used as a column header
|
||||||
|
expiryFileList = Caduca en
|
||||||
|
deleteFileList = Desaniciar
|
||||||
|
nevermindButton = Nun m'importa
|
||||||
|
legalHeader = Términos y privacidá
|
||||||
|
legalNoticeTestPilot = Anguaño Firefox Send ye un esperimentu de Test Pilot y ta suxetu a los <a>Términos de serviciu</a> y l'<a>Avisu de privacidá</a> de Test Pilot. <a>Equí</a> pues deprender más tocante a esti esperimentu y la so recoyida de datos.
|
||||||
|
legalNoticeMozilla = L'usu de Firefox Send tamién ta suxetu al <a>Avisu de privacidá</a> y a los <a>Términos d'usu de la páxina web</a> de Mozilla.
|
||||||
|
deletePopupText = ¿Desaniciar esti ficheru?
|
||||||
|
deletePopupYes = Sí
|
||||||
|
deletePopupCancel = Encaboxar
|
||||||
|
deleteButtonHover
|
||||||
|
.title = Desaniciar
|
||||||
|
copyUrlHover
|
||||||
|
.title = Copiar URL
|
||||||
|
footerLinkLegal = Llegal
|
||||||
|
// Test Pilot is a proper name and should not be localized.
|
||||||
|
footerLinkAbout = Tocante a Test Pilot
|
||||||
|
footerLinkPrivacy = Privacidá
|
||||||
|
footerLinkTerms = Términos
|
||||||
|
footerLinkCookies = Cookies
|
||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Yükləmək üçün faylınızı buraya daşıyın
|
|||||||
uploadPageSizeMessage = Xidmətin daha yaxşı işləməsi üçün faylınız 1 GB-dan az olmalıdır
|
uploadPageSizeMessage = Xidmətin daha yaxşı işləməsi üçün faylınız 1 GB-dan az olmalıdır
|
||||||
uploadPageBrowseButton = Kompüterinizdən fayl seçin
|
uploadPageBrowseButton = Kompüterinizdən fayl seçin
|
||||||
.title = Kompüterinizdən fayl seçin
|
.title = Kompüterinizdən fayl seçin
|
||||||
|
uploadPageBrowseButton1 = Yüklənəcək faylı seçin
|
||||||
|
.title = Yüklənəcək faylı seçin
|
||||||
uploadPageMultipleFilesAlert = Birdən çox fayl və ya qovluq yükləmə hələlik dəstəklənmir.
|
uploadPageMultipleFilesAlert = Birdən çox fayl və ya qovluq yükləmə hələlik dəstəklənmir.
|
||||||
uploadPageBrowseButtonTitle = Fayl yüklə
|
uploadPageBrowseButtonTitle = Fayl yüklə
|
||||||
uploadingPageHeader = Faylınız yüklənir
|
uploadingPageProgress = { $filename } ({ $size }) yüklənir
|
||||||
importingFile = İdxal edilir…
|
importingFile = İdxal edilir…
|
||||||
verifyingFile = Təsdiqlənir…
|
verifyingFile = Təsdiqlənir…
|
||||||
encryptingFile = Şifrələnir...
|
encryptingFile = Şifrələnir...
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Endir
|
|||||||
.title = Endir
|
.title = Endir
|
||||||
downloadNotification = Endirməniz tamamlandı.
|
downloadNotification = Endirməniz tamamlandı.
|
||||||
downloadFinish = Endirmə Tamamlandı
|
downloadFinish = Endirmə Tamamlandı
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } / { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Firefox Send Yoxla
|
sendYourFilesLink = Firefox Send Yoxla
|
||||||
.title = Firefox Send Yoxla
|
.title = Firefox Send Yoxla
|
||||||
|
|||||||
65
public/locales/bn-BD/send.ftl
Normal file
65
public/locales/bn-BD/send.ftl
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
title = Firefox Send
|
||||||
|
siteSubtitle = ওয়েব গবেষণা
|
||||||
|
siteFeedback = প্রতিক্রিয়া
|
||||||
|
uploadPageLearnMore = আরও জানুন
|
||||||
|
uploadPageBrowseButton = আপনার কম্পিউটারে ফাইল নির্বাচন করুন
|
||||||
|
.title = আপনার কম্পিউটারে ফাইল নির্বাচন করুন
|
||||||
|
uploadPageBrowseButtonTitle = ফাইল আপলোড
|
||||||
|
importingFile = ইম্পোর্ট হচ্ছে...
|
||||||
|
verifyingFile = যাচাই হচ্ছে...
|
||||||
|
encryptingFile = ইনক্রিপট হচ্ছে...
|
||||||
|
decryptingFile = ডিক্রিপট হচ্ছে...
|
||||||
|
notifyUploadDone = আপনার আপলোড সম্পন্ন হয়েছে।
|
||||||
|
uploadingPageCancel = আপলোড বাতিল করুন
|
||||||
|
.title = আপলোড বাতিল করুন
|
||||||
|
uploadCancelNotification = আপনার অাপলোড বাতিল করা হয়েছে।
|
||||||
|
uploadSuccessConfirmHeader = পাঠানোর জন্য প্রস্তুত
|
||||||
|
uploadSvgAlt
|
||||||
|
.alt = আপলোড
|
||||||
|
// Note: Title text for button should be the same.
|
||||||
|
copyUrlFormButton = ক্লিপবোর্ডে কপি করুন
|
||||||
|
.title = ক্লিপবোর্ডে কপি করুন
|
||||||
|
copiedUrl = কপি করা হয়েছে!
|
||||||
|
// Note: Title text for button should be the same.
|
||||||
|
deleteFileButton = ফাইল মুছুন
|
||||||
|
.title = ফাইল মুছুন
|
||||||
|
// Note: Title text for button should be the same.
|
||||||
|
sendAnotherFileLink = আরেকটি ফাইল পাঠান
|
||||||
|
.title = আরেকটি ফাইল পাঠান
|
||||||
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
|
downloadAltText
|
||||||
|
.alt = ডাউনলোড
|
||||||
|
downloadFileName = ডাউনলোড { $filename }
|
||||||
|
downloadFileSize = ({ $size })
|
||||||
|
// Text and title used on the download link/button (indicates an action).
|
||||||
|
downloadButtonLabel = ডাউনলোড
|
||||||
|
.title = ডাউনলোড
|
||||||
|
downloadNotification = আপনার ডাউনলোড সম্পন্ন হয়েছে।
|
||||||
|
downloadFinish = ডাউনলোড সম্পন্ন
|
||||||
|
errorAltText
|
||||||
|
.alt = আপালোডে ত্রুটি
|
||||||
|
errorPageHeader = কোন সমস্যা হয়েছে!
|
||||||
|
errorPageLink = আরেকটি ফাইল পাঠান
|
||||||
|
updateFirefox = Firefox হালনাগাদ করুন
|
||||||
|
downloadFirefoxButtonSub = বিনামূল্যে ডাউনলোড
|
||||||
|
uploadedFile = ফাইল
|
||||||
|
copyFileList = URL অনুলিপি করুন
|
||||||
|
// expiryFileList is used as a column header
|
||||||
|
expiryFileList = মেয়াদোত্তীর্ণ তারিখ
|
||||||
|
deleteFileList = মুছে ফেলুন
|
||||||
|
nevermindButton = কিছু মনে করবেন না
|
||||||
|
legalHeader = শর্তাবলী এবং গোপনীয়তা
|
||||||
|
deletePopupText = ফাইলটি মুছতে চান?
|
||||||
|
deletePopupYes = হ্যাঁ
|
||||||
|
deletePopupCancel = বাতিল
|
||||||
|
deleteButtonHover
|
||||||
|
.title = মুছে ফেলুন
|
||||||
|
copyUrlHover
|
||||||
|
.title = URL অনুলিপি করুন
|
||||||
|
footerLinkLegal = আইনগত
|
||||||
|
// Test Pilot is a proper name and should not be localized.
|
||||||
|
footerLinkAbout = Test Pilot পরিচিতি
|
||||||
|
footerLinkPrivacy = গোপনীয়তা
|
||||||
|
footerLinkTerms = শর্তাবলী
|
||||||
|
footerLinkCookies = কুকি
|
||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Arrossegueu el fitxer aquí per començar a pujar-lo
|
|||||||
uploadPageSizeMessage = Funciona millor quan els fitxers tenen menys d'1 GB
|
uploadPageSizeMessage = Funciona millor quan els fitxers tenen menys d'1 GB
|
||||||
uploadPageBrowseButton = Trieu un fitxer de l'ordinador
|
uploadPageBrowseButton = Trieu un fitxer de l'ordinador
|
||||||
.title = Trieu un fitxer de l'ordinador
|
.title = Trieu un fitxer de l'ordinador
|
||||||
|
uploadPageBrowseButton1 = Seleccioneu el fitxer que voleu pujar
|
||||||
|
.title = Seleccioneu el fitxer que voleu pujar
|
||||||
uploadPageMultipleFilesAlert = Actualment no es permet pujar diversos fitxers ni una carpeta.
|
uploadPageMultipleFilesAlert = Actualment no es permet pujar diversos fitxers ni una carpeta.
|
||||||
uploadPageBrowseButtonTitle = Puja el fitxer
|
uploadPageBrowseButtonTitle = Puja el fitxer
|
||||||
uploadingPageHeader = S'està pujant el fitxer
|
uploadingPageProgress = S'està pujant { $filename } ({ $size })
|
||||||
importingFile = S'està important…
|
importingFile = S'està important…
|
||||||
verifyingFile = S'està verificant…
|
verifyingFile = S'està verificant…
|
||||||
encryptingFile = S'està xifrant…
|
encryptingFile = S'està xifrant…
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Baixa
|
|||||||
.title = Baixa
|
.title = Baixa
|
||||||
downloadNotification = La baixada ha acabat.
|
downloadNotification = La baixada ha acabat.
|
||||||
downloadFinish = Ha acabat la baixada
|
downloadFinish = Ha acabat la baixada
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Proveu el Firefox Send
|
sendYourFilesLink = Proveu el Firefox Send
|
||||||
.title = Proveu el Firefox Send
|
.title = Proveu el Firefox Send
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Přesunutím souboru sem spustíte jeho nahrávání
|
|||||||
uploadPageSizeMessage = Nahrávání funguje nejlépe pro soubory do velikosti 1 GB.
|
uploadPageSizeMessage = Nahrávání funguje nejlépe pro soubory do velikosti 1 GB.
|
||||||
uploadPageBrowseButton = Vybrat soubor z počítače
|
uploadPageBrowseButton = Vybrat soubor z počítače
|
||||||
.title = Výběr souboru z počítače
|
.title = Výběr souboru z počítače
|
||||||
|
uploadPageBrowseButton1 = Zvolte soubor k nahrání
|
||||||
|
.title = Zvolte soubor k nahrání
|
||||||
uploadPageMultipleFilesAlert = Nahrávání více souborů najednou nebo celých složek zatím není podporováno.
|
uploadPageMultipleFilesAlert = Nahrávání více souborů najednou nebo celých složek zatím není podporováno.
|
||||||
uploadPageBrowseButtonTitle = Nahrát soubor
|
uploadPageBrowseButtonTitle = Nahrát soubor
|
||||||
uploadingPageHeader = Nahrávání vašeho souboru
|
uploadingPageProgress = Nahrávání souboru { $filename } ({ $size })
|
||||||
importingFile = Probíhá import…
|
importingFile = Probíhá import…
|
||||||
verifyingFile = Probíhá ověřování…
|
verifyingFile = Probíhá ověřování…
|
||||||
encryptingFile = Probíhá šifrování…
|
encryptingFile = Probíhá šifrování…
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Stáhnout
|
|||||||
.title = Stáhnout
|
.title = Stáhnout
|
||||||
downloadNotification = Stahování bylo dokončeno.
|
downloadNotification = Stahování bylo dokončeno.
|
||||||
downloadFinish = Stahování dokončeno
|
downloadFinish = Stahování dokončeno
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } z { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Vyzkoušejte Firefox Send
|
sendYourFilesLink = Vyzkoušejte Firefox Send
|
||||||
.title = Vyzkoušejte Firefox Send
|
.title = Vyzkoušejte Firefox Send
|
||||||
@@ -67,6 +71,7 @@ expiredPageHeader = Platnost tohoto odkazu buď vypršela, nebo vůbec nikdy nee
|
|||||||
notSupportedHeader = Váš prohlížeč není podporován.
|
notSupportedHeader = Váš prohlížeč není podporován.
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
notSupportedDetail = Bohužel tento prohlížeč nepodporuje technologii, kterou Firefox Send používá. Zkuste prosím jiný prohlížeč, doporučujeme Firefox!
|
notSupportedDetail = Bohužel tento prohlížeč nepodporuje technologii, kterou Firefox Send používá. Zkuste prosím jiný prohlížeč, doporučujeme Firefox!
|
||||||
|
notSupportedLink = Proč není můj prohlížeč podporovaný?
|
||||||
notSupportedOutdatedDetail = Tato verze Firefoxu bohužel nepodporuje webovou technologii, která pohání Firefox Send. Musíte aktualizovat svůj prohlížeč.
|
notSupportedOutdatedDetail = Tato verze Firefoxu bohužel nepodporuje webovou technologii, která pohání Firefox Send. Musíte aktualizovat svůj prohlížeč.
|
||||||
updateFirefox = Aktualizovat Firefox
|
updateFirefox = Aktualizovat Firefox
|
||||||
downloadFirefoxButtonSub = Stáhnout zdarma
|
downloadFirefoxButtonSub = Stáhnout zdarma
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Gollyngwch eich ffeiliau yma i gychwyn llwytho i fyny
|
|||||||
uploadPageSizeMessage = Mae'n well cadw maint y ffeiliau o dan 1GB er mwyn iddo weithio ar ei orau.
|
uploadPageSizeMessage = Mae'n well cadw maint y ffeiliau o dan 1GB er mwyn iddo weithio ar ei orau.
|
||||||
uploadPageBrowseButton = Dewiswch ffeil ar eich cyfrifiadur
|
uploadPageBrowseButton = Dewiswch ffeil ar eich cyfrifiadur
|
||||||
.title = Dewiswch ffeil ar eich cyfrifiadur
|
.title = Dewiswch ffeil ar eich cyfrifiadur
|
||||||
|
uploadPageBrowseButton1 = Dewiswch ffeil i'w llwytho i fyny
|
||||||
|
.title = Dewiswch ffeil i'w llwytho i fyny
|
||||||
uploadPageMultipleFilesAlert = Nid yw llwytho nifer lluosog o ffeilia neu ffolder yn cael ei gynnal ar hyn o bryd.
|
uploadPageMultipleFilesAlert = Nid yw llwytho nifer lluosog o ffeilia neu ffolder yn cael ei gynnal ar hyn o bryd.
|
||||||
uploadPageBrowseButtonTitle = Llwytho ffeil i fyny
|
uploadPageBrowseButtonTitle = Llwytho ffeil i fyny
|
||||||
uploadingPageHeader = Llwytho eich Ffeiliau i Fyny
|
uploadingPageProgress = Llwytho $filename} i fyny ({ $size })
|
||||||
importingFile = Mewnforio…
|
importingFile = Mewnforio…
|
||||||
verifyingFile = Wrthi'n gwirio…
|
verifyingFile = Wrthi'n gwirio…
|
||||||
encryptingFile = Wrthi'n amgryptio…
|
encryptingFile = Wrthi'n amgryptio…
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Llwytho i Lawr
|
|||||||
.title = Llwytho i Lawr
|
.title = Llwytho i Lawr
|
||||||
downloadNotification = Mae eich llwytho wedi gorffen
|
downloadNotification = Mae eich llwytho wedi gorffen
|
||||||
downloadFinish = Llwytho wedi Gorffen
|
downloadFinish = Llwytho wedi Gorffen
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } o { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Profwch Firefox Send
|
sendYourFilesLink = Profwch Firefox Send
|
||||||
.title = Profwch Firefox Send
|
.title = Profwch Firefox Send
|
||||||
@@ -67,6 +71,7 @@ expiredPageHeader = Mae'r ddolen wedi dod i ben neu nad yw wedi bodoli erioed!
|
|||||||
notSupportedHeader = Nid yw eich porwr yn cael ei gynnal.
|
notSupportedHeader = Nid yw eich porwr yn cael ei gynnal.
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
notSupportedDetail = Yn anffodus nid yw'r porwr hwn yn cynnal y technoleg gwe sy'n cynnal Firefox Send. Bydd angen i chi ddefnyddio porwr arall. Rydym ni'n argymell Firefox!
|
notSupportedDetail = Yn anffodus nid yw'r porwr hwn yn cynnal y technoleg gwe sy'n cynnal Firefox Send. Bydd angen i chi ddefnyddio porwr arall. Rydym ni'n argymell Firefox!
|
||||||
|
notSupportedLink = Pam nad yw fy mhorwr yn cael ei gynnal?
|
||||||
notSupportedOutdatedDetail = Yn anffodus nid yw'r fersiwn yma o Firefox yn cynnal y technoleg gwe sy'n gyrru Firefox Send. Bydd angen i chi ddiweddaru eich porwr.
|
notSupportedOutdatedDetail = Yn anffodus nid yw'r fersiwn yma o Firefox yn cynnal y technoleg gwe sy'n gyrru Firefox Send. Bydd angen i chi ddiweddaru eich porwr.
|
||||||
updateFirefox = Diweddaru Firefox
|
updateFirefox = Diweddaru Firefox
|
||||||
downloadFirefoxButtonSub = Llwytho i Lawr am Ddim
|
downloadFirefoxButtonSub = Llwytho i Lawr am Ddim
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Ziehen Sie eine Datei zum Hochladen hierher
|
|||||||
uploadPageSizeMessage = Dateien unter 1 GB sorgen für erhöhte Zuverlässigkeit des Betriebs
|
uploadPageSizeMessage = Dateien unter 1 GB sorgen für erhöhte Zuverlässigkeit des Betriebs
|
||||||
uploadPageBrowseButton = Wählen Sie eine Datei auf Ihrem Computer aus
|
uploadPageBrowseButton = Wählen Sie eine Datei auf Ihrem Computer aus
|
||||||
.title = Wählen Sie eine Datei auf Ihrem Computer aus
|
.title = Wählen Sie eine Datei auf Ihrem Computer aus
|
||||||
|
uploadPageBrowseButton1 = Datei zum Hochladen auswählen
|
||||||
|
.title = Datei zum Hochladen auswählen
|
||||||
uploadPageMultipleFilesAlert = Hochladen mehrerer Dateien oder eines Ordners wird derzeit nicht unterstützt.
|
uploadPageMultipleFilesAlert = Hochladen mehrerer Dateien oder eines Ordners wird derzeit nicht unterstützt.
|
||||||
uploadPageBrowseButtonTitle = Datei hochladen
|
uploadPageBrowseButtonTitle = Datei hochladen
|
||||||
uploadingPageProgress = { $filename } ({ $size }) wird hochgeladen
|
uploadingPageProgress = { $filename } ({ $size }) wird hochgeladen
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Śěgniśo swóju dataju sem, aby ju nagrał
|
|||||||
uploadPageSizeMessage = Wužywajśo nejlěpje dataje, kótarež su mjeńše ako 1 GB za lěpšu spušćobnosć.
|
uploadPageSizeMessage = Wužywajśo nejlěpje dataje, kótarež su mjeńše ako 1 GB za lěpšu spušćobnosć.
|
||||||
uploadPageBrowseButton = Wubjeŕśo dataju na swójom licadle
|
uploadPageBrowseButton = Wubjeŕśo dataju na swójom licadle
|
||||||
.title = Wubjeŕśo dataju na swójom licadle
|
.title = Wubjeŕśo dataju na swójom licadle
|
||||||
|
uploadPageBrowseButton1 = Wubjeŕśo dataju za nagraśe
|
||||||
|
.title = Wubjeŕśo dataju za nagraśe
|
||||||
uploadPageMultipleFilesAlert = Nagrawanje někotarych datajow abo zarědnika se tuchylu njepódpěra.
|
uploadPageMultipleFilesAlert = Nagrawanje někotarych datajow abo zarědnika se tuchylu njepódpěra.
|
||||||
uploadPageBrowseButtonTitle = Dataju nagraś
|
uploadPageBrowseButtonTitle = Dataju nagraś
|
||||||
uploadingPageProgress = { $filename } ({ $size }) se nagrawa
|
uploadingPageProgress = { $filename } ({ $size }) se nagrawa
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Εναποθέστε το αρχείο σας εδώ γ
|
|||||||
uploadPageSizeMessage = Για περισσότερο αξιόπιστη λειτουργία, προτείνεται να διατηρήσετε το αρχείο κάτω από 1GB
|
uploadPageSizeMessage = Για περισσότερο αξιόπιστη λειτουργία, προτείνεται να διατηρήσετε το αρχείο κάτω από 1GB
|
||||||
uploadPageBrowseButton = Επιλέξτε αρχείο από τον υπολογιστή σας
|
uploadPageBrowseButton = Επιλέξτε αρχείο από τον υπολογιστή σας
|
||||||
.title = Επιλέξτε αρχείο από τον υπολογιστή σας
|
.title = Επιλέξτε αρχείο από τον υπολογιστή σας
|
||||||
|
uploadPageBrowseButton1 = Επιλέξτε ένα αρχείο για μεταφόρτωση
|
||||||
|
.title = Επιλέξτε ένα αρχείο για μεταφόρτωση
|
||||||
uploadPageMultipleFilesAlert = Η μεταφόρτωση πολλαπλών αρχείων ή φακέλου δεν υποστηρίζεται αυτή τη στιγμή.
|
uploadPageMultipleFilesAlert = Η μεταφόρτωση πολλαπλών αρχείων ή φακέλου δεν υποστηρίζεται αυτή τη στιγμή.
|
||||||
uploadPageBrowseButtonTitle = Μεταφόρτωση αρχείου
|
uploadPageBrowseButtonTitle = Μεταφόρτωση αρχείου
|
||||||
uploadingPageHeader = Γίνετε μεταφόρτωση του αρχείου σας
|
uploadingPageProgress = Μεταφόρτωση του { $filename } ({ $size })
|
||||||
importingFile = Εισαγωγή…
|
importingFile = Εισαγωγή…
|
||||||
verifyingFile = Επαλήθευση...
|
verifyingFile = Επαλήθευση...
|
||||||
encryptingFile = Κρυπτογράφηση…
|
encryptingFile = Κρυπτογράφηση…
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Λήψη
|
|||||||
.title = Λήψη
|
.title = Λήψη
|
||||||
downloadNotification = Η λήψη σας ολοκληρώθηκε.
|
downloadNotification = Η λήψη σας ολοκληρώθηκε.
|
||||||
downloadFinish = Η λήψη ολοκληρώθηκε
|
downloadFinish = Η λήψη ολοκληρώθηκε
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } από { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Δοκιμάστε το Firefox Send
|
sendYourFilesLink = Δοκιμάστε το Firefox Send
|
||||||
.title = Δοκιμάστε το Firefox Send
|
.title = Δοκιμάστε το Firefox Send
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Drop your file here to start uploading
|
|||||||
uploadPageSizeMessage = For the most reliable operation, it’s best to keep your file under 1GB
|
uploadPageSizeMessage = For the most reliable operation, it’s best to keep your file under 1GB
|
||||||
uploadPageBrowseButton = Select a file on your computer
|
uploadPageBrowseButton = Select a file on your computer
|
||||||
.title = Select a file on your computer
|
.title = Select a file on your computer
|
||||||
|
uploadPageBrowseButton1 = Select a file to upload
|
||||||
|
.title = Select a file to upload
|
||||||
uploadPageMultipleFilesAlert = Uploading multiple files or a folder is currently not supported.
|
uploadPageMultipleFilesAlert = Uploading multiple files or a folder is currently not supported.
|
||||||
uploadPageBrowseButtonTitle = Upload file
|
uploadPageBrowseButtonTitle = Upload file
|
||||||
uploadingPageProgress = Uploading { $filename } ({ $size })
|
uploadingPageProgress = Uploading { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Arrastrá el archivo hasta acá para empezar a subir
|
|||||||
uploadPageSizeMessage = Para una operación más confiable, es mejor que el archivo tenga menos de 1GB
|
uploadPageSizeMessage = Para una operación más confiable, es mejor que el archivo tenga menos de 1GB
|
||||||
uploadPageBrowseButton = Seleccioná un archivo en tu computadora
|
uploadPageBrowseButton = Seleccioná un archivo en tu computadora
|
||||||
.title = Seleccioná un archivo en tu computadora
|
.title = Seleccioná un archivo en tu computadora
|
||||||
|
uploadPageBrowseButton1 = Seleccioná un archivo para subir
|
||||||
|
.title = Seleccioná un archivo para subir
|
||||||
uploadPageMultipleFilesAlert = Cargar múltiples archivos o una carpeta todavía no está soportado.
|
uploadPageMultipleFilesAlert = Cargar múltiples archivos o una carpeta todavía no está soportado.
|
||||||
uploadPageBrowseButtonTitle = Subir archivo
|
uploadPageBrowseButtonTitle = Subir archivo
|
||||||
uploadingPageProgress = Subiendo { $filename } ({ $size })
|
uploadingPageProgress = Subiendo { $filename } ({ $size })
|
||||||
@@ -78,6 +80,7 @@ copyFileList = Copiar URL
|
|||||||
// expiryFileList is used as a column header
|
// expiryFileList is used as a column header
|
||||||
expiryFileList = Expira en
|
expiryFileList = Expira en
|
||||||
deleteFileList = Borrar
|
deleteFileList = Borrar
|
||||||
|
nevermindButton = No importa
|
||||||
legalHeader = Términos y privacidad
|
legalHeader = Términos y privacidad
|
||||||
legalNoticeTestPilot = Firefox Send es actualmente un experimento de Test Pilot y está sujeto a los <a>términos de servicio</a> y la <a>nota de privacidad</a> de Test Pilot. Podés conocer más sobre este experimento y su recolección de datos <a>aquí</a>.
|
legalNoticeTestPilot = Firefox Send es actualmente un experimento de Test Pilot y está sujeto a los <a>términos de servicio</a> y la <a>nota de privacidad</a> de Test Pilot. Podés conocer más sobre este experimento y su recolección de datos <a>aquí</a>.
|
||||||
legalNoticeMozilla = El uso del sitio web de Firefox Send también está sujeto a la <a>nota de privacidad de sitios web</a> y los <a>términos de uso de sitios web</a> de Mozilla.
|
legalNoticeMozilla = El uso del sitio web de Firefox Send también está sujeto a la <a>nota de privacidad de sitios web</a> y los <a>términos de uso de sitios web</a> de Mozilla.
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Suelta tu archivo aquí para empezar a subirlo
|
|||||||
uploadPageSizeMessage = Para una operación más confiable, es mejor mantener el tamaño del archivo bajo 1 GB
|
uploadPageSizeMessage = Para una operación más confiable, es mejor mantener el tamaño del archivo bajo 1 GB
|
||||||
uploadPageBrowseButton = Selecciona un archivo en tu computador
|
uploadPageBrowseButton = Selecciona un archivo en tu computador
|
||||||
.title = Selecciona un archivo en tu computador
|
.title = Selecciona un archivo en tu computador
|
||||||
|
uploadPageBrowseButton1 = Selecciona un archivo a subir
|
||||||
|
.title = Selecciona un archivo a subir
|
||||||
uploadPageMultipleFilesAlert = Subir múltiples archivos o una carpeta actualmente no es posible.
|
uploadPageMultipleFilesAlert = Subir múltiples archivos o una carpeta actualmente no es posible.
|
||||||
uploadPageBrowseButtonTitle = Subir archivo
|
uploadPageBrowseButtonTitle = Subir archivo
|
||||||
uploadingPageHeader = Subiendo tu archivo
|
uploadingPageProgress = Subiendo { $filename } ({ $size })
|
||||||
importingFile = Importando…
|
importingFile = Importando…
|
||||||
verifyingFile = Verificando…
|
verifyingFile = Verificando…
|
||||||
encryptingFile = Cifrando…
|
encryptingFile = Cifrando…
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Descargar
|
|||||||
.title = Descargar
|
.title = Descargar
|
||||||
downloadNotification = Tu descarga se completó.
|
downloadNotification = Tu descarga se completó.
|
||||||
downloadFinish = Descarga completa
|
downloadFinish = Descarga completa
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Probar Firefox Send
|
sendYourFilesLink = Probar Firefox Send
|
||||||
.title = Probar Firefox Send
|
.title = Probar Firefox Send
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Suelta aquí tu archivo para empezar a subirlo
|
|||||||
uploadPageSizeMessage = Para que la operación sea más segura, el archivo debería ocupar menos de 1GB
|
uploadPageSizeMessage = Para que la operación sea más segura, el archivo debería ocupar menos de 1GB
|
||||||
uploadPageBrowseButton = Seleccionar un archivo en el equipo
|
uploadPageBrowseButton = Seleccionar un archivo en el equipo
|
||||||
.title = Seleccionar un archivo en el equipo
|
.title = Seleccionar un archivo en el equipo
|
||||||
|
uploadPageBrowseButton1 = Seleccionar un archivo para subir
|
||||||
|
.title = Seleccionar un archivo para subir
|
||||||
uploadPageMultipleFilesAlert = Aún no se pueden subir varios archivos o una carpeta.
|
uploadPageMultipleFilesAlert = Aún no se pueden subir varios archivos o una carpeta.
|
||||||
uploadPageBrowseButtonTitle = Subir archivo
|
uploadPageBrowseButtonTitle = Subir archivo
|
||||||
uploadingPageHeader = Subiendo archivo
|
uploadingPageProgress = Subiendo { $filename } ({ $size })
|
||||||
importingFile = Imporando...
|
importingFile = Imporando...
|
||||||
verifyingFile = Comprobando...
|
verifyingFile = Comprobando...
|
||||||
encryptingFile = Encriptando...
|
encryptingFile = Encriptando...
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Descargar
|
|||||||
.title = Descargar
|
.title = Descargar
|
||||||
downloadNotification = Se completó la descarga.
|
downloadNotification = Se completó la descarga.
|
||||||
downloadFinish = Descarga completa
|
downloadFinish = Descarga completa
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Prueba Firefox Send
|
sendYourFilesLink = Prueba Firefox Send
|
||||||
.title = Prueba Firefox Send
|
.title = Prueba Firefox Send
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Suelta aquí tu archivo para empezar a subirlo
|
|||||||
uploadPageSizeMessage = Para que la operación sea más segura, el archivo debería ocupar menos de 1GB
|
uploadPageSizeMessage = Para que la operación sea más segura, el archivo debería ocupar menos de 1GB
|
||||||
uploadPageBrowseButton = Selecciona un archivo de tu computadora
|
uploadPageBrowseButton = Selecciona un archivo de tu computadora
|
||||||
.title = Selecciona un archivo de tu computadora
|
.title = Selecciona un archivo de tu computadora
|
||||||
|
uploadPageBrowseButton1 = Seleccionar un archivo para subir
|
||||||
|
.title = Seleccionar un archivo para subir
|
||||||
uploadPageMultipleFilesAlert = Aún no se pueden subir varios archivos o una carpeta.
|
uploadPageMultipleFilesAlert = Aún no se pueden subir varios archivos o una carpeta.
|
||||||
uploadPageBrowseButtonTitle = Subir archivo
|
uploadPageBrowseButtonTitle = Subir archivo
|
||||||
uploadingPageHeader = Subiendo tu archivo
|
uploadingPageProgress = Subiendo { $filename } ({ $size })
|
||||||
importingFile = Importando...
|
importingFile = Importando...
|
||||||
verifyingFile = Verificando...
|
verifyingFile = Verificando...
|
||||||
encryptingFile = Encriptando...
|
encryptingFile = Encriptando...
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Descargar
|
|||||||
.title = Descargar
|
.title = Descargar
|
||||||
downloadNotification = Tu descarga se ha completado
|
downloadNotification = Tu descarga se ha completado
|
||||||
downloadFinish = Descarga completa
|
downloadFinish = Descarga completa
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Prueba Firefox Send
|
sendYourFilesLink = Prueba Firefox Send
|
||||||
.title = Prueba Firefox Send
|
.title = Prueba Firefox Send
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Déposez votre fichier ici pour l’envoyer
|
|||||||
uploadPageSizeMessage = Pour un résultat fiable, il est conseillé d’utiliser des fichiers de taille inférieure à 1 Go
|
uploadPageSizeMessage = Pour un résultat fiable, il est conseillé d’utiliser des fichiers de taille inférieure à 1 Go
|
||||||
uploadPageBrowseButton = Sélectionner un fichier sur l’ordinateur
|
uploadPageBrowseButton = Sélectionner un fichier sur l’ordinateur
|
||||||
.title = Sélectionner un fichier sur l’ordinateur
|
.title = Sélectionner un fichier sur l’ordinateur
|
||||||
|
uploadPageBrowseButton1 = Choisir un fichier à envoyer
|
||||||
|
.title = Choisir un fichier à envoyer
|
||||||
uploadPageMultipleFilesAlert = L’envoi de plusieurs fichiers ou de dossiers n’est pas pris en charge pour le moment.
|
uploadPageMultipleFilesAlert = L’envoi de plusieurs fichiers ou de dossiers n’est pas pris en charge pour le moment.
|
||||||
uploadPageBrowseButtonTitle = Envoyer le fichier
|
uploadPageBrowseButtonTitle = Envoyer le fichier
|
||||||
uploadingPageProgress = Envoi en cours de { $filename } ({ $size })
|
uploadingPageProgress = Envoi en cours de { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Ćehńće swoju dataju sem, zo byšće ju nahrał
|
|||||||
uploadPageSizeMessage = Wužiwajće najlěpje dataje, kotrež su mjeńše hač 1 GB za lěpšu spušćomnosć.
|
uploadPageSizeMessage = Wužiwajće najlěpje dataje, kotrež su mjeńše hač 1 GB za lěpšu spušćomnosć.
|
||||||
uploadPageBrowseButton = Wubjerće dataju na swojim ličaku
|
uploadPageBrowseButton = Wubjerće dataju na swojim ličaku
|
||||||
.title = Wubjerće dataju na swojim ličaku
|
.title = Wubjerće dataju na swojim ličaku
|
||||||
|
uploadPageBrowseButton1 = Wubjerće dataju za nahraće
|
||||||
|
.title = Wubjerće dataju za nahraće
|
||||||
uploadPageMultipleFilesAlert = Nahrawanje wjacorych datajow abo rjadowaka so tuchwilu njepodpěruje.
|
uploadPageMultipleFilesAlert = Nahrawanje wjacorych datajow abo rjadowaka so tuchwilu njepodpěruje.
|
||||||
uploadPageBrowseButtonTitle = Dataju nahrać
|
uploadPageBrowseButtonTitle = Dataju nahrać
|
||||||
uploadingPageProgress = { $filename } ({ $size }) so nahrawa
|
uploadingPageProgress = { $filename } ({ $size }) so nahrawa
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Dobja ide a fájljait, és kezdjen feltölteni
|
|||||||
uploadPageSizeMessage = A megbízható működés érdekében a legjobb, ha a fájlok 1 GB-nál kisebbek maradnak
|
uploadPageSizeMessage = A megbízható működés érdekében a legjobb, ha a fájlok 1 GB-nál kisebbek maradnak
|
||||||
uploadPageBrowseButton = Válasszon egy fájlt a számítógépén
|
uploadPageBrowseButton = Válasszon egy fájlt a számítógépén
|
||||||
.title = Válasszon egy fájlt a számítógépén
|
.title = Válasszon egy fájlt a számítógépén
|
||||||
|
uploadPageBrowseButton1 = Válassza ki a feltöltendő fájlt
|
||||||
|
.title = Válassza ki a feltöltendő fájlt
|
||||||
uploadPageMultipleFilesAlert = Több fájl vagy mappa feltöltése pillanatnyilag nem támogatott.
|
uploadPageMultipleFilesAlert = Több fájl vagy mappa feltöltése pillanatnyilag nem támogatott.
|
||||||
uploadPageBrowseButtonTitle = Fájl feltöltése
|
uploadPageBrowseButtonTitle = Fájl feltöltése
|
||||||
uploadingPageProgress = { $filename } ({ $size }) feltöltése
|
uploadingPageProgress = { $filename } ({ $size }) feltöltése
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Trascina qui un file per caricarlo
|
|||||||
uploadPageSizeMessage = Per evitare problemi è consigliabile caricare file di dimensione inferiore a 1 GB
|
uploadPageSizeMessage = Per evitare problemi è consigliabile caricare file di dimensione inferiore a 1 GB
|
||||||
uploadPageBrowseButton = Seleziona un file sul computer
|
uploadPageBrowseButton = Seleziona un file sul computer
|
||||||
.title = Seleziona un file sul computer
|
.title = Seleziona un file sul computer
|
||||||
|
uploadPageBrowseButton1 = Seleziona un file da caricare
|
||||||
|
.title = Seleziona un file da caricare
|
||||||
uploadPageMultipleFilesAlert = Il caricamento di più file o cartelle non è attualmente supportato.
|
uploadPageMultipleFilesAlert = Il caricamento di più file o cartelle non è attualmente supportato.
|
||||||
uploadPageBrowseButtonTitle = Carica file
|
uploadPageBrowseButtonTitle = Carica file
|
||||||
uploadingPageProgress = Caricamento { $filename } ({ $size })
|
uploadingPageProgress = Caricamento { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = ここにファイルをドロップしてアップロ
|
|||||||
uploadPageSizeMessage = 確実に処理できるよう、ファイルサイズは 1 GB 以下にすることを推奨します。
|
uploadPageSizeMessage = 確実に処理できるよう、ファイルサイズは 1 GB 以下にすることを推奨します。
|
||||||
uploadPageBrowseButton = コンピューター上のファイルを選択
|
uploadPageBrowseButton = コンピューター上のファイルを選択
|
||||||
.title = コンピューター上のファイルを選択
|
.title = コンピューター上のファイルを選択
|
||||||
|
uploadPageBrowseButton1 = アップロードするファイルを選択
|
||||||
|
.title = アップロードするファイルを選択
|
||||||
uploadPageMultipleFilesAlert = 今のところ複数ファイルやフォルダーのアップロードには対応していません。
|
uploadPageMultipleFilesAlert = 今のところ複数ファイルやフォルダーのアップロードには対応していません。
|
||||||
uploadPageBrowseButtonTitle = ファイルをアップロード
|
uploadPageBrowseButtonTitle = ファイルをアップロード
|
||||||
uploadingPageProgress = { $filename } ({ $size }) をアップロード中
|
uploadingPageProgress = { $filename } ({ $size }) をアップロード中
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Zuɣeṛ afaylu-ik ar dagi akken ad tebduḍ asali
|
|||||||
uploadPageSizeMessage = I ugmuḍ ufrin, yelha ad tesqedceḍ ifuyla daw n 1 GAṬ
|
uploadPageSizeMessage = I ugmuḍ ufrin, yelha ad tesqedceḍ ifuyla daw n 1 GAṬ
|
||||||
uploadPageBrowseButton = Fren afaylu sef uselkim-ik
|
uploadPageBrowseButton = Fren afaylu sef uselkim-ik
|
||||||
.title = Fren afaylu seg uselkim-ik
|
.title = Fren afaylu seg uselkim-ik
|
||||||
|
uploadPageBrowseButton1 = Fren afaylu ad tazneḍ
|
||||||
|
.title = Fren afaylu ad tazneḍ
|
||||||
uploadPageMultipleFilesAlert = Asali n ddeqs n ifuyla neɣ ikaramen ur ittusefrak ara yakan.
|
uploadPageMultipleFilesAlert = Asali n ddeqs n ifuyla neɣ ikaramen ur ittusefrak ara yakan.
|
||||||
uploadPageBrowseButtonTitle = Sali ifuyla
|
uploadPageBrowseButtonTitle = Sali ifuyla
|
||||||
uploadingPageHeader = Asali n ufaylu-ik
|
uploadingPageProgress = Tuzna n { $filename } ({ $size })
|
||||||
importingFile = Akter...
|
importingFile = Akter...
|
||||||
verifyingFile = Asenqed...
|
verifyingFile = Asenqed...
|
||||||
encryptingFile = Awgelhen...
|
encryptingFile = Awgelhen...
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Sider
|
|||||||
.title = Sider
|
.title = Sider
|
||||||
downloadNotification = Asider-ik yemmed.
|
downloadNotification = Asider-ik yemmed.
|
||||||
downloadFinish = Asider yemmed
|
downloadFinish = Asider yemmed
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } seg { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Ɛreḍ Firefox Send
|
sendYourFilesLink = Ɛreḍ Firefox Send
|
||||||
.title = Ɛreḍ Firefox Send
|
.title = Ɛreḍ Firefox Send
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Letakkan fail anda di sini untuk mulakan memuat naik
|
|||||||
uploadPageSizeMessage = Untuk operasi yang paling selamat, lebih baik pastikan fail anda itu kurang 1GB
|
uploadPageSizeMessage = Untuk operasi yang paling selamat, lebih baik pastikan fail anda itu kurang 1GB
|
||||||
uploadPageBrowseButton = Pilih fail dalam komputer anda
|
uploadPageBrowseButton = Pilih fail dalam komputer anda
|
||||||
.title = Pilih fail dalam komputer anda
|
.title = Pilih fail dalam komputer anda
|
||||||
|
uploadPageBrowseButton1 = Pilih fail untuk dimuat naik
|
||||||
|
.title = Pilih fail untuk dimuat naik
|
||||||
uploadPageMultipleFilesAlert = Memuat naik pelbagai fail atau satu folder masih belum disokong.
|
uploadPageMultipleFilesAlert = Memuat naik pelbagai fail atau satu folder masih belum disokong.
|
||||||
uploadPageBrowseButtonTitle = Muat naik fail
|
uploadPageBrowseButtonTitle = Muat naik fail
|
||||||
uploadingPageProgress = Memuat naik { $filename } ({ $size })
|
uploadingPageProgress = Memuat naik { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Slipp din fil her for å starte opplastingen
|
|||||||
uploadPageSizeMessage = For den mest problemfrie bruken, er det best å holde filen under 1 GB
|
uploadPageSizeMessage = For den mest problemfrie bruken, er det best å holde filen under 1 GB
|
||||||
uploadPageBrowseButton = Velg en fil på din datamaskin
|
uploadPageBrowseButton = Velg en fil på din datamaskin
|
||||||
.title = Velg en fil på din datamaskin
|
.title = Velg en fil på din datamaskin
|
||||||
|
uploadPageBrowseButton1 = Velg en fil til å laste opp
|
||||||
|
.title = Velg en fil til å laste opp
|
||||||
uploadPageMultipleFilesAlert = Opplasting av flere filer eller en mappe støttes ikke for øyeblikket.
|
uploadPageMultipleFilesAlert = Opplasting av flere filer eller en mappe støttes ikke for øyeblikket.
|
||||||
uploadPageBrowseButtonTitle = Last opp fil
|
uploadPageBrowseButtonTitle = Last opp fil
|
||||||
uploadingPageHeader = Laster opp din fil
|
uploadingPageProgress = Laster opp { $filename } ({ $size })
|
||||||
importingFile = Importerer…
|
importingFile = Importerer…
|
||||||
verifyingFile = Verifiserer...
|
verifyingFile = Verifiserer...
|
||||||
encryptingFile = Krypterer...
|
encryptingFile = Krypterer...
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Last ned
|
|||||||
.title = Last ned
|
.title = Last ned
|
||||||
downloadNotification = Nedlastingen er fullført.
|
downloadNotification = Nedlastingen er fullført.
|
||||||
downloadFinish = Nedlastingen er fullført.
|
downloadFinish = Nedlastingen er fullført.
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } av { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Prøv Firefox Send
|
sendYourFilesLink = Prøv Firefox Send
|
||||||
.title = Prøv Firefox Send
|
.title = Prøv Firefox Send
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Sleep uw bestand hiernaartoe om het te uploaden
|
|||||||
uploadPageSizeMessage = Voor de meest betrouwbare werking kunt u uw bestand het beste onder de 1 GB houden
|
uploadPageSizeMessage = Voor de meest betrouwbare werking kunt u uw bestand het beste onder de 1 GB houden
|
||||||
uploadPageBrowseButton = Selecteer een bestand op uw computer
|
uploadPageBrowseButton = Selecteer een bestand op uw computer
|
||||||
.title = Selecteer een bestand op uw computer
|
.title = Selecteer een bestand op uw computer
|
||||||
|
uploadPageBrowseButton1 = Selecteer een bestand om te uploaden
|
||||||
|
.title = Selecteer een bestand om te uploaden
|
||||||
uploadPageMultipleFilesAlert = Het uploaden van meerdere bestanden of een map wordt momenteel niet ondersteund.
|
uploadPageMultipleFilesAlert = Het uploaden van meerdere bestanden of een map wordt momenteel niet ondersteund.
|
||||||
uploadPageBrowseButtonTitle = bestand uploaden
|
uploadPageBrowseButtonTitle = bestand uploaden
|
||||||
uploadingPageProgress = { $filename } ({ $size }) wordt geüpload
|
uploadingPageProgress = { $filename } ({ $size }) wordt geüpload
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Slepp fila di her for å starte opplastinga
|
|||||||
uploadPageSizeMessage = For mest problemfrie bruk, er det best å halde fila under 1 GB
|
uploadPageSizeMessage = For mest problemfrie bruk, er det best å halde fila under 1 GB
|
||||||
uploadPageBrowseButton = Vel ei fil på datamaskina di
|
uploadPageBrowseButton = Vel ei fil på datamaskina di
|
||||||
.title = Vel ei fil på datamaskina di
|
.title = Vel ei fil på datamaskina di
|
||||||
|
uploadPageBrowseButton1 = Vel ei fil å laste opp
|
||||||
|
.title = Vel ei fil å laste opp
|
||||||
uploadPageMultipleFilesAlert = Opplasting av fleire filer eller ei mappe er for tida ikkje støtta.
|
uploadPageMultipleFilesAlert = Opplasting av fleire filer eller ei mappe er for tida ikkje støtta.
|
||||||
uploadPageBrowseButtonTitle = Last opp fil
|
uploadPageBrowseButtonTitle = Last opp fil
|
||||||
uploadingPageProgress = Lastar opp { $filename } ({ $size })
|
uploadingPageProgress = Lastar opp { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Arraste o arquivo para cá para iniciar o envio
|
|||||||
uploadPageSizeMessage = Para uma operação mais confiável, é melhor manter seu arquivo menor que 1GB
|
uploadPageSizeMessage = Para uma operação mais confiável, é melhor manter seu arquivo menor que 1GB
|
||||||
uploadPageBrowseButton = Selecione um arquivo em seu computador
|
uploadPageBrowseButton = Selecione um arquivo em seu computador
|
||||||
.title = Selecione um arquivo em seu computador
|
.title = Selecione um arquivo em seu computador
|
||||||
|
uploadPageBrowseButton1 = Selecione um arquivo para carregar
|
||||||
|
.title = Selecione um arquivo para carregar
|
||||||
uploadPageMultipleFilesAlert = Enviar múltiplos arquivos ou uma pasta ainda não é suportado.
|
uploadPageMultipleFilesAlert = Enviar múltiplos arquivos ou uma pasta ainda não é suportado.
|
||||||
uploadPageBrowseButtonTitle = Enviar arquivo
|
uploadPageBrowseButtonTitle = Enviar arquivo
|
||||||
uploadingPageProgress = Enviando { $filename } ({ $size })
|
uploadingPageProgress = Enviando { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Largue o seu ficheiro aqui para começar a carregar
|
|||||||
uploadPageSizeMessage = Para uma operação mais confiável, é melhor manter o seu ficheiro abaixo de 1GB
|
uploadPageSizeMessage = Para uma operação mais confiável, é melhor manter o seu ficheiro abaixo de 1GB
|
||||||
uploadPageBrowseButton = Selecionar um ficheiro no seu computador
|
uploadPageBrowseButton = Selecionar um ficheiro no seu computador
|
||||||
.title = Selecionar um ficheiro no seu computador
|
.title = Selecionar um ficheiro no seu computador
|
||||||
|
uploadPageBrowseButton1 = Selecione um ficheiro a enviar
|
||||||
|
.title = Selecione um ficheiro a enviar
|
||||||
uploadPageMultipleFilesAlert = Carregar múltiplos ficheiros ou uma pasta não é atualmente suportado.
|
uploadPageMultipleFilesAlert = Carregar múltiplos ficheiros ou uma pasta não é atualmente suportado.
|
||||||
uploadPageBrowseButtonTitle = Carregar ficheiro
|
uploadPageBrowseButtonTitle = Carregar ficheiro
|
||||||
uploadingPageProgress = A carregar { $filename } ({ $size })
|
uploadingPageProgress = A carregar { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Перетащите свой файл сюда, что
|
|||||||
uploadPageSizeMessage = Для более надёжной работы сервиса, размер вашего файла не должен превышать 1ГБ.
|
uploadPageSizeMessage = Для более надёжной работы сервиса, размер вашего файла не должен превышать 1ГБ.
|
||||||
uploadPageBrowseButton = Выбрать файл с моего компьютера
|
uploadPageBrowseButton = Выбрать файл с моего компьютера
|
||||||
.title = Выбрать файл с моего компьютера
|
.title = Выбрать файл с моего компьютера
|
||||||
|
uploadPageBrowseButton1 = Выбрать файл для загрузки
|
||||||
|
.title = Выбрать файл для загрузки
|
||||||
uploadPageMultipleFilesAlert = Загрузка нескольких файлов или папок в настоящее время не поддерживается.
|
uploadPageMultipleFilesAlert = Загрузка нескольких файлов или папок в настоящее время не поддерживается.
|
||||||
uploadPageBrowseButtonTitle = Загрузить файл
|
uploadPageBrowseButtonTitle = Загрузить файл
|
||||||
uploadingPageHeader = Загрузка вашего файла
|
uploadingPageProgress = Загружаю { $filename } ({ $size })
|
||||||
importingFile = Импортирование...
|
importingFile = Импортирование...
|
||||||
verifyingFile = Проверка...
|
verifyingFile = Проверка...
|
||||||
encryptingFile = Шифрование...
|
encryptingFile = Шифрование...
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Скачать
|
|||||||
.title = Скачать
|
.title = Скачать
|
||||||
downloadNotification = Ваша загрузка завершена.
|
downloadNotification = Ваша загрузка завершена.
|
||||||
downloadFinish = Загрузка завершена
|
downloadFinish = Загрузка завершена
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } из { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Попробовать Firefox Send
|
sendYourFilesLink = Попробовать Firefox Send
|
||||||
.title = Попробовать Firefox Send
|
.title = Попробовать Firefox Send
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Presunutím súboru sem začnete nahrávanie
|
|||||||
uploadPageSizeMessage = Pre zaistenie čo najväčšej spoľahlivosti vám odporúčame nahrávať súbory menšie než 1GB.
|
uploadPageSizeMessage = Pre zaistenie čo najväčšej spoľahlivosti vám odporúčame nahrávať súbory menšie než 1GB.
|
||||||
uploadPageBrowseButton = Vyberte súbor vo vašom počítači
|
uploadPageBrowseButton = Vyberte súbor vo vašom počítači
|
||||||
.title = Vyberte súbor vo vašom počítači
|
.title = Vyberte súbor vo vašom počítači
|
||||||
|
uploadPageBrowseButton1 = Vyberte súbor na nahratie
|
||||||
|
.title = Vyberte súbor na nahratie
|
||||||
uploadPageMultipleFilesAlert = Nahrávanie viacerých súborov alebo priečinkov momentálne nie je podporované.
|
uploadPageMultipleFilesAlert = Nahrávanie viacerých súborov alebo priečinkov momentálne nie je podporované.
|
||||||
uploadPageBrowseButtonTitle = Nahrať súbor
|
uploadPageBrowseButtonTitle = Nahrať súbor
|
||||||
uploadingPageProgress = Nahrávanie súboru { $filename } ({ $size })
|
uploadingPageProgress = Nahrávanie súboru { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Tukaj spustite datoteko za začetek nalaganja
|
|||||||
uploadPageSizeMessage = Za zanesljivo delovanje je najbolje, da datoteka ne presega 1 GB
|
uploadPageSizeMessage = Za zanesljivo delovanje je najbolje, da datoteka ne presega 1 GB
|
||||||
uploadPageBrowseButton = Izberite datoteko na računalniku
|
uploadPageBrowseButton = Izberite datoteko na računalniku
|
||||||
.title = Izberite datoteko na računalniku
|
.title = Izberite datoteko na računalniku
|
||||||
|
uploadPageBrowseButton1 = Izberite datoteko za nalaganje
|
||||||
|
.title = Izberite datoteko za nalaganje
|
||||||
uploadPageMultipleFilesAlert = Nalaganje več datotek ali map trenutno ni podprto.
|
uploadPageMultipleFilesAlert = Nalaganje več datotek ali map trenutno ni podprto.
|
||||||
uploadPageBrowseButtonTitle = Naloži datoteko
|
uploadPageBrowseButtonTitle = Naloži datoteko
|
||||||
uploadingPageProgress = Nalaganje { $filename } ({ $size })
|
uploadingPageProgress = Nalaganje { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Превуците ваше датотеке овде д
|
|||||||
uploadPageSizeMessage = За бољи рад предлажемо да датотека не буде већа од 1GB
|
uploadPageSizeMessage = За бољи рад предлажемо да датотека не буде већа од 1GB
|
||||||
uploadPageBrowseButton = Изаберите датотеку на рачунару
|
uploadPageBrowseButton = Изаберите датотеку на рачунару
|
||||||
.title = Изаберите датотеку на рачунару
|
.title = Изаберите датотеку на рачунару
|
||||||
|
uploadPageBrowseButton1 = Изаберите датотеку за отпремање
|
||||||
|
.title = Изаберите датотеку за отпремање
|
||||||
uploadPageMultipleFilesAlert = Отпремање фасцикли или више датотека тренутно није подржано.
|
uploadPageMultipleFilesAlert = Отпремање фасцикли или више датотека тренутно није подржано.
|
||||||
uploadPageBrowseButtonTitle = Отпреми датотеку
|
uploadPageBrowseButtonTitle = Отпреми датотеку
|
||||||
uploadingPageProgress = Отпремам { $filename } ({ $size })
|
uploadingPageProgress = Отпремам { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Släpp filen här för att börja ladda upp
|
|||||||
uploadPageSizeMessage = För den mest tillförlitliga driften är det bäst att hålla din fil under 1 GB
|
uploadPageSizeMessage = För den mest tillförlitliga driften är det bäst att hålla din fil under 1 GB
|
||||||
uploadPageBrowseButton = Välj en fil på din dator
|
uploadPageBrowseButton = Välj en fil på din dator
|
||||||
.title = Välj en fil på din dator
|
.title = Välj en fil på din dator
|
||||||
|
uploadPageBrowseButton1 = Välj en fil att ladda upp
|
||||||
|
.title = Välj en fil att ladda upp
|
||||||
uploadPageMultipleFilesAlert = Överföring av flera filer eller en mapp stöds för närvarande inte.
|
uploadPageMultipleFilesAlert = Överföring av flera filer eller en mapp stöds för närvarande inte.
|
||||||
uploadPageBrowseButtonTitle = Ladda upp fil
|
uploadPageBrowseButtonTitle = Ladda upp fil
|
||||||
uploadingPageHeader = Överför din fil
|
uploadingPageProgress = Laddar upp { $filename } ({ $size })
|
||||||
importingFile = Importerar…
|
importingFile = Importerar…
|
||||||
verifyingFile = Verifierar…
|
verifyingFile = Verifierar…
|
||||||
encryptingFile = Krypterar…
|
encryptingFile = Krypterar…
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = Ladda ner
|
|||||||
.title = Ladda ner
|
.title = Ladda ner
|
||||||
downloadNotification = Din nedladdning har slutförts.
|
downloadNotification = Din nedladdning har slutförts.
|
||||||
downloadFinish = Nedladdning klar
|
downloadFinish = Nedladdning klar
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } av { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Testa Firefox Send
|
sendYourFilesLink = Testa Firefox Send
|
||||||
.title = Testa Firefox Send
|
.title = Testa Firefox Send
|
||||||
@@ -67,7 +71,7 @@ expiredPageHeader = Den här länken har upphört eller har aldrig existerat i f
|
|||||||
notSupportedHeader = Din webbläsare stöds inte.
|
notSupportedHeader = Din webbläsare stöds inte.
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
notSupportedDetail = Tyvärr stöder inte webbläsaren den webbteknologi som används av Firefox Send. Du måste försöka med en annan webbläsare. Vi rekommenderar Firefox!
|
notSupportedDetail = Tyvärr stöder inte webbläsaren den webbteknologi som används av Firefox Send. Du måste försöka med en annan webbläsare. Vi rekommenderar Firefox!
|
||||||
notSupportedLink = Varför stödjs inte min webbläsare?
|
notSupportedLink = Varför stöds inte min webbläsare?
|
||||||
notSupportedOutdatedDetail = Tyvärr stödjer den här versionen av Firefox inte webbtekniken som driver Firefox Send. Du måste uppdatera din webbläsare.
|
notSupportedOutdatedDetail = Tyvärr stödjer den här versionen av Firefox inte webbtekniken som driver Firefox Send. Du måste uppdatera din webbläsare.
|
||||||
updateFirefox = Uppdatera Firefox
|
updateFirefox = Uppdatera Firefox
|
||||||
downloadFirefoxButtonSub = Gratis nedladdning
|
downloadFirefoxButtonSub = Gratis nedladdning
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ uploadPageDropMessage = ఎగుమతిని ప్రారంభించ
|
|||||||
uploadPageSizeMessage = అత్యంత నమ్మకమైన కార్యం కోసం, మీ ఫైలును 1GB కంటే తక్కువగా ఉంచడం ఉత్తమం
|
uploadPageSizeMessage = అత్యంత నమ్మకమైన కార్యం కోసం, మీ ఫైలును 1GB కంటే తక్కువగా ఉంచడం ఉత్తమం
|
||||||
uploadPageBrowseButton = మీ కంప్యూటర్లో ఒక ఫైలును ఎంచుకోండి
|
uploadPageBrowseButton = మీ కంప్యూటర్లో ఒక ఫైలును ఎంచుకోండి
|
||||||
.title = మీ కంప్యూటర్లో ఒక ఫైలును ఎంచుకోండి
|
.title = మీ కంప్యూటర్లో ఒక ఫైలును ఎంచుకోండి
|
||||||
|
uploadPageBrowseButton1 = ఎక్కించటానికి ఒక ఫైలును ఎంచుకోండి
|
||||||
|
.title = ఎక్కించటానికి ఒక ఫైలును ఎంచుకోండి
|
||||||
uploadPageBrowseButtonTitle = ఫైలును ఎగుమతి చేయండి
|
uploadPageBrowseButtonTitle = ఫైలును ఎగుమతి చేయండి
|
||||||
uploadingPageHeader = మీ ఫైలు ఎగుమతి అవుతుంది
|
uploadingPageProgress = { $filename } ({ $size }) ఎక్కుతోంది
|
||||||
importingFile = దిగుమతవుతోంది...
|
importingFile = దిగుమతవుతోంది...
|
||||||
verifyingFile = పరిశీలిస్తున్నది…
|
verifyingFile = పరిశీలిస్తున్నది…
|
||||||
encryptingFile = గుప్తీకరిస్తోంది...
|
encryptingFile = గుప్తీకరిస్తోంది...
|
||||||
@@ -45,6 +47,8 @@ downloadButtonLabel = దిగుమతి
|
|||||||
.title = దిగుమతి
|
.title = దిగుమతి
|
||||||
downloadNotification = మీ దిగుమతి పూర్తయ్యింది.
|
downloadNotification = మీ దిగుమతి పూర్తయ్యింది.
|
||||||
downloadFinish = దిగుమతి పూర్తయింది
|
downloadFinish = దిగుమతి పూర్తయింది
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = { $totalSize }) యొక్క ({ $partialSize }
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Firefox sendను ప్రయత్నించండి
|
sendYourFilesLink = Firefox sendను ప్రయత్నించండి
|
||||||
.title = Firefox sendను ప్రయత్నించండి
|
.title = Firefox sendను ప్రయత్నించండి
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ uploadPageDropMessage = Yüklemeyi başlatmak için dosyanızı buraya bırakın
|
|||||||
uploadPageSizeMessage = Sorun yaşamamak adına dosyanızın 1 GB’den küçük olmasını öneririz
|
uploadPageSizeMessage = Sorun yaşamamak adına dosyanızın 1 GB’den küçük olmasını öneririz
|
||||||
uploadPageBrowseButton = Bilgisayarınızdan bir dosya seçin
|
uploadPageBrowseButton = Bilgisayarınızdan bir dosya seçin
|
||||||
.title = Bilgisayarınızdan bir dosya seçin
|
.title = Bilgisayarınızdan bir dosya seçin
|
||||||
|
uploadPageBrowseButton1 = Yüklenecek dosyayı seçin
|
||||||
|
.title = Yüklenecek dosyayı seçin
|
||||||
uploadPageMultipleFilesAlert = Birden fazla dosya veya klasör yükleme şimdilik desteklenmiyor.
|
uploadPageMultipleFilesAlert = Birden fazla dosya veya klasör yükleme şimdilik desteklenmiyor.
|
||||||
uploadPageBrowseButtonTitle = Dosyayı yükle
|
uploadPageBrowseButtonTitle = Dosyayı yükle
|
||||||
uploadingPageHeader = Dosyanız yükleniyor
|
uploadingPageProgress = { $filename } yükleniyor ({ $size })
|
||||||
importingFile = İçe aktarılıyor…
|
importingFile = İçe aktarılıyor…
|
||||||
verifyingFile = Doğrulanıyor…
|
verifyingFile = Doğrulanıyor…
|
||||||
encryptingFile = Şifreleniyor…
|
encryptingFile = Şifreleniyor…
|
||||||
@@ -50,6 +52,8 @@ downloadButtonLabel = İndir
|
|||||||
.title = İndir
|
.title = İndir
|
||||||
downloadNotification = İndirme tamamlandı.
|
downloadNotification = İndirme tamamlandı.
|
||||||
downloadFinish = İndirme tamamlandı
|
downloadFinish = İndirme tamamlandı
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } / { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||||
sendYourFilesLink = Firefox Send’i deneyin
|
sendYourFilesLink = Firefox Send’i deneyin
|
||||||
.title = Firefox Send’i deneyin
|
.title = Firefox Send’i deneyin
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ title = Firefox Send
|
|||||||
siteSubtitle = веб-експеримент
|
siteSubtitle = веб-експеримент
|
||||||
siteFeedback = Відгуки
|
siteFeedback = Відгуки
|
||||||
uploadPageHeader = Приватний, зашифрований обмін файлами
|
uploadPageHeader = Приватний, зашифрований обмін файлами
|
||||||
uploadPageExplainer = Надсилайте файли, використовуючи безпечні, приватні та зашифровані посилання, термін дії яких автоматично закінчується, щоб ваші файли не лишився в Інтернеті назавжди.
|
uploadPageExplainer = Надсилайте файли, використовуючи безпечні, приватні та зашифровані посилання, термін дії яких автоматично закінчується, щоб ваші файли не лишилися в Інтернеті назавжди.
|
||||||
uploadPageLearnMore = Докладніше
|
uploadPageLearnMore = Докладніше
|
||||||
uploadPageDropMessage = Перетягніть свій файл сюди, щоб почати вивантаження
|
uploadPageDropMessage = Перетягніть свій файл сюди, щоб почати вивантаження
|
||||||
uploadPageSizeMessage = Для більш надійної роботи сервісу, розмір вашого файлу не має перевищувати 1ГБ.
|
uploadPageSizeMessage = Для більш надійної роботи сервісу, розмір вашого файлу не має перевищувати 1ГБ.
|
||||||
uploadPageBrowseButton = Виберіть файл на комп'ютері
|
uploadPageBrowseButton = Виберіть файл на комп'ютері
|
||||||
.title = Виберіть файл на комп'ютері
|
.title = Виберіть файл на комп'ютері
|
||||||
|
uploadPageBrowseButton1 = Виберіть файл для вивантаження
|
||||||
|
.title = Виберіть файл для вивантаження
|
||||||
uploadPageMultipleFilesAlert = Вивантаження кількох файлів чи тек на даний момент не підтримується.
|
uploadPageMultipleFilesAlert = Вивантаження кількох файлів чи тек на даний момент не підтримується.
|
||||||
uploadPageBrowseButtonTitle = Вивантажити файл
|
uploadPageBrowseButtonTitle = Вивантажити файл
|
||||||
uploadingPageProgress = Вивантажуємо { $filename } ({ $size })
|
uploadingPageProgress = Вивантажуємо { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = Kéo thả tập tin của bạn vào đây và bắt đ
|
|||||||
uploadPageSizeMessage = Để có thể hoạt động tốt nhất, hãy giữ tập tin của bạn dưới 1GB.
|
uploadPageSizeMessage = Để có thể hoạt động tốt nhất, hãy giữ tập tin của bạn dưới 1GB.
|
||||||
uploadPageBrowseButton = Chọn một tập tin từ máy tính
|
uploadPageBrowseButton = Chọn một tập tin từ máy tính
|
||||||
.title = Chọn một tập tin từ máy tính
|
.title = Chọn một tập tin từ máy tính
|
||||||
|
uploadPageBrowseButton1 = Chọn tập tin để tải lên
|
||||||
|
.title = Chọn tập tin để tải lên
|
||||||
uploadPageMultipleFilesAlert = Tải lên nhiều tập tin một lúc hoặc tải lên một thư mục chưa được hỗ trợ.
|
uploadPageMultipleFilesAlert = Tải lên nhiều tập tin một lúc hoặc tải lên một thư mục chưa được hỗ trợ.
|
||||||
uploadPageBrowseButtonTitle = Tải tập tin lên
|
uploadPageBrowseButtonTitle = Tải tập tin lên
|
||||||
uploadingPageProgress = Đang tải lên { $filename } ({ $size })
|
uploadingPageProgress = Đang tải lên { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = 拖放您的文件到此处以开始上传
|
|||||||
uploadPageSizeMessage = 为保证运行稳定,建议文件大小不超过 1GB
|
uploadPageSizeMessage = 为保证运行稳定,建议文件大小不超过 1GB
|
||||||
uploadPageBrowseButton = 选择一个您电脑上的文件
|
uploadPageBrowseButton = 选择一个您电脑上的文件
|
||||||
.title = 选择一个您电脑上的文件
|
.title = 选择一个您电脑上的文件
|
||||||
|
uploadPageBrowseButton1 = 选择一个要上传的文件
|
||||||
|
.title = 选择一个要上传的文件
|
||||||
uploadPageMultipleFilesAlert = 目前不支持上传多个文件或上传文件夹。
|
uploadPageMultipleFilesAlert = 目前不支持上传多个文件或上传文件夹。
|
||||||
uploadPageBrowseButtonTitle = 上传文件
|
uploadPageBrowseButtonTitle = 上传文件
|
||||||
uploadingPageProgress = 正在上传 { $filename } ({ $size })
|
uploadingPageProgress = 正在上传 { $filename } ({ $size })
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ uploadPageDropMessage = 將檔案放到此處開始上傳
|
|||||||
uploadPageSizeMessage = 為了讓系統能最穩定地執行,請盡量將檔案控制在 1GB 以下。
|
uploadPageSizeMessage = 為了讓系統能最穩定地執行,請盡量將檔案控制在 1GB 以下。
|
||||||
uploadPageBrowseButton = 選擇您電腦上的檔案
|
uploadPageBrowseButton = 選擇您電腦上的檔案
|
||||||
.title = 選擇您電腦上的檔案
|
.title = 選擇您電腦上的檔案
|
||||||
|
uploadPageBrowseButton1 = 選擇要上傳的檔案
|
||||||
|
.title = 選擇要上傳的檔案
|
||||||
uploadPageMultipleFilesAlert = 目前暫不支援上傳多個檔案或資料夾。
|
uploadPageMultipleFilesAlert = 目前暫不支援上傳多個檔案或資料夾。
|
||||||
uploadPageBrowseButtonTitle = 上傳檔案
|
uploadPageBrowseButtonTitle = 上傳檔案
|
||||||
uploadingPageProgress = 正在上傳 { $filename }({ $size })
|
uploadingPageProgress = 正在上傳 { $filename }({ $size })
|
||||||
|
|||||||
BIN
public/resources/send-fb.jpg
Normal file
BIN
public/resources/send-fb.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 312 KiB |
BIN
public/resources/send-twitter.jpg
Normal file
BIN
public/resources/send-twitter.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@@ -1,6 +1,7 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const pkg = require('../package.json');
|
const pkg = require('../package.json');
|
||||||
|
const mkdirp = require('mkdirp');
|
||||||
|
|
||||||
let commit;
|
let commit;
|
||||||
|
|
||||||
@@ -10,11 +11,11 @@ try {
|
|||||||
// Whatever...
|
// Whatever...
|
||||||
}
|
}
|
||||||
|
|
||||||
const filename = path.join(__dirname, '..', 'public', 'version.json');
|
const filename = path.join(__dirname, '..', 'dist', 'public', 'version.json');
|
||||||
const filedata = {
|
const filedata = {
|
||||||
commit,
|
commit,
|
||||||
source: pkg.homepage,
|
source: pkg.homepage,
|
||||||
version: process.env.CIRCLE_TAG || `v${pkg.version}`
|
version: process.env.CIRCLE_TAG || `v${pkg.version}`
|
||||||
};
|
};
|
||||||
|
mkdirp.sync(path.dirname(filename));
|
||||||
fs.writeFileSync(filename, JSON.stringify(filedata, null, 2) + '\n');
|
fs.writeFileSync(filename, JSON.stringify(filedata, null, 2) + '\n');
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ const conf = convict({
|
|||||||
format: Boolean,
|
format: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
env: 'L10N_DEV'
|
env: 'L10N_DEV'
|
||||||
|
},
|
||||||
|
base_url: {
|
||||||
|
format: 'url',
|
||||||
|
default: 'https://send.firefox.com',
|
||||||
|
env: 'BASE_URL'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const storage = require('./storage.js');
|
|||||||
const Raven = require('raven');
|
const Raven = require('raven');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const version = require('../public/version.json');
|
const version = require('../dist/public/version.json');
|
||||||
|
|
||||||
if (conf.sentry_dsn) {
|
if (conf.sentry_dsn) {
|
||||||
Raven.config(conf.sentry_dsn).install();
|
Raven.config(conf.sentry_dsn).install();
|
||||||
@@ -19,7 +19,7 @@ const mozlog = require('./log.js');
|
|||||||
|
|
||||||
const log = mozlog('send.server');
|
const log = mozlog('send.server');
|
||||||
|
|
||||||
const STATIC_PATH = path.join(__dirname, '../public');
|
const STATIC_PATH = path.join(__dirname, '../dist/public');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@@ -38,14 +38,32 @@ function prodLangs() {
|
|||||||
|
|
||||||
const availableLanguages = conf.l10n_dev ? allLangs() : prodLangs();
|
const availableLanguages = conf.l10n_dev ? allLangs() : prodLangs();
|
||||||
|
|
||||||
|
// dev middleware is broken at the moment because of how webpack builds the
|
||||||
|
// handlebars templates. Leaving the commented code here as a mark of shame.
|
||||||
|
|
||||||
|
// if (conf.env === 'development') {
|
||||||
|
// const webpack = require('webpack');
|
||||||
|
// const webpackDevMiddleware = require('webpack-dev-middleware');
|
||||||
|
// const config = require('../webpack.config.js');
|
||||||
|
// config.devtool = 'inline-source-map';
|
||||||
|
// const compiler = webpack(config);
|
||||||
|
// const wdm = webpackDevMiddleware(compiler, {
|
||||||
|
// publicPath: config.output.publicPath
|
||||||
|
// });
|
||||||
|
// app.use(wdm);
|
||||||
|
// }
|
||||||
|
app.set('views', 'dist/views/');
|
||||||
app.engine(
|
app.engine(
|
||||||
'handlebars',
|
'handlebars',
|
||||||
exphbs({
|
exphbs({
|
||||||
defaultLayout: 'main',
|
defaultLayout: 'main',
|
||||||
partialsDir: 'views/partials/',
|
layoutsDir: 'dist/views/layouts',
|
||||||
helpers: {
|
helpers: {
|
||||||
availableLanguages,
|
availableLanguages,
|
||||||
l10nDev: conf.l10n_dev
|
baseUrl: conf.base_url,
|
||||||
|
title: 'Firefox Send',
|
||||||
|
description:
|
||||||
|
'Encrypt and send files with a link that automatically expires to ensure your important documents don’t stay online forever.'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -86,6 +104,14 @@ app.use(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
app.use(
|
||||||
|
'/resources',
|
||||||
|
express.static(path.join(STATIC_PATH, 'resources'), {
|
||||||
|
setHeaders: function(res) {
|
||||||
|
res.set('Cache-Control', 'public, max-age=31536000, immutable');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
app.use(express.static(STATIC_PATH));
|
app.use(express.static(STATIC_PATH));
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
@@ -135,7 +161,7 @@ app.get('/exists/:id', async (req, res) => {
|
|||||||
app.get('/download/:id', async (req, res) => {
|
app.get('/download/:id', async (req, res) => {
|
||||||
const id = req.params.id;
|
const id = req.params.id;
|
||||||
if (!validateID(id)) {
|
if (!validateID(id)) {
|
||||||
res.sendStatus(404);
|
res.status(404).render('notfound');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,24 +262,27 @@ app.post('/upload', (req, res, next) => {
|
|||||||
meta.delete = crypto.randomBytes(10).toString('hex');
|
meta.delete = crypto.randomBytes(10).toString('hex');
|
||||||
req.pipe(req.busboy);
|
req.pipe(req.busboy);
|
||||||
|
|
||||||
req.busboy.on('file', async (fieldname, file, filename) => {
|
req.busboy.on(
|
||||||
try {
|
'file',
|
||||||
await storage.set(newId, file, filename, meta);
|
async (fieldname, file, filename, encoding, mimeType) => {
|
||||||
|
try {
|
||||||
const protocol = conf.env === 'production' ? 'https' : req.protocol;
|
meta.mimeType = mimeType || 'application/octet-stream';
|
||||||
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
await storage.set(newId, file, filename, meta);
|
||||||
res.json({
|
const protocol = conf.env === 'production' ? 'https' : req.protocol;
|
||||||
url,
|
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
||||||
delete: meta.delete,
|
res.json({
|
||||||
id: newId
|
url,
|
||||||
});
|
delete: meta.delete,
|
||||||
} catch (e) {
|
id: newId
|
||||||
if (e.message === 'limit') {
|
});
|
||||||
return res.sendStatus(413);
|
} catch (e) {
|
||||||
|
if (e.message === 'limit') {
|
||||||
|
return res.sendStatus(413);
|
||||||
|
}
|
||||||
|
res.sendStatus(500);
|
||||||
}
|
}
|
||||||
res.sendStatus(500);
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
req.on('close', async err => {
|
req.on('close', async err => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,22 +1,124 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const HtmlPlugin = require('html-webpack-plugin');
|
||||||
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
|
vendor: ['babel-polyfill', 'raven-js'],
|
||||||
upload: ['./frontend/src/upload.js'],
|
upload: ['./frontend/src/upload.js'],
|
||||||
download: ['./frontend/src/download.js']
|
download: ['./frontend/src/download.js']
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: 'resources/[name].[chunkhash].js',
|
||||||
path: path.resolve(__dirname, 'public')
|
path: path.resolve(__dirname, 'dist/public'),
|
||||||
|
publicPath: '/'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
loaders: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
include: [path.resolve(__dirname, 'frontend'), path.resolve(__dirname, 'node_modules/testpilot-ga/src')],
|
include: [
|
||||||
query: { babelrc: false, presets: ['es2015', 'stage-2'], plugins: ['add-module-exports'] }
|
path.resolve(__dirname, 'frontend'),
|
||||||
|
path.resolve(__dirname, 'node_modules/testpilot-ga/src')
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
babelrc: false,
|
||||||
|
presets: [['es2015', { modules: false }], 'stage-2']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(svg|png|jpg)$/,
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: 'resources/[name].[hash].[ext]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: 'resources/[name].[hash].[ext]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'extract-loader',
|
||||||
|
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||||
|
'postcss-loader'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.hbs$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'html-loader',
|
||||||
|
options: {
|
||||||
|
interpolate: 'require',
|
||||||
|
minimize: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyPlugin([
|
||||||
|
{
|
||||||
|
context: 'public',
|
||||||
|
from: 'locales/**/*.ftl'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: 'public',
|
||||||
|
from: '*.*'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'views/**',
|
||||||
|
to: '../'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: 'node_modules/l20n/dist/web',
|
||||||
|
from: 'l20n.min.js'
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
new HtmlPlugin({
|
||||||
|
filename: '../views/index.handlebars',
|
||||||
|
template: 'webpack/upload.hbs',
|
||||||
|
chunks: ['upload']
|
||||||
|
}),
|
||||||
|
new HtmlPlugin({
|
||||||
|
filename: '../views/download.handlebars',
|
||||||
|
template: 'webpack/download.hbs',
|
||||||
|
chunks: ['download']
|
||||||
|
}),
|
||||||
|
new HtmlPlugin({
|
||||||
|
filename: '../views/legal.handlebars',
|
||||||
|
template: 'webpack/legal.hbs',
|
||||||
|
inject: false
|
||||||
|
}),
|
||||||
|
new HtmlPlugin({
|
||||||
|
filename: '../views/notfound.handlebars',
|
||||||
|
template: 'webpack/notfound.hbs',
|
||||||
|
inject: false
|
||||||
|
}),
|
||||||
|
new HtmlPlugin({
|
||||||
|
filename: '../views/layouts/main.handlebars',
|
||||||
|
template: 'webpack/layout.hbs',
|
||||||
|
inject: 'head',
|
||||||
|
excludeChunks: ['upload', 'download']
|
||||||
|
}),
|
||||||
|
new HtmlPlugin({
|
||||||
|
filename: '../views/unsupported.handlebars',
|
||||||
|
template: 'webpack/unsupported.hbs',
|
||||||
|
inject: false
|
||||||
|
}),
|
||||||
|
new webpack.HashedModuleIdsPlugin(),
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'vendor'
|
||||||
|
}),
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'runtime'
|
||||||
|
})
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<div id="download">
|
<div id="download">
|
||||||
<script src="/download.js"></script>
|
|
||||||
<div id="download-page-one">
|
<div id="download-page-one">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span id="dl-file"
|
<span id="dl-file"
|
||||||
@@ -11,17 +10,20 @@
|
|||||||
<span id="dl-filesize"></span>
|
<span id="dl-filesize"></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="../public/resources/illustration_download.svg" id="download-img" data-l10n-id="downloadAltText"/>
|
||||||
<div>
|
<div>
|
||||||
<button id="download-btn" data-l10n-id="downloadButtonLabel"></button>
|
<button id="download-btn" class="btn" data-l10n-id="downloadButtonLabel"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="download-progress" hidden="true">
|
<div id="download-progress" hidden="true">
|
||||||
<div id="dl-title" class="title"></div>
|
<div id="dl-title" class="title"></div>
|
||||||
<div class="description" data-l10n-id="downloadingPageMessage"></div>
|
<div class="description" data-l10n-id="downloadingPageMessage"></div>
|
||||||
<!-- progress bar here -->
|
<div class="progress-bar">
|
||||||
<div class="progress-bar" id="dl-progress">
|
<svg id="progress" width="166" height="166" viewPort="0 0 166 166" version="1.1">
|
||||||
|
<circle r="73" cx="83" cy="83" fill="transparent"/>
|
||||||
|
<circle id="bar" r="73" cx="83" cy="83" fill="transparent" transform="rotate(-90 83 83)" stroke-dasharray="458.67" stroke-dashoffset="458.67"/>
|
||||||
|
</svg>
|
||||||
<div class="percentage">
|
<div class="percentage">
|
||||||
<span class="percent-number"></span>
|
<span class="percent-number"></span>
|
||||||
<span class="percent-sign">%</span>
|
<span class="percent-sign">%</span>
|
||||||
@@ -32,5 +34,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="upload-error" hidden="true">
|
||||||
|
<div class="title" data-l10n-id="errorPageHeader"></div>
|
||||||
|
<img id="upload-error-img" data-l10n-id="errorAltText" src="../public/resources/illustration_error.svg"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a class="send-new" data-state="completed" data-l10n-id="sendYourFilesLink" href="/"></a>
|
<a class="send-new" data-state="completed" data-l10n-id="sendYourFilesLink" href="/"></a>
|
||||||
</div>
|
</div>
|
||||||
@@ -7,25 +7,34 @@
|
|||||||
<meta name="defaultLanguage" content="en-US">
|
<meta name="defaultLanguage" content="en-US">
|
||||||
<meta name="availableLanguages" content="{{availableLanguages}}">
|
<meta name="availableLanguages" content="{{availableLanguages}}">
|
||||||
|
|
||||||
<title>Firefox Send</title>
|
<meta property="og:title" content="{{title}}"/>
|
||||||
|
<meta name="twitter:title" content="{{title}}"/>
|
||||||
|
<meta name="description" content="{{description}}"/>
|
||||||
|
<meta property="og:description" content="{{description}}"/>
|
||||||
|
<meta name="twitter:description" content="{{description}}"/>
|
||||||
|
<meta name="twitter:card" content="summary"/>
|
||||||
|
<meta property="og:image" content="{{baseUrl}}${require('../public/resources/send-fb.jpg')}"/>
|
||||||
|
<meta name="twitter:image" content="{{baseUrl}}${require('../public/resources/send-twitter.jpg')}"/>
|
||||||
|
<meta property="og:url" content="{{baseUrl}}"/>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="/main.css" />
|
<title>{{title}}</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="${require('../frontend/src/main.css')}" />
|
||||||
{{#if fira}}
|
{{#if fira}}
|
||||||
<link rel="stylesheet" type="text/css" href="https://code.cdn.mozilla.net/fonts/fira.css" />
|
<link rel="stylesheet" type="text/css" href="https://code.cdn.mozilla.net/fonts/fira.css" />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="/resources/favicon-32x32.png" sizes="32x32" />
|
<link rel="icon" type="image/png" href="${require('../public/resources/favicon-32x32.png')}" sizes="32x32" />
|
||||||
<link rel="localization" href="/locales/{locale}/send.ftl">
|
<link rel="localization" href="/locales/{locale}/send.ftl">
|
||||||
|
|
||||||
<script src="/jsconfig.js"></script>
|
<script src="/jsconfig.js"></script>
|
||||||
<script src="/polyfill.min.js"></script>
|
|
||||||
<script defer src="/l20n.min.js"></script>
|
<script defer src="/l20n.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<div class="send-logo">
|
<div class="send-logo">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="/resources/send_logo.svg" alt="Send"/><h1 class="site-title">Send</h1>
|
<img src="../public/resources/send_logo.svg" alt="Send"/><h1 class="site-title">Send</h1>
|
||||||
</a>
|
</a>
|
||||||
<div class="site-subtitle">
|
<div class="site-subtitle">
|
||||||
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
||||||
@@ -44,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="legal-links">
|
<div class="legal-links">
|
||||||
<a href="https://www.mozilla.org"><img class="mozilla-logo" src="/resources/mozilla-logo.svg"/></a>
|
<a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="../public/resources/mozilla-logo.svg" alt="mozilla"/></a>
|
||||||
<a href="https://www.mozilla.org/about/legal" data-l10n-id="footerLinkLegal">Legal</a>
|
<a href="https://www.mozilla.org/about/legal" data-l10n-id="footerLinkLegal">Legal</a>
|
||||||
<a href="https://testpilot.firefox.com/about" data-l10n-id="footerLinkAbout">About Test Pilot</a>
|
<a href="https://testpilot.firefox.com/about" data-l10n-id="footerLinkAbout">About Test Pilot</a>
|
||||||
<a href="/legal" data-l10n-id="footerLinkPrivacy">Privacy</a>
|
<a href="/legal" data-l10n-id="footerLinkPrivacy">Privacy</a>
|
||||||
@@ -52,8 +61,8 @@
|
|||||||
<a href="https://www.mozilla.org/privacy/websites/#cookies" data-l10n-id="footerLinkCookies">Cookies</a>
|
<a href="https://www.mozilla.org/privacy/websites/#cookies" data-l10n-id="footerLinkCookies">Cookies</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="social-links">
|
<div class="social-links">
|
||||||
<a href="https://github.com/mozilla/send"><img class="github" src="/resources/github-icon.svg"/></a>
|
<a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="../public/resources/github-icon.svg" alt="github"/></a>
|
||||||
<a href="https://twitter.com/FxTestPilot"><img class="twitter" src="/resources/twitter-icon.svg"/></a>
|
<a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="../public/resources/twitter-icon.svg" alt="twitter"/></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<div id="download">
|
<div id="download">
|
||||||
<div class="title" data-l10n-id="expiredPageHeader"></div>
|
<div class="title" data-l10n-id="expiredPageHeader"></div>
|
||||||
<div class="share-window">
|
<div class="share-window">
|
||||||
<img src="/resources/illustration_expired.svg" id="expired-img" data-l10n-id="linkExpiredAlt"/>
|
<img src="../public/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="/" data-state="notfound" data-l10n-id="sendYourFilesLink"></a>
|
<a class="send-new" href="/" data-state="notfound" data-l10n-id="sendYourFilesLink"></a>
|
||||||
@@ -3,14 +3,14 @@
|
|||||||
{{#if outdated}}
|
{{#if outdated}}
|
||||||
<div class="description" data-l10n-id="notSupportedOutdatedDetail">Unfortunately this version of Firefox does not support the web technology that powers Firefox Send. You’ll need to update your browser.</div>
|
<div class="description" data-l10n-id="notSupportedOutdatedDetail">Unfortunately this version of Firefox does not support the web technology that powers Firefox Send. You’ll need to update your browser.</div>
|
||||||
<a id="update-firefox" href="https://support.mozilla.org/kb/update-firefox-latest-version">
|
<a id="update-firefox" href="https://support.mozilla.org/kb/update-firefox-latest-version">
|
||||||
<img src="/resources/firefox_logo-only.svg" class="firefox-logo" alt="Firefox"/>
|
<img src="../public/resources/firefox_logo-only.svg" class="firefox-logo" alt="Firefox"/>
|
||||||
<div class="unsupported-button-text" data-l10n-id="updateFirefox">Update Firefox</div>
|
<div class="unsupported-button-text" data-l10n-id="updateFirefox">Update Firefox</div>
|
||||||
</a>
|
</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="description" data-l10n-id="notSupportedDetail">Unfortunately this browser does not support the web technology that powers Firefox Send. You’ll need to try another browser. We recommend Firefox!</div>
|
<div class="description" data-l10n-id="notSupportedDetail">Unfortunately this browser does not support the web technology that powers Firefox Send. You’ll need to try another browser. We recommend Firefox!</div>
|
||||||
<div class="description"><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported" data-l10n-id="notSupportedLink">Why is my browser not supported?</a></div>
|
<div class="description"><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported" data-l10n-id="notSupportedLink">Why is my browser not supported?</a></div>
|
||||||
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?scene=2">
|
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?scene=2">
|
||||||
<img src="/resources/firefox_logo-only.svg" class="firefox-logo" alt="Firefox"/>
|
<img src="../public/resources/firefox_logo-only.svg" class="firefox-logo" alt="Firefox"/>
|
||||||
<div class="unsupported-button-text">Firefox<br>
|
<div class="unsupported-button-text">Firefox<br>
|
||||||
<span data-l10n-id="downloadFirefoxButtonSub">Free Download</span>
|
<span data-l10n-id="downloadFirefoxButtonSub">Free Download</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
<div id="page-one" hidden>
|
<div id="page-one" hidden>
|
||||||
<script src="/upload.js"></script>
|
|
||||||
<div class="title" data-l10n-id="uploadPageHeader"></div>
|
<div class="title" data-l10n-id="uploadPageHeader"></div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div data-l10n-id="uploadPageExplainer"></div>
|
<div data-l10n-id="uploadPageExplainer"></div>
|
||||||
<a href="https://testpilot.firefox.com/experiments/send" class="link" data-l10n-id="uploadPageLearnMore"></a>
|
<a href="https://testpilot.firefox.com/experiments/send" class="link" data-l10n-id="uploadPageLearnMore"></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="upload-window" >
|
<div class="upload-window" >
|
||||||
<div id="upload-img"><img data-l10n-id="uploadSvgAlt" src="/resources/upload.svg"/></div>
|
<div id="upload-img"><img data-l10n-id="uploadSvgAlt" src="../public/resources/upload.svg"/></div>
|
||||||
<div id="upload-text" data-l10n-id="uploadPageDropMessage"></div>
|
<div id="upload-text" data-l10n-id="uploadPageDropMessage"></div>
|
||||||
<span id="file-size-msg"><em data-l10n-id="uploadPageSizeMessage"></em></span>
|
<span id="file-size-msg"><em data-l10n-id="uploadPageSizeMessage"></em></span>
|
||||||
<form method="post" action="upload" enctype="multipart/form-data">
|
<form method="post" action="upload" enctype="multipart/form-data">
|
||||||
<label for="file-upload" id="browse"
|
<label for="file-upload" id="browse"
|
||||||
data-l10n-id="uploadPageBrowseButton"></label>
|
data-l10n-id="uploadPageBrowseButton1" class="btn"></label>
|
||||||
<input id="file-upload" type="file" name="fileUploaded" />
|
<input id="file-upload" type="file" name="fileUploaded" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,8 +36,11 @@
|
|||||||
<div id="upload-progress" hidden="true">
|
<div id="upload-progress" hidden="true">
|
||||||
<div class="title" id="upload-filename"></div>
|
<div class="title" id="upload-filename"></div>
|
||||||
<div class="description"></div>
|
<div class="description"></div>
|
||||||
<!-- progress bar here -->
|
<div class="progress-bar">
|
||||||
<div class="progress-bar" id="ul-progress">
|
<svg id="progress" width="166" height="166" viewPort="0 0 166 166" version="1.1">
|
||||||
|
<circle r="73" cx="83" cy="83" fill="transparent"/>
|
||||||
|
<circle id="bar" r="73" cx="83" cy="83" fill="transparent" transform="rotate(-90 83 83)" stroke-dasharray="458.67" stroke-dashoffset="458.67"/>
|
||||||
|
</svg>
|
||||||
<div class="percentage">
|
<div class="percentage">
|
||||||
<span class="percent-number">0</span>
|
<span class="percent-number">0</span>
|
||||||
<span class="percent-sign">%</span>
|
<span class="percent-sign">%</span>
|
||||||
@@ -58,9 +60,9 @@
|
|||||||
<div id="copy-text"></div>
|
<div id="copy-text"></div>
|
||||||
<div id="copy">
|
<div id="copy">
|
||||||
<input id="link" type="url" value="" readonly/>
|
<input id="link" type="url" value="" readonly/>
|
||||||
<button id="copy-btn" data-l10n-id="copyUrlFormButton"></button>
|
<button id="copy-btn" class="btn" data-l10n-id="copyUrlFormButton"></button>
|
||||||
</div>
|
</div>
|
||||||
<button id="delete-file" data-l10n-id="deleteFileButton"></button>
|
<button id="delete-file" class="btn" data-l10n-id="deleteFileButton"></button>
|
||||||
<a class="send-new" data-state="completed" data-l10n-id="sendAnotherFileLink" href="/"></a>
|
<a class="send-new" data-state="completed" data-l10n-id="sendAnotherFileLink" href="/"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,6 +70,6 @@
|
|||||||
<div id="upload-error" hidden="true">
|
<div id="upload-error" hidden="true">
|
||||||
<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="../public/resources/illustration_error.svg"/>
|
||||||
<a class="send-new" data-state="errored" data-l10n-id="sendAnotherFileLink"></a>
|
<a class="send-new" href="/" data-state="errored" data-l10n-id="sendAnotherFileLink"></a>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user