inventory/inventory/templates/inventory_note.html
2025-10-21 11:33:11 -05:00

103 lines
3.8 KiB
HTML

<label class="form-label">Notes</label>
<div class="d-flex justify-content-between align-items-start border rounded py-1 px-2">
<div class="me-3 w-100 markdown-body" id="editContainer"></div>
<script type="application/json" id="noteContent">{{ (field['template_ctx']['values']['notes'] if field['template_ctx']['values']['notes'] else '') | tojson }}</script>
<div class="form-check form-switch">
<input type="checkbox" class="form-check-input" id="editSwitch" onchange="changeMode()" role="switch"
aria-label="Edit mode switch for inventory notes.">
<label for="editSwitch" class="form-check-label">Edit</label>
</div>
</div>
<!-- link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown.min.css" -->
<style>
textarea.auto-md {
box-sizing: border-box;
width: 100%;
max-height: 60vh;
overflow: hidden;
resize: vertical;
}
@supports (field-sizing: content) {
textarea.auto-md {
field-sizing: content;
}
}
</style>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
<script src="{{ url_for('static', filename='js/components/markdown.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/utils/json.js') }}" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
MarkDown.renderInto(document.getElementById('editContainer'), getMarkdown());
});
// used by entry_buttons submit
window.getMarkdown = function () {
return readJSONScript('noteContent', "");
};
function setMarkdown(md) {
const el = document.getElementById('noteContent');
if (el) el.textContent = JSON.stringify(md ?? "");
}
function changeMode() {
const container = document.getElementById('editContainer');
const toggle = document.getElementById('editSwitch');
if (!toggle.checked) {
MarkDown.renderInto(container, getMarkdown());
return;
}
const current = getMarkdown();
container.innerHTML = `
<textarea class="form-control w-100 auto-md" id="editor" name="notes">${escapeForTextarea(current)}</textarea>
<div class="mt-2 d-flex gap-2">
<button type="button" class="btn btn-primary btn-sm" onclick="saveEdit()">Save</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="cancelEdit()">Cancel</button>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="togglePreview()">Preview</button>
</div>
<div class="mt-2 border rounded p-2 d-none" id="preview" aria-live="polite"></div>
`;
const ta = document.getElementById('editor');
autoGrow(ta);
ta.addEventListener('input', () => autoGrow(ta));
}
function saveEdit() {
const ta = document.getElementById('editor');
const value = ta ? ta.value : "";
setMarkdown(value);
MarkDown.renderInto(document.getElementById('editContainer'), value);
document.getElementById('editSwitch').checked = false;
}
function cancelEdit() {
document.getElementById('editSwitch').checked = false;
MarkDown.renderInto(document.getElementById('editContainer'), getMarkdown());
}
function togglePreview() {
const ta = document.getElementById('editor');
const preview = document.getElementById('preview');
preview.classList.toggle('d-none');
if (!preview.classList.contains('d-none')) {
MarkDown.renderInto(preview, ta ? ta.value : "");
}
}
function autoGrow(ta) {
if (!ta) return;
if (CSS?.supports?.('field-sizing: content')) return;
ta.style.height = 'auto';
ta.style.height = ta.scrollHeight + 'px';
}
function escapeForTextarea(s) {
return (s ?? "").replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
</script>