227 lines
6.6 KiB
Svelte
227 lines
6.6 KiB
Svelte
<script>
|
||
import { onMount } from 'svelte';
|
||
import { useTinyRouter } from 'svelte-tiny-router';
|
||
import { api } from '../../urls.svelte';
|
||
import { error, warn, yikes } from '../../warn.svelte';
|
||
import { t } from '../../translations.svelte';
|
||
import { user } from '../../user.svelte';
|
||
|
||
const image_extensions = ['jpg','jpeg','gif','png','svg','webp'];
|
||
const router = useTinyRouter();
|
||
let children = $state({});
|
||
|
||
let new_dir = $state(null);
|
||
let files = $state();
|
||
let parent = $state(false);
|
||
let form = $state(false);
|
||
let path = $state(null);
|
||
let delete_allowed = $state(false);
|
||
let available = $derived.by(isAvailable);
|
||
|
||
async function create_dir(ev){
|
||
ev.preventDefault();
|
||
ev.stopPropagation();
|
||
const url = api('files'+path+'/'+new_dir);
|
||
const res = await fetch(url,{
|
||
credentials: 'include',
|
||
method: 'POST'
|
||
});
|
||
if (res.ok) {
|
||
handleDirectory(res);
|
||
new_dir = null;
|
||
} else {
|
||
error(res);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function dropDir(p,name){
|
||
if (confirm(t('confirm_delete',{element:name})+"\n\n"+t('deletes_nested'))) dropElement(p);
|
||
}
|
||
|
||
|
||
async function dropElement(url){
|
||
const res = await fetch(url,{
|
||
credentials: 'include',
|
||
method: 'DELETE'
|
||
});
|
||
if (res.ok) {
|
||
handleDirectory(res);
|
||
} else {
|
||
error(res);
|
||
}
|
||
}
|
||
|
||
function dropFile(p,name){
|
||
if (confirm(t('confirm_delete',{element:name}))) dropElement(p);
|
||
}
|
||
|
||
async function handleDirectory(res){
|
||
let json = await res.json();
|
||
children.dirs = json.dirs ? val_sort(json.dirs) : {};
|
||
children.files = json.files ? val_sort(json.files) : {};
|
||
children.title = json.title ? json.title : path;
|
||
delete_allowed = json.delete;
|
||
yikes();
|
||
}
|
||
|
||
function isAvailable(){
|
||
if (!new_dir) return false;
|
||
if (children){
|
||
if (children.dirs) {
|
||
for (let key of Object.values(children.dirs)){
|
||
if (key == new_dir) return false;
|
||
}
|
||
}
|
||
if (children.files) {
|
||
for (let key of Object.values(children.files)){
|
||
if (key == new_dir) return false;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
function is_image(file){
|
||
let parts = file.toLowerCase().split('.');
|
||
let ext = parts.pop();
|
||
return image_extensions.includes(ext);
|
||
}
|
||
|
||
async function loadChildren(p){
|
||
p = p.substring(6);
|
||
if (p == '') p = '/';
|
||
children = { dirs : [], files : [], title : p};
|
||
path = p;
|
||
if (p == '/'){
|
||
children.dirs = [
|
||
{ path : `/user/${user.id}`, name : t('my files') },
|
||
{ path : '/project', name : t('projects')},
|
||
{ path : '/company', name : t('companies')},
|
||
]
|
||
|
||
parent = false;
|
||
form = false;
|
||
} else {
|
||
const url = api(`files${p}`);
|
||
const res = await fetch(url,{credentials:'include'});
|
||
if (res.ok){
|
||
parent = p.substring(0, p.lastIndexOf("/"));
|
||
if (parent == '/user'||p=='/project'||p=='/company') parent = '/';
|
||
form = !(p=='/company'||p=='/project'||p=='/user');
|
||
handleDirectory(res);
|
||
} else {
|
||
error(res);
|
||
}
|
||
}
|
||
}
|
||
|
||
function markdown(file){
|
||
let parts = file.split('/');
|
||
let path = `/api/files${file}`;
|
||
path = encodeURI(path);
|
||
let md = ``;
|
||
navigator.clipboard.writeText(md);
|
||
warn(t('Markdown has been copied to clipboard!'));
|
||
setTimeout(yikes, 2500);
|
||
}
|
||
|
||
function onclick(ev){
|
||
ev.preventDefault();
|
||
ev.stopPropagation();
|
||
|
||
var target = ev.target;
|
||
while (target && !target.href) target=target.parentNode;
|
||
let href = target.getAttribute('href');
|
||
if (href) {
|
||
router.navigate(href);
|
||
loadChildren(href);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
async function upload_file(ev){
|
||
ev.preventDefault();
|
||
const url = api('files'+path+'/'+files[0].name);
|
||
const resp = await fetch(url, {
|
||
credentials: 'include',
|
||
method: 'POST',
|
||
headers: {
|
||
"Content-Type": "application/unknown",
|
||
},
|
||
body: files[0]
|
||
});
|
||
if (resp.ok){
|
||
handleDirectory(resp);
|
||
files = null;
|
||
} else {
|
||
error(resp);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function val_sort(map){
|
||
return Object.entries(map)
|
||
.map(item => ({name:item[1],path:item[0]}))
|
||
.sort((a,b) => a.name.localeCompare(b.name));
|
||
}
|
||
|
||
onMount(() => loadChildren(window.location.pathname));
|
||
</script>
|
||
|
||
<h1>{t('files')} – {children?.title}</h1>
|
||
|
||
<ul>
|
||
{#if parent}
|
||
<li class="dir parent">
|
||
<span class="symbol"></span>
|
||
<a href={'/files'+parent} {onclick}>..</a>
|
||
</li>
|
||
{/if}
|
||
{#if children?.dirs}
|
||
{#each children.dirs as dir}
|
||
<li class="dir">
|
||
<span class="symbol"></span>
|
||
<a href={'/files'+dir.path} {onclick}>{dir.name}</a>
|
||
{#if delete_allowed}
|
||
<button class="symbol" onclick={e => dropDir(`/api/files${dir.path}`,dir.name)}></button>
|
||
{/if}
|
||
</li>
|
||
{/each}
|
||
{/if}
|
||
{#if form}
|
||
<li class="action">
|
||
<form onsubmit={create_dir} >
|
||
<span class="symbol">+</span>
|
||
<input type="text" bind:value={new_dir} />
|
||
<button type="submit" disabled={!available} >{t('create_new_object',{object:t('directory')})}</button>
|
||
</form>
|
||
</li>
|
||
{/if}
|
||
{#if children.files}
|
||
{#each children.files as file}
|
||
<li class="file">
|
||
<span class="symbol"></span>
|
||
<a href={`/api/files${file.path}`} target="_blank">{file.name}</a>
|
||
{#if is_image(file.path)}
|
||
<button class="symbol" title={'markdown_code'} onclick={e => markdown(file.path)}></button>
|
||
{/if}
|
||
{#if delete_allowed}
|
||
<button class="symbol" title={t('delete_object',{'object':t('file')})} onclick={e => dropFile(`/api/files${file.path}`,file.name)}></button>
|
||
{/if}
|
||
</li>
|
||
{/each}
|
||
{/if}
|
||
{#if form}
|
||
<li class="action">
|
||
<form onsubmit={upload_file}>
|
||
<span class="symbol">+</span>
|
||
<input type="file" bind:files />
|
||
<button disabled={!files}>{t('upload_file')}</button>
|
||
</form>
|
||
</li>
|
||
{/if}
|
||
</ul>
|
||
|