hmn/src/templates/src/editor.html

225 lines
9.0 KiB
HTML

{{ template "base.html" . }}
{{ define "extrahead" }}
<link rel="stylesheet" href="{{ static "editor.css" }}" />
<script src="{{ static "util.js" }}"></script>
<script src="{{ static "editor.js" }}"></script>
<script src="{{ static "go_wasm_exec.js" }}"></script>
<script>
const previewWorker = new Worker('{{ static "js/editorpreviews.js" }}');
</script>
<style>
#editor {
resize: vertical;
}
</style>
{{ end }}
{{ define "content" }}
<div class="content-block ph3 ph0-ns">
{{ if .ThreadTitle }}
<h2>{{ .ThreadTitle }}</h2>
{{ end }}
<div class="flex flex-column flex-row-ns">
<form id="form" action="{{ .SubmitUrl }}" method="post" class="flex-fair-ns">
{{ csrftoken .Session }}
{{ if not .PostReplyingTo }}
<input class="b w-100 mb1" name="title" type="text" placeholder="Post title..." value="{{ .PostTitle }}"/>
{{ end }}
{{/* TODO: Reintroduce the toolbar in a way that makes sense for Markdown */}}
{{/*
<div class="toolbar" id="toolbar">
<input type="button" id="bold" value="B" />
<input type="button" id="italic" value="I" />
<input type="button" id="underline" value="U" />
<input type="button" id="monospace" value="monospace" />
<input type="button" id="url" value="url" />
<input type="button" id="img" value="img" />
<input type="button" id="code" value="code" />
<input type="button" id="quote_simple" value="quote (anon)" />
<input type="button" id="quote_member" value="quote (member)" />
<input type="button" id="spoiler" value="spoiler" />
<input type="button" id="lalign" value="Left" />
<input type="button" id="calign" value="Center" />
<input type="button" id="ralign" value="Right" />
<input type="button" id="ulist" value="ul" />
<input type="button" id="olist" value="ol" />
<input type="button" id="litem" value="li" />
<input type="button" id="youtube" value="youtube" />
</div>
*/}}
<textarea id="editor" class="w-100 h5 minh-5" name="body">{{ .PostBody }}</textarea>
<div class="flex flex-row-reverse justify-start mt2">
<input type="submit" class="button ml2" name="submit" value="{{ .SubmitLabel }}" />
</div>
{{ if .IsEditing }}
<span class="editreason">
<label for="editreason">Edit reason:</label>
<input name="editreason" maxlength="255" type="text" id="editreason" />
</span>
{{ end }}
{{/* TODO: Sticky threads
{% if user.is_staff and post and post.depth == 0 %}
<div class="checkbox sticky">
<input type="checkbox" name="sticky" id="sticky" {% if thread.sticky %}checked{% endif%} />
<label for="sticky">Sticky thread</label>
</div>
{% endif %}
*/}}
{{ with .PostReplyingTo }}
<h4 class="mt3">The post you're replying to:</h4>
<div class="bg--dim pa3 br3">
<div class="w-100 flex items-center">
{{ if .Author }}
<div class="w-20 mw3 w3">
<!-- Mobile avatar -->
<div class="aspect-ratio--1x1 contain bg-center" style="background-image:url('{{ .Author.AvatarUrl }}');"></div>
</div>
<div class="pl3 flex flex-column">
<div>
<a class="username" href="{{ .Author.ProfileUrl }}" target="_blank">{{ .Author.Username }}</a> {{/* TODO: Text scale stuff? Seems unnecessary. */}}
<!-- Mobile badges -->
<div class="di ph1">
{{ if .Author.IsStaff }}
<div class="badge staff"></div>
{{ end }}
</div>
</div>
{{ if and .Author.Name (ne .Author.Name .Author.Username) }}
<div class="c--dim f7"> {{ .Author.Name }} </div>
{{ end }}
<div class="c--dim f7">
{{ timehtml (relativedate .PostDate) .PostDate }}
{{ if .Editor }}
<span class="pl3">
Edited by
<a class="name" href="{{ .Editor.ProfileUrl }}" target="_blank">{{ coalesce .Editor.Name .Editor.Username }}</a>
on {{ timehtml (absolutedate .EditDate) .EditDate }}
{{ with .EditReason }}
Reason: {{ . }}
{{ end }}
</span>
{{ end }}
</div>
</div>
{{ else }}
<div class="username">Deleted member</div>
<div class="avatar" style="background-image:url('{{ .Author.AvatarUrl }}');"></div>
{{ end }}
</div>
<div class="w-100 pt3">
<div class="contents overflow-x-auto">
{{ .Content }}
</div>
</div>
</div>
{{ end }}
{{/*
{% if context_reply_to %}
<h4>The post you're replying to:</h4>
<div class="recent-posts">
{% with post=post_reply_to %}
{% include "forum_thread_single_post.html" %}
{% endwith %}
</div>
{% endif %}
{% if context_newer %}
<h4>Replies since then:</h4>
<div class="recent-posts">
{% for post in posts_newer %}
{% include "forum_thread_single_post.html" %}
{% endfor %}
</div>
{% endif %}
{% if context_older %}
<h4>Replies before then:</h4>
<div class="recent-posts">
{% for post in posts_older %}
{% include "forum_thread_single_post.html" %}
{% endfor %}
</div>
{% endif %}
*/}}
</form>
<div class="post post-preview mv3 mathjax flex-fair-ns mv0-ns ml3-ns">
<div id="preview" class="body contents"></div>
</div>
</div>
</div>
<script>
const form = document.querySelector('#form');
const tf = document.querySelector('#editor');
const preview = document.querySelector('#preview');
const storagePrefix = 'post-contents';
// Delete old irrelevant local post contents
const aWeekAgo = new Date().getTime() - (7 * 24 * 60 * 60 * 1000);
for (const key in window.localStorage) {
if (!window.localStorage.hasOwnProperty(key)) {
continue;
}
if (key.startsWith(storagePrefix)) {
try {
const { when } = JSON.parse(window.localStorage.getItem(key));
if (when <= aWeekAgo) {
window.localStorage.removeItem(key);
}
} catch (e) {
console.error(e);
}
}
}
// Load any stored content from localStorage
const storageKey = `${storagePrefix}/${window.location.host}${window.location.pathname}`;
const storedContents = window.localStorage.getItem(storageKey);
if (storedContents) {
try {
const { contents } = JSON.parse(storedContents);
tf.value = contents;
} catch (e) {
console.error(e);
}
}
function updatePreview(previewHtml) {
preview.innerHTML = previewHtml;
MathJax.typeset();
}
previewWorker.onmessage = ({ data }) => {
updatePreview(data);
};
function doMarkdown() {
const md = tf.value;
previewWorker.postMessage(md);
window.localStorage.setItem(storageKey, JSON.stringify({
when: new Date().getTime(),
contents: md,
}));
}
doMarkdown();
tf.addEventListener('input', () => doMarkdown());
form.addEventListener('submit', e => {
window.localStorage.removeItem(storageKey);
});
</script>
{{ end }}