Update lufi to only use Lufi API
This commit is contained in:
parent
e372e660cb
commit
51f3181b4a
|
@ -13,3 +13,7 @@ stop-upload
|
||||||
themes/*
|
themes/*
|
||||||
!themes/default
|
!themes/default
|
||||||
!themes/default/*
|
!themes/default/*
|
||||||
|
.stignore
|
||||||
|
.stfolder/
|
||||||
|
TODO
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,7 @@
|
||||||
# Set to '' to disable CSP header
|
# Set to '' to disable CSP header
|
||||||
# https://content-security-policy.com/ provides a good documentation about CSP.
|
# https://content-security-policy.com/ provides a good documentation about CSP.
|
||||||
# https://report-uri.com/home/generate provides a tool to generate a CSP header.
|
# https://report-uri.com/home/generate provides a tool to generate a CSP header.
|
||||||
# optional, default is "base-uri 'self'; connect-src 'self' ws://YOUR_HOST; default-src 'none'; font-src 'self'; form-action 'self'; frame-ancestors 'none'; img-src 'self' blob:; media-src blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"
|
# optional, default is "base-uri 'self'; connect-src 'self' ws://YOUR_HOST; default-src 'none'; font-src 'self'; form-action 'self'; frame-ancestors 'none'; img-src 'self' blob:; media-src blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'"
|
||||||
#csp => "",
|
#csp => "",
|
||||||
|
|
||||||
# X-Frame-Options header that will be sent by Lufi
|
# X-Frame-Options header that will be sent by Lufi
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
Revision history for Lufi
|
Revision history for Lufi
|
||||||
|
|
||||||
0.08.0 ????-??-??
|
0.08.0 ????-??-??
|
||||||
|
- Use Lufi API
|
||||||
|
- Password encryption is now done client side, through Lufi API
|
||||||
|
- Update default CSP to allow "blob:"
|
||||||
|
|
||||||
|
|
||||||
0.07.0 2023-12-25
|
0.07.0 2023-12-25
|
||||||
- ⬆️ — Update jQuery
|
- ⬆️ — Update jQuery
|
||||||
|
|
|
@ -11,7 +11,7 @@ sub register {
|
||||||
if (!defined($app->config('csp')) || (defined($app->config('csp')) && $app->config('csp') ne '')) {
|
if (!defined($app->config('csp')) || (defined($app->config('csp')) && $app->config('csp') ne '')) {
|
||||||
my $directives = {
|
my $directives = {
|
||||||
'default-src' => "'none'",
|
'default-src' => "'none'",
|
||||||
'script-src' => "'self' 'unsafe-inline' 'unsafe-eval'",
|
'script-src' => "'self' 'unsafe-inline' 'unsafe-eval' blob:",
|
||||||
'style-src' => "'self' 'unsafe-inline'",
|
'style-src' => "'self' 'unsafe-inline'",
|
||||||
'img-src' => "'self' blob:",
|
'img-src' => "'self' blob:",
|
||||||
'media-src' => "blob:",
|
'media-src' => "blob:",
|
||||||
|
|
|
@ -337,7 +337,7 @@
|
||||||
# Set to '' to disable CSP header
|
# Set to '' to disable CSP header
|
||||||
# https://content-security-policy.com/ provides a good documentation about CSP.
|
# https://content-security-policy.com/ provides a good documentation about CSP.
|
||||||
# https://report-uri.com/home/generate provides a tool to generate a CSP header.
|
# https://report-uri.com/home/generate provides a tool to generate a CSP header.
|
||||||
# optional, default is "base-uri 'self'; connect-src 'self' ws://YOUR_HOST; default-src 'none'; font-src 'self'; form-action 'self'; frame-ancestors 'none'; img-src 'self' blob:; media-src blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"
|
# optional, default is "base-uri 'self'; connect-src 'self' ws://YOUR_HOST; default-src 'none'; font-src 'self'; form-action 'self'; frame-ancestors 'none'; img-src 'self' blob:; media-src blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'"
|
||||||
#csp => "",
|
#csp => "",
|
||||||
|
|
||||||
# X-Frame-Options header that will be sent by Lufi
|
# X-Frame-Options header that will be sent by Lufi
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -4,9 +4,9 @@ var entityMap = {
|
||||||
"&": "&",
|
"&": "&",
|
||||||
"<": "<",
|
"<": "<",
|
||||||
">": ">",
|
">": ">",
|
||||||
'"': '"',
|
'"': """,
|
||||||
"'": ''',
|
"'": "'",
|
||||||
"/": '/'
|
"/": "/",
|
||||||
};
|
};
|
||||||
|
|
||||||
function escapeHtml(string) {
|
function escapeHtml(string) {
|
||||||
|
@ -18,17 +18,20 @@ function changeLang() {
|
||||||
window.location = langUrl + $(this).val();
|
window.location = langUrl + $(this).val();
|
||||||
}
|
}
|
||||||
function formatDate(unixTimestamp) {
|
function formatDate(unixTimestamp) {
|
||||||
return new Date(unixTimestamp * 1000).toLocaleString(window.navigator.language, {
|
return new Date(unixTimestamp * 1000).toLocaleString(
|
||||||
year: 'numeric',
|
window.navigator.language,
|
||||||
month: 'long',
|
{
|
||||||
day: 'numeric',
|
year: "numeric",
|
||||||
weekday: 'long',
|
month: "long",
|
||||||
hour: '2-digit',
|
day: "numeric",
|
||||||
minute: '2-digit',
|
weekday: "long",
|
||||||
})
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('select').material_select();
|
$("select").material_select();
|
||||||
$(".select-lang select").on('change', changeLang);
|
$(".select-lang select").on("change", changeLang);
|
||||||
$(".select-lang-mobile select").on('change', changeLang);
|
$(".select-lang-mobile select").on("change", changeLang);
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,14 +17,17 @@ const filesizeDOM = document.getElementById("filesize");
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
let go = true;
|
let go = true;
|
||||||
|
|
||||||
filesizeDOM.innerHTML = filesize(filesizeDOM.attributes.getNamedItem("data-filesize").value, {
|
filesizeDOM.innerHTML = filesize(
|
||||||
|
filesizeDOM.attributes.getNamedItem("data-filesize").value,
|
||||||
|
{
|
||||||
base: 10,
|
base: 10,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (isPasswordNeeded()) {
|
if (isPasswordNeeded()) {
|
||||||
go = false;
|
go = false;
|
||||||
|
|
||||||
passwordDOM.focus()
|
passwordDOM.focus();
|
||||||
|
|
||||||
onPasswordEvents();
|
onPasswordEvents();
|
||||||
}
|
}
|
||||||
|
@ -34,12 +37,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isPasswordNeeded = () => document.querySelectorAll("#file_pwd").length === 1
|
const isPasswordNeeded = () =>
|
||||||
|
document.querySelectorAll("#file_pwd").length === 1;
|
||||||
|
|
||||||
const startDownload = () => {
|
const startDownload = () => {
|
||||||
warnOnReload();
|
warnOnReload();
|
||||||
|
|
||||||
|
|
||||||
lufi
|
lufi
|
||||||
.download(window.location, passwordDOM?.value)
|
.download(window.location, passwordDOM?.value)
|
||||||
.andThen((job) => {
|
.andThen((job) => {
|
||||||
|
@ -53,7 +56,7 @@ const startDownload = () => {
|
||||||
job.terminate();
|
job.terminate();
|
||||||
|
|
||||||
filesizeDOM.parentElement.append(abortedDOM);
|
filesizeDOM.parentElement.append(abortedDOM);
|
||||||
warnOnReload(false)
|
warnOnReload(false);
|
||||||
|
|
||||||
document.getElementById("reloadLocation").onclick = (e) => {
|
document.getElementById("reloadLocation").onclick = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -65,8 +68,8 @@ const startDownload = () => {
|
||||||
})
|
})
|
||||||
.mapErr((error) => {
|
.mapErr((error) => {
|
||||||
addAlert(error.message);
|
addAlert(error.message);
|
||||||
warnOnReload(false)
|
warnOnReload(false);
|
||||||
remove(["abort"])
|
remove(["abort"]);
|
||||||
})
|
})
|
||||||
.andThen((job) => {
|
.andThen((job) => {
|
||||||
notify(i18n.fileDownloaded, job.lufiFile.name);
|
notify(i18n.fileDownloaded, job.lufiFile.name);
|
||||||
|
@ -115,20 +118,22 @@ const remove = (elements) => {
|
||||||
if (document.getElementById(id)) {
|
if (document.getElementById(id)) {
|
||||||
document.getElementById(id).remove();
|
document.getElementById(id).remove();
|
||||||
} else {
|
} else {
|
||||||
console.error(`${id} does not exist`)
|
console.error(`${id} does not exist`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPasswordEvents = () => {
|
const onPasswordEvents = () => {
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
document.getElementsByClassName("file-progress")[0].classList.remove("hide");
|
document
|
||||||
|
.getElementsByClassName("file-progress")[0]
|
||||||
|
.classList.remove("hide");
|
||||||
document.getElementsByClassName("file-abort")[0].classList.remove("hide");
|
document.getElementsByClassName("file-abort")[0].classList.remove("hide");
|
||||||
|
|
||||||
passwordDOM.parentElement.parentElement.classList.add("hide");
|
passwordDOM.parentElement.parentElement.classList.add("hide");
|
||||||
|
|
||||||
startDownload();
|
startDownload();
|
||||||
}
|
};
|
||||||
|
|
||||||
document.getElementById("go").onclick = () => {
|
document.getElementById("go").onclick = () => {
|
||||||
callback();
|
callback();
|
||||||
|
@ -138,8 +143,8 @@ const onPasswordEvents = () => {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
// Something's wring
|
// Something's wring
|
||||||
const addAlert = (msg) => {
|
const addAlert = (msg) => {
|
||||||
|
@ -156,7 +161,7 @@ const addAlert = (msg) => {
|
||||||
<strong>${msg}</strong>
|
<strong>${msg}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
};
|
||||||
|
|
||||||
const warnOnReload = (toWarn = true) => {
|
const warnOnReload = (toWarn = true) => {
|
||||||
if (toWarn) {
|
if (toWarn) {
|
||||||
|
@ -164,14 +169,15 @@ const warnOnReload = (toWarn = true) => {
|
||||||
} else {
|
} else {
|
||||||
window.onbeforeunload = null;
|
window.onbeforeunload = null;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const updateProgress = (lufiFile) => {
|
const updateProgress = (lufiFile) => {
|
||||||
// Update loading text
|
// Update loading text
|
||||||
loadingDOM.textContent = i18n.loading.replace(/XX1/, lufiFile.chunksReady);
|
loadingDOM.textContent = i18n.loading.replace(/XX1/, lufiFile.chunksReady);
|
||||||
|
|
||||||
// Update progress bar
|
// Update progress bar
|
||||||
const percent = Math.round((1000 * lufiFile.chunksReady) / lufiFile.totalChunks) / 10;
|
const percent =
|
||||||
|
Math.round((1000 * lufiFile.chunksReady) / lufiFile.totalChunks) / 10;
|
||||||
const wClass = percent.toString().replace(".", "-");
|
const wClass = percent.toString().replace(".", "-");
|
||||||
|
|
||||||
const pb = document.getElementById("pb");
|
const pb = document.getElementById("pb");
|
||||||
|
@ -179,59 +185,61 @@ const updateProgress = (lufiFile) => {
|
||||||
pb.attributes.getNamedItem("aria-valuenow").value = percent;
|
pb.attributes.getNamedItem("aria-valuenow").value = percent;
|
||||||
|
|
||||||
document.getElementById("pbt").innerHTML = `${percent}%`;
|
document.getElementById("pbt").innerHTML = `${percent}%`;
|
||||||
}
|
};
|
||||||
|
|
||||||
const showZipContent = (blob) => {
|
const showZipContent = (blob) => {
|
||||||
const showZipContentDOM = document.getElementById('showZipContent');
|
const showZipContentDOM = document.getElementById("showZipContent");
|
||||||
|
|
||||||
const showZipContentDOMListener = () => {
|
const showZipContentDOMListener = () => {
|
||||||
JSZip.loadAsync(blob)
|
JSZip.loadAsync(blob).then((zip) => {
|
||||||
.then((zip) => {
|
|
||||||
const newElement = document.createElement("div");
|
const newElement = document.createElement("div");
|
||||||
|
|
||||||
let innerHTML = `<h3>${i18n.zipContent}</h3><ul>`;
|
let innerHTML = `<h3>${i18n.zipContent}</h3><ul>`;
|
||||||
|
|
||||||
|
|
||||||
zip.forEach(function (_relativePath, zipEntry) {
|
zip.forEach(function (_relativePath, zipEntry) {
|
||||||
innerHTML += `<li>
|
innerHTML += `<li>
|
||||||
${escapeHtml(zipEntry.name)}
|
${escapeHtml(zipEntry.name)}
|
||||||
(${filesize(zipEntry._data.uncompressedSize, { base: 10 })})
|
(${filesize(zipEntry._data.uncompressedSize, {
|
||||||
|
base: 10,
|
||||||
|
})})
|
||||||
<a href="#"
|
<a href="#"
|
||||||
download="${escapeHtml(zipEntry.name)}"
|
download="${escapeHtml(zipEntry.name)}"
|
||||||
class="download-zip-content"
|
class="download-zip-content"
|
||||||
title="${i18n.download}">
|
title="${i18n.download}">
|
||||||
<i class="mdi-file-file-download"></i>
|
<i class="mdi-file-file-download"></i>
|
||||||
</a>
|
</a>
|
||||||
</li>`
|
</li>`;
|
||||||
});
|
});
|
||||||
|
|
||||||
innerHTML += '</ul>';
|
innerHTML += "</ul>";
|
||||||
|
|
||||||
newElement.innerHTML = innerHTML
|
newElement.innerHTML = innerHTML;
|
||||||
|
|
||||||
pbd.append(newElement);
|
pbd.append(newElement);
|
||||||
|
|
||||||
console.debug()
|
console.debug();
|
||||||
|
|
||||||
document.querySelectorAll('.download-zip-content').forEach((element) => {
|
document.querySelectorAll(".download-zip-content").forEach((element) => {
|
||||||
const elementListener = (e) => {
|
const elementListener = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var filename = element.getAttribute('download');
|
var filename = element.getAttribute("download");
|
||||||
zip.files[filename].async('blob').then((blob) => {
|
zip.files[filename].async("blob").then((blob) => {
|
||||||
element.removeEventListener('click', elementListener);
|
element.removeEventListener("click", elementListener);
|
||||||
element.setAttribute('href', URL.createObjectURL(blob));
|
element.setAttribute("href", URL.createObjectURL(blob));
|
||||||
element.click();
|
element.click();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
element.addEventListener('click', elementListener);
|
element.addEventListener("click", elementListener);
|
||||||
|
|
||||||
showZipContentDOM.style.display = "none";
|
showZipContentDOM.style.display = "none";
|
||||||
|
|
||||||
showZipContentDOM.removeEventListener('click', showZipContentDOMListener);
|
showZipContentDOM.removeEventListener(
|
||||||
|
"click",
|
||||||
|
showZipContentDOMListener
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
showZipContentDOM.onclick = showZipContentDOMListener
|
showZipContentDOM.onclick = showZipContentDOMListener;
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
|
@ -1,39 +1,32 @@
|
||||||
// vim:set sw=4 ts=4 sts=4 ft=javascript expandtab:
|
// vim:set sw=4 ts=4 sts=4 ft=javascript expandtab:
|
||||||
// Add item to localStorage
|
// Add item to localStorage
|
||||||
function addItem(item) {
|
const addItem = (item) => {
|
||||||
var files = localStorage.getItem(`${window.prefix}files`);
|
const files = JSON.parse(localStorage.getItem(`${window.prefix}files`)) || [];
|
||||||
if (files === null) {
|
|
||||||
files = new Array();
|
|
||||||
} else {
|
|
||||||
files = JSON.parse(files);
|
|
||||||
}
|
|
||||||
files.push(item);
|
files.push(item);
|
||||||
localStorage.setItem(`${window.prefix}files`, JSON.stringify(files));
|
localStorage.setItem(`${window.prefix}files`, JSON.stringify(files));
|
||||||
}
|
};
|
||||||
|
|
||||||
function delItem(name) {
|
const delItem = (name) => {
|
||||||
var files = localStorage.getItem(`${window.prefix}files`);
|
const files = JSON.parse(localStorage.getItem(`${window.prefix}files`)) || [];
|
||||||
if (files === null) {
|
|
||||||
files = new Array();
|
let i;
|
||||||
} else {
|
|
||||||
files = JSON.parse(files);
|
|
||||||
}
|
|
||||||
var i;
|
|
||||||
for (i = 0; i < files.length; i++) {
|
for (i = 0; i < files.length; i++) {
|
||||||
if (files[i].short === name) {
|
if (files[i].short === name) {
|
||||||
files.splice(i, 1);
|
files.splice(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
localStorage.setItem(`${window.prefix}files`, JSON.stringify(files));
|
localStorage.setItem(`${window.prefix}files`, JSON.stringify(files));
|
||||||
}
|
};
|
||||||
|
|
||||||
function itemExists(name) {
|
const itemExists = (name) => {
|
||||||
var files = localStorage.getItem(`${window.prefix}files`);
|
let files = localStorage.getItem(`${window.prefix}files`);
|
||||||
if (files === null) {
|
if (files === null) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
files = JSON.parse(files);
|
files = JSON.parse(files);
|
||||||
var i;
|
|
||||||
|
let i;
|
||||||
for (i = 0; i < files.length; i++) {
|
for (i = 0; i < files.length; i++) {
|
||||||
if (files[i].short === name) {
|
if (files[i].short === name) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -41,72 +34,96 @@ function itemExists(name) {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function invertSelection(event) {
|
const invertSelection = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
$('input[type="checkbox"]').each(function() {
|
document.querySelectorAll('input[type="checkbox"]').forEach((element) => {
|
||||||
var el = $(this);
|
element.click();
|
||||||
el.click();
|
|
||||||
if (el.attr('data-checked') && el.attr('data-checked') === 'data-checked') {
|
if (element.getAttribute("data-checked") === "data-checked") {
|
||||||
el.attr('data-checked', null);
|
element.setAttribute("data-checked", null);
|
||||||
} else {
|
} else {
|
||||||
el.attr('data-checked', 'data-checked');
|
element.setAttribute("data-checked", "data-checked");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
evaluateMassDelete();
|
evaluateMassDelete();
|
||||||
|
};
|
||||||
|
|
||||||
|
const purgeExpired = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const files = JSON.parse(localStorage.getItem(`${window.prefix}files`));
|
||||||
|
|
||||||
|
files.forEach(function (element) {
|
||||||
|
fetch(counterURL, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
short: element.short,
|
||||||
|
token: element.token,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Request error.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function purgeExpired(event) {
|
return response.json();
|
||||||
event.preventDefault();
|
})
|
||||||
var files = JSON.parse(localStorage.getItem(`${window.prefix}files`));
|
.then((data) => {
|
||||||
|
|
||||||
files.forEach(function(element, index, array) {
|
|
||||||
$.ajax({
|
|
||||||
url: counterURL,
|
|
||||||
method: 'POST',
|
|
||||||
dataType: 'json',
|
|
||||||
data: {
|
|
||||||
short: element.short,
|
|
||||||
token: element.token
|
|
||||||
},
|
|
||||||
success: function(data, textStatus, jqXHR) {
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
if (data.deleted) {
|
if (data.deleted) {
|
||||||
$(`#count-${data.short}`).parent().remove();
|
const elementToRemove = document.querySelector(
|
||||||
|
`#count-${data.short}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (elementToRemove) {
|
||||||
|
elementToRemove.parentElement.remove();
|
||||||
|
}
|
||||||
|
|
||||||
delItem(data.short);
|
delItem(data.short);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function exportStorage(event) {
|
const exportStorage = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var a = $('<a id="data-json">');
|
|
||||||
a.hide();
|
|
||||||
$('body').append(a);
|
|
||||||
|
|
||||||
var storageData = [localStorage.getItem(`${window.prefix}files`)];
|
const a = document.createElement("a");
|
||||||
var exportFile = new Blob(storageData, {type : 'application/json'});
|
a.id = "data-json";
|
||||||
var url = window.URL.createObjectURL(exportFile);
|
|
||||||
|
|
||||||
a.attr('href', url);
|
a.style.display = "none";
|
||||||
a.attr('download', 'data.json');
|
|
||||||
$('#data-json')[0].click();
|
|
||||||
$('#data-json').remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
function importStorage(f) {
|
document.body.append(a);
|
||||||
var reader = new FileReader();
|
|
||||||
reader.addEventListener("loadend", function() {
|
const storageData = [localStorage.getItem(`${window.prefix}files`)];
|
||||||
|
const exportFile = new Blob(storageData, { type: "application/json" });
|
||||||
|
const url = window.URL.createObjectURL(exportFile);
|
||||||
|
|
||||||
|
a.setAttribute("href", url);
|
||||||
|
a.setAttribute("download", "data.json");
|
||||||
|
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
const importStorage = (f) => {
|
||||||
|
let reader = new FileReader();
|
||||||
|
|
||||||
|
reader.addEventListener("loadend", () => {
|
||||||
try {
|
try {
|
||||||
var newFiles = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(reader.result)));
|
const newFiles = JSON.parse(
|
||||||
var i;
|
String.fromCharCode.apply(null, new Uint8Array(reader.result))
|
||||||
var hasImported = 0;
|
);
|
||||||
|
let i;
|
||||||
|
let hasImported = 0;
|
||||||
for (i = 0; i < newFiles.length; i++) {
|
for (i = 0; i < newFiles.length; i++) {
|
||||||
var item = newFiles[i];
|
const item = newFiles[i];
|
||||||
if (validURL(item.url) && !itemExists(item.short)) {
|
if (validURL(item.url) && !itemExists(item.short)) {
|
||||||
addItem(item);
|
addItem(item);
|
||||||
hasImported++;
|
hasImported++;
|
||||||
|
@ -120,98 +137,112 @@ function importStorage(f) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
reader.readAsArrayBuffer(f[0]);
|
reader.readAsArrayBuffer(f[0]);
|
||||||
}
|
};
|
||||||
|
|
||||||
function validURL(str) {
|
const validURL = (str) => {
|
||||||
try {
|
try {
|
||||||
var url = new URL(str);
|
return new URL(str).host ? true : false;
|
||||||
if (url.host) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const delFile = (element) => {
|
||||||
|
const deleteUrl = new URL(element.getAttribute("data-dlink"));
|
||||||
|
const short = element.getAttribute("data-short");
|
||||||
|
|
||||||
|
deleteUrl.searchParams.append("_format", "json");
|
||||||
|
|
||||||
|
fetch(deleteUrl, {
|
||||||
|
method: "GET",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Network error while deleting file");
|
||||||
}
|
}
|
||||||
|
|
||||||
function delFile() {
|
return response.json();
|
||||||
var dlink = $(this).attr('data-dlink');
|
})
|
||||||
var short = $(this).attr('data-short');
|
.then((data) => {
|
||||||
$.ajax({
|
|
||||||
url: dlink,
|
|
||||||
method: 'GET',
|
|
||||||
data: {
|
|
||||||
_format: 'json'
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
$(`#row-${short}`).remove();
|
document.getElementById(`row-${short}`).remove();
|
||||||
delItem(short);
|
delItem(short);
|
||||||
} else {
|
} else {
|
||||||
alert(data.msg);
|
alert(data.msg);
|
||||||
}
|
}
|
||||||
evaluateMassDelete();
|
evaluateMassDelete();
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
},
|
|
||||||
complete: function() {
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function evaluateMassDelete() {
|
const evaluateMassDelete = () => {
|
||||||
if ($('input[data-checked="data-checked"]').length > 0) {
|
const massDeleteDOM = document.getElementById("mass-delete");
|
||||||
$('#mass-delete').removeAttr('disabled');
|
|
||||||
$('#mass-delete').removeClass('disabled');
|
if (
|
||||||
|
document.querySelectorAll('input[data-checked="data-checked"]').length > 0
|
||||||
|
) {
|
||||||
|
massDeleteDOM.removeAttribute("disabled");
|
||||||
|
massDeleteDOM.classList.remove("disabled");
|
||||||
} else {
|
} else {
|
||||||
$('#mass-delete').attr('disabled');
|
massDeleteDOM.setAttribute("disabled", "disabled");
|
||||||
$('#mass-delete').addClass('disabled');
|
massDeleteDOM.classList.add("disabled");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function massDelete(event) {
|
const massDelete = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
$('input[data-checked="data-checked"]').each(delFile);
|
document
|
||||||
}
|
.querySelectorAll('input[data-checked="data-checked"]')
|
||||||
|
.forEach(delFile);
|
||||||
|
};
|
||||||
|
|
||||||
function populateFilesTable() {
|
const populateFilesTable = () => {
|
||||||
$('#myfiles').empty();
|
const myFilesDOM = document.getElementById("myfiles");
|
||||||
|
|
||||||
var files = localStorage.getItem(`${window.prefix}files`);
|
myFilesDOM.innerHTML = "";
|
||||||
|
|
||||||
|
let files = localStorage.getItem(`${window.prefix}files`);
|
||||||
if (files === null) {
|
if (files === null) {
|
||||||
var filesWithoutPrefix = localStorage.getItem('files');
|
var filesWithoutPrefix = localStorage.getItem("files");
|
||||||
if (filesWithoutPrefix !== null) {
|
if (filesWithoutPrefix !== null) {
|
||||||
if (window.confirm(i18n.importFilesWithoutPrefix)) {
|
if (window.confirm(i18n.importFilesWithoutPrefix)) {
|
||||||
localStorage.setItem(`${window.prefix}files`, filesWithoutPrefix);
|
localStorage.setItem(`${window.prefix}files`, filesWithoutPrefix);
|
||||||
files = JSON.parse(filesWithoutPrefix);
|
files = JSON.parse(filesWithoutPrefix);
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem(`${window.prefix}files`, JSON.stringify([]));
|
localStorage.setItem(`${window.prefix}files`, JSON.stringify([]));
|
||||||
files = new Array();
|
files = [];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
files = new Array();
|
files = [];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
files = JSON.parse(files);
|
files = JSON.parse(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
files.sort(function (a, b) {
|
files.sort(function (a, b) {
|
||||||
if (a.created_at < b.created_at) {
|
if (a.created_at < b.created_at) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (a.created_at > b.created_at) {
|
} else if (a.created_at > b.created_at) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
files.forEach(function(element, index, array) {
|
|
||||||
var del_view = (element.del_at_first_view) ? '<i class="small mdi-action-done"></i>' : '<i class="small mdi-navigation-close"></i>';
|
|
||||||
var dlink = `${actionURL}d/${element.short}/${element.token}`;
|
|
||||||
var limit = (element.delay === 0) ? i18n.noExpiration : formatDate(element.delay * 86400 + element.created_at);
|
|
||||||
var created_at = formatDate(element.created_at);
|
|
||||||
|
|
||||||
var tr = $(`<tr id="row-${element.short}">`);
|
files.forEach(function (element) {
|
||||||
tr.html(`<td class="center-align">
|
const del_view = element.del_at_first_view
|
||||||
|
? '<i class="small mdi-action-done"></i>'
|
||||||
|
: '<i class="small mdi-navigation-close"></i>';
|
||||||
|
const dlink = `${actionURL}d/${element.short}/${element.token}`;
|
||||||
|
const limit =
|
||||||
|
element.delay === 0
|
||||||
|
? i18n.noExpiration
|
||||||
|
: formatDate(element.delay * 86400 + element.created_at);
|
||||||
|
const created_at = formatDate(element.created_at);
|
||||||
|
|
||||||
|
const tr = document.createElement("tr");
|
||||||
|
tr.id = `row-${element.short}`;
|
||||||
|
|
||||||
|
tr.innerHTML = `<td class="center-align">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
id="check-${element.short}"
|
id="check-${element.short}"
|
||||||
data-short="${element.short}"
|
data-short="${element.short}"
|
||||||
|
@ -249,47 +280,72 @@ function populateFilesTable() {
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="center-align">
|
<td class="center-align">
|
||||||
<a href="${actionURL}m?links=["${element.short}"]"
|
<a href="${actionURL}m?links=["${
|
||||||
|
element.short
|
||||||
|
}"]"
|
||||||
class="classic"><i class="small mdi-communication-email"></i></a>
|
class="classic"><i class="small mdi-communication-email"></i></a>
|
||||||
</td>`);
|
</td>`;
|
||||||
$('#myfiles').append(tr);
|
|
||||||
$(`#del-${element.short}`).on('click', delFile);
|
|
||||||
$(`label[for="check-${element.short}"]`).on('click', function(){
|
|
||||||
if ($(`#check-${element.short}`).attr('data-checked') && $(`#check-${element.short}`).attr('data-checked') === 'data-checked') {
|
|
||||||
$(`#check-${element.short}`).attr('data-checked', null);
|
|
||||||
} else {
|
|
||||||
$(`#check-${element.short}`).attr('data-checked', 'data-checked');
|
|
||||||
}
|
|
||||||
evaluateMassDelete();
|
|
||||||
});
|
|
||||||
|
|
||||||
$.ajax({
|
myFilesDOM.append(tr);
|
||||||
url: counterURL,
|
|
||||||
method: 'POST',
|
document.getElementById(`del-${element.short}`).onclick = (event) =>
|
||||||
dataType: 'json',
|
delFile(event.target.parentElement);
|
||||||
data: {
|
|
||||||
short: element.short,
|
document.querySelector(`label[for="check-${element.short}"]`).onclick = (
|
||||||
token: element.token
|
event
|
||||||
},
|
) => {
|
||||||
success: function(data, textStatus, jqXHR) {
|
const checkDOM = document.getElementById(`check-${element.short}`);
|
||||||
if (data.success) {
|
|
||||||
$(`#count-${data.short}`).html(data.counter);
|
if (checkDOM.getAttribute("data-checked") === "data-checked") {
|
||||||
if (data.deleted) {
|
checkDOM.setAttribute("data-checked", null);
|
||||||
$(`#count-${data.short}`).parent().addClass('purple lighten-4');
|
} else {
|
||||||
|
checkDOM.setAttribute("data-checked", "data-checked");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evaluateMassDelete();
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch(counterURL, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
short: element.short,
|
||||||
|
token: element.token,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Request error.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
if (data.success) {
|
||||||
|
if (data.deleted) {
|
||||||
|
const countDOM = document.getElementById(`count-${data.short}`);
|
||||||
|
|
||||||
|
countDOM.innerHTML = data.counter;
|
||||||
|
|
||||||
|
if (data.deleted) {
|
||||||
|
countDOM.parentElement.classList.add("purple", "lighten-4");
|
||||||
} else {
|
} else {
|
||||||
alert(data.msg);
|
alert(data.msg);
|
||||||
$(`#count-${data.short}`).parent().remove();
|
countDOM.parentElement.remove();
|
||||||
|
|
||||||
if (data.missing) {
|
if (data.missing) {
|
||||||
delItem(data.short);
|
delItem(data.short);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function clickImport(event) {
|
const clickImport = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
$('#import').click();
|
document.getElementById("import").click();
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
// vim:set sw=4 ts=4 sts=4 ft=javascript expandtab:
|
// vim:set sw=4 ts=4 sts=4 ft=javascript expandtab:
|
||||||
|
|
||||||
import { lufi, okAsync, errAsync } from "/js/lufi.js";
|
import {
|
||||||
|
lufi,
|
||||||
|
okAsync,
|
||||||
|
ResultAsync,
|
||||||
|
isSecureContext,
|
||||||
|
CryptoAlgorithm,
|
||||||
|
} from "/js/lufi.js";
|
||||||
|
|
||||||
// Cancelled files indexes
|
// Cancelled files indexes
|
||||||
window.cancelled = [];
|
window.cancelled = [];
|
||||||
// Set websocket
|
|
||||||
// window.ws = spawnWebsocket(0, function () {
|
|
||||||
// return null;
|
|
||||||
// });
|
|
||||||
// Use slice of 0.75MB
|
|
||||||
window.sliceLength = 750000;
|
|
||||||
// Global zip objects for currently created zip file
|
// Global zip objects for currently created zip file
|
||||||
window.zip = null;
|
|
||||||
window.zipSize = 0;
|
window.zipSize = 0;
|
||||||
// Init the list of files (used by LDAP invitation feature)
|
// Init the list of files (used by LDAP invitation feature)
|
||||||
window.filesURLs = [];
|
window.filesURLs = [];
|
||||||
|
|
||||||
|
let archiveEntries;
|
||||||
|
|
||||||
// Copy a link to clipboard
|
// Copy a link to clipboard
|
||||||
function copyToClipboard(txt) {
|
function copyToClipboard(txt) {
|
||||||
var textArea = document.createElement("textarea");
|
const textArea = document.createElement("textarea");
|
||||||
textArea.className = "textarea-hidden";
|
textArea.className = "textarea-hidden";
|
||||||
textArea.value = txt;
|
textArea.value = txt;
|
||||||
|
|
||||||
|
@ -56,7 +57,16 @@ function copyAllToClipboard(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add item to localStorage
|
// Add item to localStorage
|
||||||
function addItem(name, url, size, del_at_first_view, created_at, delay, short, token) {
|
function addItem(
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
size,
|
||||||
|
del_at_first_view,
|
||||||
|
created_at,
|
||||||
|
delay,
|
||||||
|
short,
|
||||||
|
token
|
||||||
|
) {
|
||||||
let files = localStorage.getItem(`${window.prefix}files`);
|
let files = localStorage.getItem(`${window.prefix}files`);
|
||||||
files = JSON.parse(files) || [];
|
files = JSON.parse(files) || [];
|
||||||
|
|
||||||
|
@ -79,7 +89,10 @@ function destroyBlock(clientKey) {
|
||||||
|
|
||||||
if (document.querySelectorAll(".link-input").length === 0) {
|
if (document.querySelectorAll(".link-input").length === 0) {
|
||||||
document.getElementById("misc").innerHTML = "";
|
document.getElementById("misc").innerHTML = "";
|
||||||
if (document.querySelectorAll("#results li").length === 0 && window.fileList === null) {
|
if (
|
||||||
|
document.querySelectorAll("#results li").length === 0 &&
|
||||||
|
window.fileList === null
|
||||||
|
) {
|
||||||
document.getElementById("results").style.display = "none";
|
document.getElementById("results").style.display = "none";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +106,8 @@ function firstViewClicking() {
|
||||||
.getElementById("first-view")
|
.getElementById("first-view")
|
||||||
.setAttribute(
|
.setAttribute(
|
||||||
"data-checked",
|
"data-checked",
|
||||||
document.getElementById("first-view").getAttribute("data-checked") === "data-checked"
|
document.getElementById("first-view").getAttribute("data-checked") ===
|
||||||
|
"data-checked"
|
||||||
? null
|
? null
|
||||||
: "data-checked"
|
: "data-checked"
|
||||||
);
|
);
|
||||||
|
@ -101,9 +115,11 @@ function firstViewClicking() {
|
||||||
|
|
||||||
// When clicking on zip checkbox
|
// When clicking on zip checkbox
|
||||||
function zipClicking() {
|
function zipClicking() {
|
||||||
if (document.getElementById("zip-files").getAttribute("data-checked") === "data-checked") {
|
if (
|
||||||
|
document.getElementById("zip-files").getAttribute("data-checked") ===
|
||||||
|
"data-checked"
|
||||||
|
) {
|
||||||
window.zipSize = 0;
|
window.zipSize = 0;
|
||||||
window.zip = null;
|
|
||||||
document.getElementById("zip-files").removeAttribute("data-checked");
|
document.getElementById("zip-files").removeAttribute("data-checked");
|
||||||
document.getElementById("zipname").value = "documents.zip";
|
document.getElementById("zipname").value = "documents.zip";
|
||||||
document.getElementById("zipname-input").classList.add("hide");
|
document.getElementById("zipname-input").classList.add("hide");
|
||||||
|
@ -112,7 +128,9 @@ function zipClicking() {
|
||||||
document.getElementById("zip-parts").innerHTML = "";
|
document.getElementById("zip-parts").innerHTML = "";
|
||||||
document.getElementById("delete-day").removeAttribute("disabled");
|
document.getElementById("delete-day").removeAttribute("disabled");
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("zip-files").setAttribute("data-checked", "data-checked");
|
document
|
||||||
|
.getElementById("zip-files")
|
||||||
|
.setAttribute("data-checked", "data-checked");
|
||||||
document.getElementById("zipname-input").classList.remove("hide");
|
document.getElementById("zipname-input").classList.remove("hide");
|
||||||
document.getElementById("zip-size").innerText = filesize(window.zipSize);
|
document.getElementById("zip-size").innerText = filesize(window.zipSize);
|
||||||
}
|
}
|
||||||
|
@ -120,14 +138,10 @@ function zipClicking() {
|
||||||
|
|
||||||
// Get the zip file name
|
// Get the zip file name
|
||||||
const getZipname = () => {
|
const getZipname = () => {
|
||||||
var zipname = document.getElementById("zipname").value || "documents.zip";
|
let zipname = document.getElementById("zipname").value || "documents.zip";
|
||||||
|
|
||||||
if (!zipname.endsWith(".zip")) {
|
if (!zipname.endsWith(".zip")) {
|
||||||
if (zipname.endsWith(".")) {
|
zipname += zipname.endsWith(".") ? "zip" : ".zip";
|
||||||
zipname += "zip";
|
|
||||||
} else {
|
|
||||||
zipname += ".zip";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return escapeHtml(zipname);
|
return escapeHtml(zipname);
|
||||||
|
@ -141,8 +155,8 @@ const updateZipname = () => {
|
||||||
// Create blob from zip
|
// Create blob from zip
|
||||||
const uploadZip = (e) => {
|
const uploadZip = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var delay = document.getElementById("delete-day");
|
const delay = document.getElementById("delete-day");
|
||||||
var del_at_first_view = document.getElementById("first-view");
|
const del_at_first_view = document.getElementById("first-view");
|
||||||
document.getElementById("zip-files").disabled = true;
|
document.getElementById("zip-files").disabled = true;
|
||||||
document.getElementById("file-browser-button").disabled = true;
|
document.getElementById("file-browser-button").disabled = true;
|
||||||
document.getElementById("file-browser-span").classList.add("disabled");
|
document.getElementById("file-browser-span").classList.add("disabled");
|
||||||
|
@ -150,10 +164,14 @@ const uploadZip = (e) => {
|
||||||
document.getElementById("zip-parts").textContent = "";
|
document.getElementById("zip-parts").textContent = "";
|
||||||
|
|
||||||
document.getElementById("zip-compressing").classList.remove("hide");
|
document.getElementById("zip-compressing").classList.remove("hide");
|
||||||
window.zip.generateAsync({ type: "blob" }).then((zipFile) => {
|
|
||||||
|
const zipname = getZipname();
|
||||||
|
|
||||||
|
lufi
|
||||||
|
.compress(archiveEntries, zipname)
|
||||||
|
.andThen((zipFile) => {
|
||||||
// if '#zipping' is hidden, the zipping has been aborted
|
// if '#zipping' is hidden, the zipping has been aborted
|
||||||
if (!document.getElementById("zipping").classList.contains("hide")) {
|
if (!document.getElementById("zipping").classList.contains("hide")) {
|
||||||
window.zip = null;
|
|
||||||
document.getElementById("zipping").classList.add("hide");
|
document.getElementById("zipping").classList.add("hide");
|
||||||
document.getElementById("files").classList.remove("m6");
|
document.getElementById("files").classList.remove("m6");
|
||||||
document.getElementById("files").classList.add("m12");
|
document.getElementById("files").classList.add("m12");
|
||||||
|
@ -162,21 +180,36 @@ const uploadZip = (e) => {
|
||||||
document.getElementById("uploadZip").classList.remove("hide");
|
document.getElementById("uploadZip").classList.remove("hide");
|
||||||
document.getElementById("results").style.display = "block";
|
document.getElementById("results").style.display = "block";
|
||||||
document.getElementById("zip-files").disabled = false;
|
document.getElementById("zip-files").disabled = false;
|
||||||
|
document.getElementById("zip-files").removeAttribute("data-checked");
|
||||||
|
document.getElementById("zip-files").checked = false;
|
||||||
|
|
||||||
var zipname = getZipname();
|
|
||||||
const password = document.getElementById("file_pwd").value;
|
const password = document.getElementById("file_pwd").value;
|
||||||
|
|
||||||
var file = new File([zipFile], zipname, { type: "application/zip" });
|
Materialize.toast(
|
||||||
|
i18n.enqueued.replace("XXX", zipname),
|
||||||
|
3000,
|
||||||
|
"teal accent-3"
|
||||||
|
);
|
||||||
|
|
||||||
Materialize.toast(i18n.enqueued.replace("XXX", zipname), 3000, "teal accent-3");
|
window.fileList = window.fileList || [zipFile];
|
||||||
|
|
||||||
window.fileList = window.fileList || [file];
|
startUpload(
|
||||||
|
[zipFile],
|
||||||
|
delay.value,
|
||||||
|
del_at_first_view.checked,
|
||||||
|
true,
|
||||||
|
zipname,
|
||||||
|
password
|
||||||
|
);
|
||||||
|
|
||||||
startUpload(file, delay.value, del_at_first_view.checked, true, password);
|
archiveEntries = undefined;
|
||||||
}
|
}
|
||||||
document.getElementById("file-browser-button").disabled = false;
|
document.getElementById("file-browser-button").disabled = false;
|
||||||
document.getElementById("file-browser-span").classList.remove("disabled");
|
document.getElementById("file-browser-span").classList.remove("disabled");
|
||||||
});
|
|
||||||
|
return okAsync(undefined);
|
||||||
|
})
|
||||||
|
.orElse((error) => console.error(error.message));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the mail link
|
// Update the mail link
|
||||||
|
@ -239,8 +272,7 @@ const handleDrop = (evt) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
|
||||||
var f = evt.dataTransfer.files; // FileList object
|
handleFiles(evt.dataTransfer.files);
|
||||||
handleFiles(f);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDragOver = (evt) => {
|
const handleDragOver = (evt) => {
|
||||||
|
@ -259,7 +291,9 @@ const bindDropZone = () => {
|
||||||
document.getElementById("file-browser-span").classList.add("cyan");
|
document.getElementById("file-browser-span").classList.add("cyan");
|
||||||
document.getElementById("file-browser-button").disabled = false;
|
document.getElementById("file-browser-button").disabled = false;
|
||||||
|
|
||||||
document.getElementById("file-browser-button").addEventListener("change", (e) => {
|
document
|
||||||
|
.getElementById("file-browser-button")
|
||||||
|
.addEventListener("change", (e) => {
|
||||||
handleFiles(e.target.files);
|
handleFiles(e.target.files);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -278,28 +312,51 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector('label[for="first-view"]').addEventListener("click", firstViewClicking);
|
document
|
||||||
document.querySelector('label[for="zip-files"]').addEventListener("click", zipClicking);
|
.querySelector('label[for="first-view"]')
|
||||||
|
.addEventListener("click", firstViewClicking);
|
||||||
|
document
|
||||||
|
.querySelector('label[for="zip-files"]')
|
||||||
|
.addEventListener("click", zipClicking);
|
||||||
document.getElementById("zipname").addEventListener("input", updateZipname);
|
document.getElementById("zipname").addEventListener("input", updateZipname);
|
||||||
document.getElementById("uploadZip").addEventListener("click", uploadZip);
|
document.getElementById("uploadZip").addEventListener("click", uploadZip);
|
||||||
|
|
||||||
document.getElementById("reset-zipping").addEventListener("click", () => {
|
document.getElementById("reset-zipping").addEventListener("click", () => {
|
||||||
window.zip = null;
|
archiveEntries = undefined;
|
||||||
document.querySelector('label[for="zip-files"]').click();
|
document.querySelector('label[for="zip-files"]').click();
|
||||||
document.getElementById("zip-files").disabled = false;
|
document.getElementById("zip-files").disabled = false;
|
||||||
|
document.getElementById("zip-files").removeAttribute("data-checked");
|
||||||
document.getElementById("zip-compressing").classList.add("hide");
|
document.getElementById("zip-compressing").classList.add("hide");
|
||||||
document.getElementById("file-browser-button").disabled = false;
|
document.getElementById("file-browser-button").disabled = false;
|
||||||
document.getElementById("file-browser-span").classList.remove("disabled");
|
document.getElementById("file-browser-span").classList.remove("disabled");
|
||||||
document.getElementById("files").classList.remove("m6").classList.add("m12");
|
document.getElementById("files").classList.replace("m6", "m12");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const startUpload = (file, delay, delAtFirstView, isZipped, password) => {
|
const startUpload = (
|
||||||
|
files,
|
||||||
|
delay,
|
||||||
|
delAtFirstView,
|
||||||
|
isZipped,
|
||||||
|
zipName,
|
||||||
|
password
|
||||||
|
) => {
|
||||||
let clientKey;
|
let clientKey;
|
||||||
|
|
||||||
lufi
|
return lufi
|
||||||
.upload(window.location, file, delay, delAtFirstView, isZipped, password)
|
.upload(
|
||||||
.andThen((job) => {
|
window.location,
|
||||||
|
files,
|
||||||
|
delay,
|
||||||
|
delAtFirstView,
|
||||||
|
isZipped,
|
||||||
|
zipName,
|
||||||
|
password,
|
||||||
|
isSecureContext() ? CryptoAlgorithm.WebCrypto : CryptoAlgorithm.Sjcl
|
||||||
|
)
|
||||||
|
.andThen((jobs) =>
|
||||||
|
ResultAsync.combine(
|
||||||
|
jobs.map((job) => {
|
||||||
clientKey = job.lufiFile.keys.client;
|
clientKey = job.lufiFile.keys.client;
|
||||||
|
|
||||||
createUploadBox(job);
|
createUploadBox(job);
|
||||||
|
@ -308,8 +365,8 @@ const startUpload = (file, delay, delAtFirstView, isZipped, password) => {
|
||||||
updateProgressBar(job.lufiFile);
|
updateProgressBar(job.lufiFile);
|
||||||
});
|
});
|
||||||
|
|
||||||
return job.waitForCompletion();
|
return job
|
||||||
})
|
.waitForCompletion()
|
||||||
.andThen((job) => {
|
.andThen((job) => {
|
||||||
notify(i18n.fileUploaded, job.lufiFile.name);
|
notify(i18n.fileUploaded, job.lufiFile.name);
|
||||||
|
|
||||||
|
@ -360,17 +417,24 @@ const startUpload = (file, delay, delAtFirstView, isZipped, password) => {
|
||||||
sendFilesURLs();
|
sendFilesURLs();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFiles = (files = []) => {
|
const handleFiles = (files = []) => {
|
||||||
const filesArray = Array.from(files);
|
const filesArray = Array.from(files);
|
||||||
const isZipped =
|
const isZipped =
|
||||||
document.getElementById("zip-files").getAttribute("data-checked") === "data-checked";
|
document.getElementById("zip-files").getAttribute("data-checked") ===
|
||||||
|
"data-checked";
|
||||||
|
|
||||||
|
document.body.style.cursor = "wait";
|
||||||
|
|
||||||
if (!isZipped) {
|
if (!isZipped) {
|
||||||
const delay = document.getElementById("delete-day").value;
|
const delay = document.getElementById("delete-day").value;
|
||||||
const delAtFirstView =
|
const delAtFirstView =
|
||||||
document.getElementById("first-view").getAttribute("data-checked") === "data-checked";
|
document.getElementById("first-view").getAttribute("data-checked") ===
|
||||||
|
"data-checked";
|
||||||
const password = document.getElementById("file_pwd").value;
|
const password = document.getElementById("file_pwd").value;
|
||||||
|
|
||||||
if (window.fileList === undefined || window.fileList === null) {
|
if (window.fileList === undefined || window.fileList === null) {
|
||||||
|
@ -392,43 +456,43 @@ const handleFiles = (files = []) => {
|
||||||
window.fileList = window.fileList.concat(filesArray); // Concatenate new files
|
window.fileList = window.fileList.concat(filesArray); // Concatenate new files
|
||||||
}
|
}
|
||||||
|
|
||||||
filesArray.forEach((file) => {
|
document.body.style.cursor = "default";
|
||||||
startUpload(file, delay, delAtFirstView, isZipped, password);
|
|
||||||
});
|
startUpload(filesArray, delay, delAtFirstView, isZipped, password);
|
||||||
} else {
|
} else {
|
||||||
window.zip = window.zip || new JSZip();
|
lufi
|
||||||
|
.addFilesToArchive(filesArray, archiveEntries)
|
||||||
|
.andThen((entries) => {
|
||||||
|
archiveEntries = entries;
|
||||||
|
|
||||||
document.getElementById("zipping").classList.remove("hide");
|
document.getElementById("zipping").classList.remove("hide");
|
||||||
const filesElement = document.getElementById("files");
|
const filesElement = document.getElementById("files");
|
||||||
filesElement.classList.remove("m12");
|
filesElement.classList.replace("m12", "m6");
|
||||||
filesElement.classList.add("m6");
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
const zipPartsDOM = document.getElementById("zip-parts");
|
||||||
const element = files.item(i);
|
|
||||||
let filename = element.name;
|
|
||||||
const originalName = filename;
|
|
||||||
let counter = 0;
|
|
||||||
|
|
||||||
// Ensure unique filename
|
zipPartsDOM.replaceChildren();
|
||||||
while (window.zip.files[filename] !== undefined) {
|
|
||||||
counter++;
|
for (const [name, file] of Object.entries(archiveEntries)) {
|
||||||
const extensionIndex = originalName.lastIndexOf(".");
|
window.zipSize += file.length;
|
||||||
const baseName = originalName.substring(0, extensionIndex);
|
|
||||||
const extension = originalName.substring(extensionIndex);
|
const listItemDOM = document.createElement("li");
|
||||||
filename = `${baseName}_(${counter})${extension}`;
|
listItemDOM.innerHTML = `— ${escapeHtml(name)} (${filesize(
|
||||||
|
file.length
|
||||||
|
)})`;
|
||||||
|
|
||||||
|
zipPartsDOM.appendChild(listItemDOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the file to the zip
|
document.getElementById("zip-size").textContent = filesize(
|
||||||
window.zip.file(filename, element);
|
window.zipSize
|
||||||
window.zipSize += element.size;
|
);
|
||||||
|
|
||||||
// Update DOM
|
document.body.style.cursor = "default";
|
||||||
document.getElementById("zip-size").textContent = filesize(window.zipSize);
|
|
||||||
const zipPartsElement = document.getElementById("zip-parts");
|
return okAsync(undefined);
|
||||||
const listItem = document.createElement("li");
|
})
|
||||||
listItem.innerHTML = `— ${escapeHtml(filename)} (${filesize(element.size)})`;
|
.orElse((error) => console.error(error.message));
|
||||||
zipPartsElement.appendChild(listItem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -450,7 +514,9 @@ const createUploadBox = (job) => {
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<span class="card-title"
|
<span class="card-title"
|
||||||
id="name-${clientKey}">${job.lufiFile.name}</span>
|
id="name-${clientKey}">${job.lufiFile.name}</span>
|
||||||
<span id="size-${clientKey}">(${filesize(job.lufiFile.size)})</span>
|
<span id="size-${clientKey}">(${filesize(
|
||||||
|
job.lufiFile.size
|
||||||
|
)})</span>
|
||||||
<p id="parts-${clientKey}"></p>
|
<p id="parts-${clientKey}"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
|
@ -501,7 +567,9 @@ const uploadBoxComplete = (lufiFile) => {
|
||||||
const limit =
|
const limit =
|
||||||
lufiFile.delay === 0
|
lufiFile.delay === 0
|
||||||
? i18n.noLimit
|
? i18n.noLimit
|
||||||
: `${i18n.expiration} ${formatDate(lufiFile.delay * 86400 + lufiFile.createdAt)}`;
|
: `${i18n.expiration} ${formatDate(
|
||||||
|
lufiFile.delay * 86400 + lufiFile.createdAt
|
||||||
|
)}`;
|
||||||
|
|
||||||
if (!isGuest) {
|
if (!isGuest) {
|
||||||
nameDOM.innerHTML += `${sizeDOM.innerHTML} <a href="${actionURL}m?links=${links}"><i class="mdi-communication-email"></i></a><br>${limit}`;
|
nameDOM.innerHTML += `${sizeDOM.innerHTML} <a href="${actionURL}m?links=${links}"><i class="mdi-communication-email"></i></a><br>${limit}`;
|
||||||
|
@ -542,7 +610,9 @@ const uploadBoxComplete = (lufiFile) => {
|
||||||
p1.appendChild(newDivDOM);
|
p1.appendChild(newDivDOM);
|
||||||
|
|
||||||
// Copy URL to clipboard
|
// Copy URL to clipboard
|
||||||
document.getElementById(`copyurl-${clientKey}`).addEventListener("click", (e) => {
|
document
|
||||||
|
.getElementById(`copyurl-${clientKey}`)
|
||||||
|
.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
copyToClipboard(downloadUrl);
|
copyToClipboard(downloadUrl);
|
||||||
});
|
});
|
||||||
|
@ -562,14 +632,17 @@ const uploadBoxComplete = (lufiFile) => {
|
||||||
<a href="#" id="copyall" class="btn btn-info">${i18n.copyAll}</a>
|
<a href="#" id="copyall" class="btn btn-info">${i18n.copyAll}</a>
|
||||||
<a id="mailto" href="${actionURL}m?links=${links}" class="btn btn-info">${i18n.mailTo}</a>
|
<a id="mailto" href="${actionURL}m?links=${links}" class="btn btn-info">${i18n.mailTo}</a>
|
||||||
`;
|
`;
|
||||||
document.getElementById("copyall").addEventListener("click", copyAllToClipboard);
|
document
|
||||||
|
.getElementById("copyall")
|
||||||
|
.addEventListener("click", copyAllToClipboard);
|
||||||
} else {
|
} else {
|
||||||
updateMailLink();
|
updateMailLink();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateProgressBar = (lufiFile) => {
|
const updateProgressBar = (lufiFile) => {
|
||||||
const percent = Math.round((1000 * lufiFile.chunksReady) / lufiFile.totalChunks) / 10;
|
const percent =
|
||||||
|
Math.round((1000 * lufiFile.chunksReady) / lufiFile.totalChunks) / 10;
|
||||||
const wClass = percent.toString().replace(".", "-");
|
const wClass = percent.toString().replace(".", "-");
|
||||||
|
|
||||||
const dp = document.getElementById(`progress-${lufiFile.keys.client}`);
|
const dp = document.getElementById(`progress-${lufiFile.keys.client}`);
|
||||||
|
@ -578,5 +651,7 @@ const updateProgressBar = (lufiFile) => {
|
||||||
dp.classList.add(`width-${wClass}`);
|
dp.classList.add(`width-${wClass}`);
|
||||||
dp.setAttribute("aria-valuenow", percent);
|
dp.setAttribute("aria-valuenow", percent);
|
||||||
|
|
||||||
document.getElementById(`parts-${lufiFile.keys.client}`).innerHTML = `${percent.toFixed(1)}%`;
|
document.getElementById(
|
||||||
|
`parts-${lufiFile.keys.client}`
|
||||||
|
).innerHTML = `${percent.toFixed(1)}%`;
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -13,10 +13,10 @@ var i18n = {
|
||||||
};
|
};
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
populateFilesTable();
|
populateFilesTable();
|
||||||
$('#invertSelection').on('click', invertSelection);
|
document.getElementById('invertSelection').onclick = (event) => invertSelection(event);
|
||||||
$('#exportStorage').on('click', exportStorage);
|
document.getElementById('exportStorage').onclick = (event) => exportStorage(event);
|
||||||
$('#purgeExpired').on('click', purgeExpired);
|
document.getElementById('purgeExpired').onclick = (event) => purgeExpired(event);
|
||||||
$('#clickImport').on('click', clickImport);
|
document.getElementById('clickImport').onclick = (event) => clickImport(event);
|
||||||
$('#mass-delete').on('click', massDelete);
|
document.getElementById('mass-delete').onclick = (event) => massDelete(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue