You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.7 KiB
123 lines
3.7 KiB
<script> |
|
import { onMount } from 'svelte'; |
|
|
|
import { api } from '../../urls.svelte.js'; |
|
import { t } from '../../translations.svelte.js'; |
|
|
|
import Editor from '../../Components/MarkdownEditor.svelte'; |
|
import Users from '../../Components/UserSelector.svelte'; |
|
import Tags from '../tags/TagList.svelte'; |
|
import Template from './Template.svelte'; |
|
|
|
let bookmarks = $state(null); |
|
let loader = { |
|
offset : 0, |
|
limit : 16, |
|
active : true |
|
} |
|
let new_bookmark = $state({ |
|
comment:{ |
|
source:null, |
|
rendered:null |
|
}, |
|
tags:[], |
|
url:null, |
|
users:{} |
|
}); |
|
let error = $state(null); |
|
|
|
async function getCandidates(text){ |
|
const url = api('user/search'); |
|
const resp = await fetch(url,{ |
|
credentials : 'include', |
|
method : 'POST', |
|
body : text |
|
}); |
|
if (resp.ok){ |
|
error = null; |
|
const input = await resp.json(); |
|
return Object.fromEntries( |
|
Object.entries(input).map(([key, value]) => [key, value.name]) |
|
); |
|
} else { |
|
error = await resp.text(); |
|
return {}; |
|
} |
|
} |
|
|
|
async function loadBookmarks(){ |
|
const url = api(`bookmark/list?offset=${loader.offset}&limit=${loader.limit}`); |
|
const resp = await fetch(url,{credentials:'include'}); |
|
if (resp.ok){ |
|
const raw = await resp.json(); |
|
let merged = bookmarks ? bookmarks : {} |
|
merged = { ...bookmarks , ...raw }; |
|
bookmarks = Object.values(merged).sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)); |
|
loader.offset += loader.limit; |
|
loader.active = false; |
|
error = null; |
|
if (Object.keys(raw).length) onscroll(null); // when bookmarks were received, check whether they fill up the page |
|
} else { |
|
error = await resp.html(); |
|
} |
|
} |
|
|
|
async function onclick(ev){ |
|
delete new_bookmark.comment.rendered; |
|
const url = api('bookmark'); |
|
const data = { |
|
comment : new_bookmark.comment.source, |
|
url : new_bookmark.url, |
|
tags : new_bookmark.tags |
|
} |
|
const share = Object.keys(new_bookmark.users).map(id => +id); |
|
if (share.length>0) data.share = share; |
|
const resp = await fetch(url,{ |
|
credentials : 'include', |
|
method : 'POST', |
|
body : JSON.stringify(data) |
|
}); |
|
if (resp.ok) { |
|
const bookmark = await resp.json(); |
|
bookmarks.unshift(bookmark); |
|
} else { |
|
error = await resp.text(); |
|
} |
|
} |
|
|
|
function onscroll(ev){ |
|
if (window.innerHeight + window.scrollY >= document.body.offsetHeight && !loader.active) { |
|
loader.active = true; |
|
loadBookmarks(); |
|
} |
|
} |
|
|
|
onMount(loadBookmarks); |
|
</script> |
|
|
|
<svelte:window {onscroll} /> |
|
<fieldset> |
|
<legend>{t('Bookmarks')}</legend> |
|
{#if error} |
|
<span class="error">{error}</span> |
|
{/if} |
|
<label> |
|
{t('URL')} |
|
<input bind:value={new_bookmark.url} autofocus /> |
|
</label> |
|
<label> |
|
{t('Comment')} |
|
<Editor simple={true} bind:value={new_bookmark.comment} /> |
|
</label> |
|
<label> |
|
{t('share_with')} |
|
<Users {getCandidates} users={new_bookmark.users} /> |
|
</label> |
|
<Tags module="bookmark" bind:tags={new_bookmark.tags} /> |
|
<button {onclick}>{t('save')}</button> |
|
{#if bookmarks} |
|
{#each bookmarks as bookmark} |
|
<Template {bookmark} /> |
|
{/each} |
|
{/if} |
|
</fieldset> |