diff options
Diffstat (limited to 'internal/web/templates/partials/imagelib.html')
| -rw-r--r-- | internal/web/templates/partials/imagelib.html | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/internal/web/templates/partials/imagelib.html b/internal/web/templates/partials/imagelib.html new file mode 100644 index 0000000..bc94f2b --- /dev/null +++ b/internal/web/templates/partials/imagelib.html @@ -0,0 +1,72 @@ +{{/* The image library panel behind every imagepick's "Choose from library…": + one per form, fetched page by page from the Files page's JSON. Its script + is self-contained: a choice goes into the imagepick's select and fires a + change event there, so the form sees it like any other edit. Without + fetch the buttons hide and the select stands in. .sub is the blog, + .count how many images the library has. */}} +{{define "imagelib"}}<div class="picker" id="picker" data-sub="{{.sub}}" hidden> + <div class="picker-box"> + <div class="picker-head"> + <input type="search" placeholder="{{t "Filter by name…"}}" aria-label="{{t "Filter by name…"}}"> + <span class="muted small pcount">{{tf "%d images" .count}}</span> + <button type="button" class="secondary small" data-pick="close">{{t "Close"}}</button> + </div> + <div class="picks"></div> + <p class="muted small pnone" hidden>{{t "No images match."}}</p> + <div class="pager"><button type="button" class="mini" data-pick="prev">← {{t "Newer"}}</button> <span class="pnum"></span> <button type="button" class="mini" data-pick="next">{{t "Older"}} →</button></div> + </div> +</div> +<script> +(function () { + var panel = document.getElementById("picker"), sub = panel.getAttribute("data-sub"), pick = null, page = 1, filter = "", timer; + function q(sel, el) { return (el || document).querySelector(sel); } + function qa(sel, el) { return Array.prototype.slice.call((el || document).querySelectorAll(sel)); } + if (!window.fetch || !panel.closest) return; // the select stands in + qa(".imagepick").forEach(function (ip) { ip.className += " js"; }); + document.addEventListener("click", function (e) { + var b = e.target.closest("[data-pick]"), ip = b && b.closest(".imagepick"); + if (!ip) return; + if (b.getAttribute("data-pick") === "open") { pick = ip; panel.hidden = false; q("input", panel).value = filter = ""; load(1); q("input", panel).focus(); } + else if (b.getAttribute("data-pick") === "clear") { choose(ip, "none", ""); } + }); + panel.addEventListener("click", function (e) { + var b = e.target.closest("[data-pick],.pick"); + if (!b) return; + if (b.className.indexOf("pick") === 0) { choose(pick, b.getAttribute("data-id"), b.getAttribute("data-name")); panel.hidden = true; return; } + switch (b.getAttribute("data-pick")) { + case "close": panel.hidden = true; break; + case "prev": load(page - 1); break; + case "next": load(page + 1); break; + } + }); + panel.addEventListener("keydown", function (e) { if (e.key === "Escape") panel.hidden = true; }); + q("input", panel).addEventListener("input", function () { clearTimeout(timer); timer = setTimeout(function () { filter = q("input", panel).value.trim(); load(1); }, 250); }); + function load(n) { + var url = "/b/" + sub + "/files?kind=image&p=" + n + (filter ? "&q=" + encodeURIComponent(filter) : ""); + fetch(url, { headers: { Accept: "application/json" }, credentials: "same-origin" }).then(function (r) { return r.json(); }).then(function (d) { + page = d.page; + var grid = q(".picks", panel); grid.innerHTML = ""; + (d.files || []).forEach(function (f) { + var b = document.createElement("button"), img = document.createElement("img"), s = document.createElement("span"); + b.type = "button"; b.className = "pick"; b.setAttribute("data-id", f.id); b.setAttribute("data-name", f.filename); + img.loading = "lazy"; img.src = "/b/" + sub + "/media/" + f.id; img.alt = ""; + s.className = "name"; s.textContent = f.filename; + b.appendChild(img); b.appendChild(s); grid.appendChild(b); + }); + q(".pnone", panel).hidden = !!(d.files && d.files.length); + q(".pnum", panel).textContent = d.last > 1 ? d.page + " / " + d.last : ""; + q("[data-pick=prev]", panel).disabled = d.page <= 1; q("[data-pick=next]", panel).disabled = d.page >= d.last; + }); + } + function choose(ip, id, name) { // the select stays the value the form sends + var sel = q("select", ip), pv = q(".preview", ip), found = false; + for (var i = 0; i < sel.options.length; i++) if (sel.options[i].value === id) found = true; + if (!found) { var o = document.createElement("option"); o.value = id; o.textContent = name; sel.appendChild(o); } + sel.value = id; + pv.innerHTML = id === "none" ? '<span class="swatch">×</span>' : ""; + if (id !== "none") { var img = document.createElement("img"); img.src = "/b/" + sub + "/media/" + id; img.alt = ""; pv.appendChild(img); } + var ev; try { ev = new Event("change", { bubbles: true }); } catch (_) { ev = document.createEvent("Event"); ev.initEvent("change", true, false); } + sel.dispatchEvent(ev); + } +})(); +</script>{{end}} |
