Files
bible/assets/templates/verse.njk
T
2026-09-08 08:24:21 -04:00

61 lines
3.3 KiB
Plaintext

{# The verse dialog's contents: what this verse is called, a link to it, and
the one thing you can do with it.
Rendered by sw.js for the verse that was clicked and swapped into the empty
modal-content in base.njk -- the shape htmx's bootstrap-modal example uses.
Bootstrap owns showing, dismissing, the backdrop and Escape; everything
here is what is inside.
Context: verse (ref, href, url).
All three are built in the worker, from the book in the address bar and the
anchor that was clicked. app.js used to read them off the page -- the book
out of article[data-name], the chapter out of the enclosing section -- which
put the reference in two places and left the spelling of an anchor known to
both the file that generates them and the file that scrapes them back.
The link is a field rather than a line of text because it is the fallback
for the button beside it: navigator.clipboard exists only in a secure
context, so over plain http:// from a LAN address there is nothing to write
with and a selected field is the whole of what is left. Readonly, so it
reads as something to take rather than something to fill in. #}
<div class="modal-header">
<h2 class="modal-title fs-5 verse-dialog-ref" id="verse-dialog-ref">{{ verse.ref }}</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<label class="visually-hidden" for="verse-dialog-url">Link to {{ verse.ref }}</label>
<input class="verse-dialog-url form-control form-control-sm" id="verse-dialog-url"
type="text" readonly value="{{ verse.url }}">
{% include "status.njk" %}
</div>
<div class="modal-footer">
{# The form is the bookmark write and nothing else. ref and href are hidden
because they are this dialog's whole subject: the reader chose them by
clicking a verse, and there is nothing here to edit. #}
<form class="verse-dialog-actions d-flex flex-wrap gap-2 m-0"
hx-post="api/bookmark" hx-target="#bookmark" hx-swap="outerHTML">
<input type="hidden" name="ref" value="{{ verse.ref }}">
<input type="hidden" name="href" value="{{ verse.href }}">
{# Selected first, written second: the selection is what makes the field
useful when the write is refused, and it costs nothing when it is not.
The status line is only told once the clipboard has actually taken it,
which is why the promise is answered rather than assumed. #}
<button class="btn btn-outline-secondary" type="button"
hx-on:click="var field = document.getElementById('verse-dialog-url');
var line = document.getElementById('verse-dialog-status');
field.focus();
field.select();
if (navigator.clipboard) {
navigator.clipboard.writeText(field.value).then(
function () { line.textContent = 'Link copied.'; },
function () { line.textContent = 'Copy the link above.'; });
} else {
line.textContent = document.execCommand('copy')
? 'Link copied.' : 'Copy the link above.';
}">Copy link</button>
<button class="btn btn-primary" type="submit">Set bookmark</button>
</form>
</div>