web-shared-folder
Version:
Web server for sharing folder on local network or Internet
594 lines (550 loc) • 15.3 kB
JavaScript
;
const _checkboxes = document.querySelectorAll('#select_form input[type="checkbox"]');
themeChanger();
setClientLanguage();
performSelectButtons();
preventDownloadIfNoFilesSelected();
backspaceToPreviousFolder();
/*---UPLOAD_SPLITTER---*/
deleteFilesWarningDialog();
upload();
dragAndDropFiles();
createFolderValidity();
renameFiles();
performCopyPaste();
/*---UPLOAD_SPLITTER---*/
function themeChanger()
{
const THEME_STORAGE_NAME = 'selected-theme';
const STORAGE_LIGHT_THEME = 'light';
const STORAGE_DARK_THEME = 'dark';
const STORAGE_AUTO_THEME = 'auto';
const radioLight = document.getElementById('radio-light-theme');
const radioDark = document.getElementById('radio-dark-theme');
const radioAuto = document.getElementById('radio-auto-theme');
const styleLight = document.getElementById('light-theme-css');
const styleDark = document.getElementById('dark-theme-css');
const selectedTheme = localStorage.getItem(THEME_STORAGE_NAME);
setTheme(selectedTheme);
radioLight.addEventListener('change', onThemeChange);
radioDark.addEventListener('change', onThemeChange);
radioAuto.addEventListener('change', onThemeChange);
function setTheme(selectedTheme)
{
if (selectedTheme !== STORAGE_LIGHT_THEME && selectedTheme !== STORAGE_DARK_THEME && selectedTheme !== STORAGE_AUTO_THEME)
{
selectedTheme = STORAGE_AUTO_THEME;
setThemeToLocalStorage(STORAGE_AUTO_THEME);
}
if (selectedTheme === STORAGE_LIGHT_THEME)
{
styleLight.media = 'all';
styleDark.media = 'not all';
radioLight.checked = true;
}
else if (selectedTheme === STORAGE_DARK_THEME)
{
styleLight.media = 'not all';
styleDark.media = 'all';
radioDark.checked = true;
}
else
{
styleLight.media = '(prefers-color-scheme: light)';
styleDark.media = '(prefers-color-scheme: dark)';
radioAuto.checked = true;
}
}
function onThemeChange()
{
let selectedTheme = '';
let ifSet = false;
if (radioLight.checked)
{
selectedTheme = STORAGE_LIGHT_THEME;
ifSet = true;
}
else if (radioDark.checked)
{
selectedTheme = STORAGE_DARK_THEME;
ifSet = true;
}
else if (radioAuto.checked)
{
selectedTheme = STORAGE_AUTO_THEME;
ifSet = true;
}
if (ifSet)
{
setThemeToLocalStorage(selectedTheme);
setTheme(selectedTheme);
}
}
function setThemeToLocalStorage(value)
{
localStorage.setItem(THEME_STORAGE_NAME, value);
}
}
function setClientLanguage()
{
let _lang = null;
for (let cookie of document.cookie.split(';'))
{
const aux = cookie.split('=');
const key = aux[0].trim();
const value = aux[1].trim();
if (key === 'lang' || key == 'nav_lang')
{
_lang = value;
break;
}
}
if (!_lang)
{
_lang = navigator.browserLanguage || navigator.language || navigator.userLanguage;
if (_lang)
{
document.cookie = `nav_lang=${_lang}; path=/; samesite=strict`;
location.reload();
}
}
}
function performSelectButtons()
{
const selectAllButton = document.getElementById('selectAll');
const deselectAllButton = document.getElementById('deselectAll');
const checkboxes = document.querySelectorAll('input[id^="item-checkbox-"]');
selectAllButton.addEventListener('click', (event) =>
{
event.preventDefault();
checkboxes.forEach((checkbox) => setCheckbox(checkbox, true));
});
deselectAllButton.addEventListener('click', (event) =>
{
event.preventDefault();
checkboxes.forEach((checkbox) => setCheckbox(checkbox, false));
});
selectAllButton.hidden = false;
deselectAllButton.hidden = false;
function setCheckbox(checkbox, value)
{
if (value)
{
checkbox.checked = true;
}
else
{
checkbox.checked = false;
}
}
}
function preventDownloadIfNoFilesSelected()
{
const downloadButton = document.querySelector('#select_form button[name="download"]');
downloadButton.addEventListener('click', (e) =>
{
if (!hasSelectedChecboxes()) e.preventDefault();
});
}
function hasSelectedChecboxes()
{
for (let elem of _checkboxes)
{
if (elem.checked) return true;
}
return false;
}
function backspaceToPreviousFolder()
{
const selectForm = document.getElementById('select_form');
selectForm.focus();
selectForm.addEventListener('keydown', (e) =>
{
if (e.code === 'Backspace' && location.pathname !== '/')
{
//history.back();
const arr = location.pathname.split('/');
let backPath = arr.slice(0, arr.length - 1).join('/');
if (backPath === '') backPath = '/';
location.assign(backPath);
}
});
}
/*---UPLOAD_SPLITTER---*/
function performCopyPaste()
{
const items = [];
const selectButton = document.getElementById('select_for_copy_or_move_button');
const copyButton = document.getElementById('copy_button');
const moveButton = document.getElementById('move_button');
const selectForm = document.getElementById('select_form');
const ITEMS_KEY = 'paste_items';
const PATH_KEY = 'paste_from';
const PASTE_TYPE_KEY = 'paste_type';
performSelectForCopyOrMoveButton();
performCopyOrPasteButtons();
function performSelectForCopyOrMoveButton()
{
const selectButtonName = selectButton.innerText;
selectButton.hidden = false;
selectButton.addEventListener('click', (e) =>
{
e.preventDefault();
for (let item of _checkboxes)
{
if (item.checked) items.push(item.name);
}
if (items.length === 0)
{
selectButton.innerText = selectButtonName;
sessionStorage.removeItem(ITEMS_KEY);
sessionStorage.removeItem(PATH_KEY);
}
else
{
sessionStorage.setItem(ITEMS_KEY, items.join(','));
sessionStorage.setItem(PATH_KEY, decodeURI(location.pathname));
selectButton.innerText = `${selectButtonName} (${items.length})`;
}
items.length = 0;
copyButton.hidden = true;
moveButton.hidden = true;
});
}
function performCopyOrPasteButtons()
{
const dialog = document.getElementById('replace-warning-dialog');
const dialogMessage = document.querySelector('#replace-warning-dialog [data-id="dialog_message"]');
const doNotAsk = document.querySelector('#replace-warning-dialog input[type="checkbox"]');
const copyButtonName = copyButton.innerText;
const moveButtonName = moveButton.innerText;
const items = sessionStorage.getItem(ITEMS_KEY);
const itemsPath = sessionStorage.getItem(PATH_KEY);
if (items && itemsPath && itemsPath !== location.pathname)
{
copyButton.innerText = `${copyButtonName} (${items.split(',').length})`;
copyButton.hidden = false;
moveButton.innerText = `${moveButtonName} (${items.split(',').length})`;
moveButton.hidden = false;
copyButton.addEventListener('click', (e) =>
{
onCopyOrMoveButtonsClick(e, 'copy');
});
moveButton.addEventListener('click', (e) =>
{
onCopyOrMoveButtonsClick(e, 'move');
});
if (dialog.showModal)
{
dialog.addEventListener('close', () =>
{
if (dialog.returnValue === 'ok')
{
if (doNotAsk.checked) sessionStorage.setItem('replace-without-ask', true);
performClick(dialog.getAttribute('data-type'));
}
});
}
}
function onCopyOrMoveButtonsClick(e, type)
{
e.preventDefault();
if (sessionStorage.getItem('replace-without-ask'))
{
performClick(type);
}
else if (dialog.showModal)
{
dialog.setAttribute('data-type', type);
dialog.showModal();
}
else
{
const message = dialogMessage.innerText;
if (confirm(message)) performClick(type);
}
}
function performClick(type)
{
sessionStorage.removeItem(ITEMS_KEY);
sessionStorage.removeItem(PATH_KEY);
submit(type);
}
function submit(type)
{
const itemsPathInput = document.createElement('input');
itemsPathInput.type = 'hidden';
itemsPathInput.name = PATH_KEY;
itemsPathInput.value = itemsPath;
const itemsInput = document.createElement('input');
itemsInput.type = 'hidden';
itemsInput.name = ITEMS_KEY;
itemsInput.value = items;
const typeInput = document.createElement('input');
typeInput.type = 'hidden';
typeInput.name = PASTE_TYPE_KEY;
typeInput.value = type;
selectForm.append(itemsPathInput);
selectForm.append(itemsInput);
selectForm.append(typeInput);
selectForm.submit();
}
}
}
function deleteFilesWarningDialog()
{
const dialog = document.getElementById('delete-warning-dialog');
const dialogMessage = document.querySelector('#delete-warning-dialog [data-id="dialog_message"]');
if (!dialog) return;
const deleteButton = document.querySelector('#select_form button[name="delete"]');
deleteButton.addEventListener('click', (event) =>
{
{
const hsc = hasSelectedChecboxes();
if (sessionStorage.getItem('delete-without-ask'))
{
if (!hsc) event.preventDefault();
return;
}
event.preventDefault();
if (!hsc) return;
}
if (dialog.showModal)
{
dialog.showModal();
}
else
{
const message = dialogMessage.innerText;
if (confirm(message)) submit();
}
});
if (dialog.showModal)
{
const doNotAsk = document.querySelector('#delete-warning-dialog input[type="checkbox"]');
dialog.addEventListener('close', () =>
{
if (dialog.returnValue === 'yes')
{
if (doNotAsk.checked) sessionStorage.setItem('delete-without-ask', true);
submit();
}
});
}
const selectForm = document.getElementById('select_form');
function submit()
{
const tmpElement = document.createElement('input');
tmpElement.type = 'hidden';
tmpElement.name = 'delete';
tmpElement.value = true;
selectForm.append(tmpElement);
selectForm.submit();
}
}
function upload(formData, callback)
{
let uploadForm = null;
if (!formData)
{
uploadForm = document.querySelector('.footer__upload_files_form');
if (!uploadForm) return;
}
const errorFiled = document.querySelector('.error_message');
const MAX_FILE_LENGTH = 2147483647;
const progressBar = document.querySelector('.footer__controls > progress');
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (event) =>
{
if (event.total > MAX_FILE_LENGTH)
{
errorFiled.innerHTML = 'Maximum files upload size exceeded';
removeProgressBar();
xhr.abort();
return;
}
const percentLoaded = Math.round((event.loaded / event.total) * 100);
progressBar.value = percentLoaded;
});
xhr.addEventListener('readystatechange', () =>
{
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200)
{
progressBar.value = 0;
removeProgressBar();
if (typeof callback === 'function') callback(xhr.response);
if (xhr.response)
{
errorFiled.innerHTML = xhr.response;
}
else
{
window.location = window.location.href;
}
}
});
xhr.addEventListener('error', (err) =>
{
progressBar.value = 0;
removeProgressBar();
const msg = 'Error occurred!';
if (typeof callback === 'function') callback(msg);
errorFiled.innerHTML = msg;
console.log(err);
});
if (!formData)
{
uploadForm.addEventListener('submit', (event) =>
{
event.preventDefault();
const inputFiles = document.querySelector('.footer__upload_files_form input[type="file"]');
if (inputFiles.files.length === 0) return;
const totalSize = filesSize(inputFiles.files);
if (totalSize <= 5242880)
{
uploadForm.submit();
callback();
return;
}
formData = new FormData(uploadForm);
submit(formData);
});
}
else
{
submit(formData);
}
function submit(formData)
{
showProgressBar();
xhr.open('post', location.href + '?xhr=true', true);
xhr.send(formData);
}
function filesSize(files)
{
let size = 0;
for (let file of files)
{
size += file.size;
}
return size;
}
function showProgressBar()
{
progressBar.classList.remove('hidden_in_flow');
}
function removeProgressBar()
{
progressBar.classList.add('hidden_in_flow');
}
}
function dragAndDropFiles()
{
let uploadingInProgress = false;
const dropZoneClass = 'footer__drag_and_drop__dragenter';
const dropZone = document.querySelector('.footer__drag_and_drop');
if (!dropZone) return;
dropZone.classList.remove('hidden');
dropZone.addEventListener('dragenter', (e) =>
{
e.preventDefault();
if (!uploadingInProgress) dropZone.classList.add(dropZoneClass);
});
dropZone.addEventListener('dragleave', (e) =>
{
e.preventDefault();
if (!uploadingInProgress) dropZone.classList.remove(dropZoneClass);
});
dropZone.addEventListener('dragover', (e) => e.preventDefault());
dropZone.addEventListener('drop', (e)=>
{
e.preventDefault();
if (!uploadingInProgress)
{
dropZone.classList.remove(dropZoneClass);
const formData = new FormData();
for (let file of e.dataTransfer.files)
{
formData.append('upload_xhr', file);
}
dropZone.classList.add('footer__drag_and_drop__while_upload');
uploadingInProgress = true;
upload(formData, () =>
{
uploadingInProgress = false;
dropZone.classList.remove('footer__drag_and_drop__while_upload');
});
}
});
}
function createFolderValidity()
{
const input = document.querySelector('form[name="mk_dir"] > input[name="dir"]');
if (!input) return;
input.addEventListener('input', () =>
{
if (input.validity.patternMismatch)
{
input.setCustomValidity(input.getAttribute('data-invalid-message'));
}
else
{
input.setCustomValidity('');
}
input.reportValidity();
});
}
function renameFiles()
{
const dialog = document.getElementById('rename-dialog');
if (!dialog || !dialog.showModal) return;
const renameButtons = document.querySelectorAll('button[id^="rename-button-"]');
const fileName = document.querySelector('#rename-dialog input[type="text"]');
let oldNameBase64 = '';
for (let rb of renameButtons)
{
rb.hidden = false;
rb.addEventListener('click', (e) =>
{
e.preventDefault();
const id = rb.id.split('-')[2];
const checkboxBeforeButton = document.getElementById(`item-checkbox-${id}`);
oldNameBase64 = checkboxBeforeButton.getAttribute('name');
dialog.showModal();
});
}
fileName.addEventListener('input', () =>
{
if (fileName.validity.patternMismatch)
{
fileName.setCustomValidity(fileName.getAttribute('data-invalid-message'));
}
else
{
fileName.setCustomValidity('');
}
fileName.reportValidity();
});
dialog.addEventListener('close', () =>
{
if (dialog.returnValue === 'ok')
{
submit(oldNameBase64, fileName.value);
}
});
function submit(oldName, newName)
{
const selectForm = document.getElementById('select_form');
const from = document.createElement('input');
from.type = 'hidden';
from.name = 'rename_from';
from.value = oldName;
selectForm.append(from);
const to = document.createElement('input');
to.type = 'hidden';
to.name = 'rename_to';
to.value = newName;
selectForm.append(to);
selectForm.submit();
}
}