184 lines
5.7 KiB
HTML
184 lines
5.7 KiB
HTML
{% extends "base.html" %}
|
|
{% block body_class %}themed-bg{% endblock %}
|
|
{% load static %}
|
|
|
|
{% block content %}
|
|
<div class="page">
|
|
<!-- Top bar -->
|
|
<div class="result-toolbar">
|
|
<div class="rt-left">
|
|
<a class="btn btn-secondary" href="{% url 'entry_view' entry.id %}">← Back to Entry</a>
|
|
<span class="rt-count">Editing: #{{ entry.id }}</span>
|
|
</div>
|
|
<div class="rt-right">
|
|
<a class="btn" href="{% url 'entry_view' entry.id %}">Cancel</a>
|
|
<button form="entry-edit-form" class="btn btn-primary">Save</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Card -->
|
|
<div class="card entry-form modern-form" style="padding: 24px; margin-bottom: 60px;">
|
|
<form id="entry-edit-form" method="post">
|
|
{% csrf_token %}
|
|
|
|
<div class="f-grid">
|
|
<div class="f-row">
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Subject</div>
|
|
<div class="f-control">
|
|
{{ form.subject }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="f-row tall">
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Illustration</div>
|
|
<div class="f-control">
|
|
{{ form.illustration }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="f-row tall">
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Application</div>
|
|
<div class="f-control">
|
|
{{ form.application }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="f-row">
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Scripture</div>
|
|
<div class="f-control">
|
|
{{ form.scripture_raw }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="f-row">
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Source</div>
|
|
<div class="f-control">
|
|
{{ form.source }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="f-row">
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Talk Title</div>
|
|
<div class="f-control">
|
|
{{ form.talk_title }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="f-row">
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Talk Number</div>
|
|
<div class="f-control">
|
|
{{ form.talk_number }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Combined row for Entry Code + Date Added + Date Edited -->
|
|
<div class="f-row" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;">
|
|
<div>
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Entry Code</div>
|
|
<div class="f-control">
|
|
{{ form.entry_code }}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Date Added</div>
|
|
<div class="f-control">
|
|
{{ form.date_added }}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="f-label" style="font-weight: 600; font-size: 1.05em;">Date Edited</div>
|
|
<div class="f-control">
|
|
{{ form.date_edited }}
|
|
</div }
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- bottom actions -->
|
|
<div class="form-actions bottom-actions" style="margin-top: 20px;">
|
|
<a class="btn btn-secondary" href="{% url 'entry_view' entry.id %}">Cancel</a>
|
|
<button class="btn btn-primary">Save</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Talk title auto-fill & auto-date -->
|
|
<script>
|
|
(function () {
|
|
const talksUrl = "{% static 'talks.json' %}";
|
|
|
|
function wireAutofill(talkMap) {
|
|
const numberEl = document.getElementById("id_talk_number");
|
|
const titleEl = document.getElementById("id_talk_title");
|
|
if (!numberEl || !titleEl) return;
|
|
|
|
const isEffectivelyEmpty = (s) => {
|
|
const t = (s || "").trim();
|
|
return t === "" || t === "-" || t === "—";
|
|
};
|
|
|
|
let userTyped = false;
|
|
|
|
titleEl.addEventListener("input", () => {
|
|
userTyped = !isEffectivelyEmpty(titleEl.value);
|
|
if (!userTyped) titleEl.dataset.autofilled = "0";
|
|
});
|
|
|
|
function maybeAutofill() {
|
|
const n = numberEl.value;
|
|
const mapped = talkMap && talkMap[n] ? talkMap[n] : "";
|
|
|
|
if (!userTyped) {
|
|
if (mapped) {
|
|
titleEl.value = mapped;
|
|
titleEl.dataset.autofilled = "1";
|
|
} else if (titleEl.dataset.autofilled === "1") {
|
|
titleEl.value = "";
|
|
titleEl.dataset.autofilled = "0";
|
|
}
|
|
}
|
|
}
|
|
|
|
numberEl.addEventListener("change", maybeAutofill);
|
|
|
|
if (isEffectivelyEmpty(titleEl.value)) {
|
|
userTyped = false;
|
|
maybeAutofill();
|
|
} else {
|
|
userTyped = true;
|
|
}
|
|
}
|
|
|
|
fetch(talksUrl, {cache: "no-store"})
|
|
.then(r => r.ok ? r.json() : {})
|
|
.then(map => wireAutofill(map))
|
|
.catch(() => wireAutofill({}));
|
|
|
|
// Auto-fill today's date for Date Edited if empty
|
|
const dateEditedEl = document.getElementById("id_date_edited");
|
|
if (dateEditedEl && !dateEditedEl.value) {
|
|
const today = new Date();
|
|
const yyyy = today.getFullYear();
|
|
const mm = String(today.getMonth() + 1).padStart(2, '0');
|
|
const dd = String(today.getDate()).padStart(2, '0');
|
|
dateEditedEl.value = `${yyyy}-${mm}-${dd}`;
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
<style>
|
|
.scripture-valid,
|
|
textarea.scripture-valid,
|
|
input.scripture-valid { background-color: hsl(140 80% 92% / 0.8); transition: background-color .15s ease; }
|
|
.scripture-invalid,
|
|
textarea.scripture-invalid,
|
|
input.scripture-invalid { background-color: hsl(0 80% 94% / 0.8); transition: background-color .15s ease; }
|
|
</style>
|
|
|
|
<!-- Use shared Scripture Validator -->
|
|
<script src="{% static 'js/scripture-validator.v1.js' %}"></script>
|
|
<script>
|
|
ScriptureValidator.attach('#id_scripture_raw');
|
|
</script>
|
|
{% endblock %} |