184 lines
5.9 KiB
Svelte
184 lines
5.9 KiB
Svelte
<script>
|
|
import { onMount } from 'svelte';
|
|
import { useTinyRouter } from 'svelte-tiny-router';
|
|
import { api } from '../../urls.svelte';
|
|
import { error, yikes } from '../../warn.svelte';
|
|
import { t } from '../../translations.svelte';
|
|
import { user } from '../../user.svelte';
|
|
|
|
import MarkdownEditor from '../../Components/MarkdownEditor.svelte';
|
|
import LineEditor from '../../Components/LineEditor.svelte';
|
|
import Notes from '../notes/RelatedNotes.svelte';
|
|
import PermissionEditor from '../../Components/PermissionEditor.svelte';
|
|
import TagList from '../tags/TagList.svelte';
|
|
|
|
let detail = $state(false);
|
|
let { key, version } = $props();
|
|
let page = $state({});
|
|
let router = useTinyRouter();
|
|
let members = $state({});
|
|
let editable = $derived(page.members[user.id].permission.code<4);
|
|
|
|
async function addMember(entry){
|
|
let newMembers = JSON.parse(JSON.stringify(page.members));
|
|
for (var id of Object.keys(entry)){
|
|
if (!newMembers[id]) newMembers[id] = { permission : {name:'READ_ONLY'} };
|
|
}
|
|
return patch({members:newMembers});
|
|
}
|
|
|
|
async function dropMember(member){
|
|
var id = member.user.id;
|
|
let newMembers = JSON.parse(JSON.stringify(page.members));
|
|
newMembers[id].permission = null;
|
|
return patch({members:newMembers});
|
|
}
|
|
|
|
async function dropVersion(){
|
|
const msg = t('confirm_delete',{element:t('version_of',{version:page.version,element:page.title})});
|
|
if (!confirm(msg)) return;
|
|
let url = api(`wiki/page/${key}/version/${page.version}`);
|
|
let res = await fetch(url,{
|
|
credentials:'include',
|
|
method: 'DELETE'
|
|
});
|
|
if (res.ok){
|
|
let json = await res.json();
|
|
router.navigate(`/wiki/${page.id}/view`);
|
|
yikes();
|
|
} else {
|
|
error(res);
|
|
}
|
|
}
|
|
|
|
function nonMember(json){
|
|
return !page.members[json.id];
|
|
}
|
|
|
|
async function getCandidates(text){
|
|
const url = api('user/search');
|
|
const resp = await fetch(url,{
|
|
credentials : 'include',
|
|
method : 'POST',
|
|
body : text
|
|
});
|
|
if (resp.ok){
|
|
var json = await resp.json();
|
|
return Object.fromEntries(Object.values(json).filter(nonMember).map(user => [user.id,user.name]));
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
async function loadContent(res){
|
|
if (res.ok){
|
|
let json = await res.json();
|
|
json.versions.sort((a,b)=>b-a);
|
|
page = { ...json };
|
|
yikes();
|
|
return true;
|
|
} else {
|
|
error(res);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function loadPage(){
|
|
let path = `wiki/page/${key}`;
|
|
if (version) path += `/version/${version}`;
|
|
const url = api(path);
|
|
const res = await fetch(url,{credentials:'include'});
|
|
loadContent(res);
|
|
}
|
|
|
|
function onclick(e){
|
|
e.preventDefault();
|
|
let href = e.target.getAttribute('href');
|
|
if (href) router.navigate(href);
|
|
return false;
|
|
}
|
|
|
|
async function patch(data){
|
|
const url = api(`wiki/page/${page.id}`);
|
|
const res = await fetch(url,{
|
|
credentials:'include',
|
|
method:'PATCH',
|
|
body:JSON.stringify(data)
|
|
});
|
|
return loadContent(res);
|
|
}
|
|
|
|
async function patchGuestPermissions(ev){
|
|
let data = {guest_allowed:page.guest_allowed};
|
|
console.log(data);
|
|
return patch(data);
|
|
}
|
|
|
|
async function patchTitle(t){
|
|
var result = await(patch({title:t}));
|
|
router.navigate(`/wiki/${page.id}/view`);
|
|
}
|
|
|
|
function toggleDetail(){
|
|
detail = !detail;
|
|
}
|
|
|
|
async function updatePermission(uid, newPerm){
|
|
let newMembers = JSON.parse(JSON.stringify(page.members));
|
|
newMembers[uid] = {permission:newPerm};
|
|
return patch({members:newMembers});
|
|
}
|
|
|
|
$effect(loadPage);
|
|
</script>
|
|
{#if page && page.versions}
|
|
<div class="wiki page">
|
|
<div class="versions">
|
|
<span class="version">{t('version')}</span>
|
|
{#each page.versions as v}
|
|
<span class="version">
|
|
<a href={`/wiki/${page.id}/version/${v}`} {onclick} class={page.version == v?'selected':''}>{v}</a>
|
|
</span>
|
|
{/each}
|
|
</div>
|
|
<LineEditor value={page.title} type="h2" {editable} onSet={t => patchTitle(t)} />
|
|
{#if page.version != page.versions[0]}
|
|
<span class="warn">{t('not_recent_version')}</span>
|
|
{/if}
|
|
<button onclick={toggleDetail} class="symbol" title={t('toggle_objects',{objects:t('users')})}></button>
|
|
<button onclick={dropVersion} class="symbol" title={t('delete_object',{object:t('version')})}> </button>
|
|
{#if detail}
|
|
{#if editable}
|
|
<PermissionEditor members={page.members} {addMember} {dropMember} {getCandidates} {updatePermission} />
|
|
<label>
|
|
<input type="checkbox" bind:checked={page.guest_allowed} onchange={patchGuestPermissions} />
|
|
{t('visible_to_guests')}
|
|
</label>
|
|
{:else}
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>{t('user')}</th>
|
|
<th>{t('permissions')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{#each Object.values(page.members) as member,id}
|
|
<tr>
|
|
<td>{member.user.name}</td>
|
|
<td>{t('permission_'+member.permission.name.toLowerCase())}</td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
{/if}
|
|
{/if}
|
|
<MarkdownEditor {editable} value={page.content} onSet={s => patch({content:s})} />
|
|
<TagList module="wiki" id={page.id} user_list={Object.keys(page.members).map(id => +id)} />
|
|
<div class="notes">
|
|
<h3>{t('notes')}</h3>
|
|
<Notes module="wiki" entity_id={page.id} />
|
|
</div>
|
|
</div>
|
|
{/if}
|