UNPKG

@sfgrp/pinpoint

Version:

Pinpoint is a engine for displaying hierarchical keys that identify the Earth's species.

454 lines (453 loc) 13.5 kB
var B = Object.defineProperty; var D = (o, t, e) => t in o ? B(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e; var w = (o, t, e) => D(o, typeof t != "symbol" ? t + "" : t, e); import { reactive as G, defineComponent as $, inject as L, openBlock as i, createElementBlock as a, createElementVNode as l, unref as u, createTextVNode as y, toDisplayString as v, createCommentVNode as p, Fragment as N, renderList as E, createBlock as k, onMounted as H, onUnmounted as q, withModifiers as O, renderSlot as g, ref as K, withCtx as h, createVNode as T, computed as I, provide as A, watch as J } from "vue"; function W(o) { return String(o).replace(/(\d+)(\.)?/, (t, e, n) => { const s = parseInt(e, 10) - 1; return n ? `${s}.` : `${s}`; }); } function z(o, t) { const e = new URL(o); return t && Object.entries(t).forEach(([n, s]) => { e.searchParams.append(n, s.toString()); }), e.toString(); } async function Q(o, { method: t, data: e, parameters: n } = {}) { try { const s = { method: t || "GET", headers: { "Content-Type": "application/json" }, body: e ? JSON.stringify(e) : void 0 }, r = await fetch(z(o, n), s); if (!r.ok) throw new Error( `Error response: ${r.status} ${r.statusText}` ); return await r.json(); } catch (s) { throw console.error("Error:", s), s; } } class S { constructor(t) { w(this, "baseUrl"); w(this, "projectToken"); this.baseUrl = t.baseUrl, this.projectToken = t.projectToken; } getDichotomousKey(t) { return Q(`${this.baseUrl}/leads/key/${t}`, { parameters: { project_token: this.projectToken } }); } } function X(o) { return { children: o.children || [], coupletNumber: o.couplet_number, parentId: o.parent_id, depth: o.depth, position: o.position }; } function Y(o, { baseUrl: t, projectToken: e }) { var n; return { caption: o.caption, label: o.label, position: o.position, image: o.medium, original: `${t}/${(n = o.original_png) == null ? void 0 : n.substring( 8 )}?project_token=${e}` }; } function Z(o, t) { var e; return { text: o.text, parentId: o.parent_id, targetId: o.target_id, targetLabel: o.target_label, targetType: o.target_type, position: o.position, figures: ((e = o.figures) == null ? void 0 : e.map((n) => Y(n, t))) || [] }; } function P(o) { return { currentNode: null, metadata: null, entries: {}, leads: {}, nodes: {}, config: o }; } function x(o) { let t = new S(o); const e = G(P(o)); function n(d) { return Object.fromEntries( Object.entries(d).map(([_, b]) => [_, X(b)]) ); } function s(d) { e.config = d, t = new S(d); } function r() { Object.assign(e, P(o)); } function c(d) { return Object.fromEntries( Object.entries(d).map(([_, b]) => [ _, Z(b, e.config) ]) ); } function f(d, _) { const b = {}; for (const [j, R] of Object.entries(_)) { const U = d[j]; b[j] = { id: parseInt(j, 10), ...R, ...U }, U || Object.assign(b[j], { children: [] }); } return b; } return { state: e, loadKey: (d) => t.getDichotomousKey(d).then(({ data: _, metadata: b }) => { e.entries = n(_.entries), e.leads = c(_.leads), e.nodes = f(e.entries, e.leads), e.currentNode = Object.values(e.nodes)[0], e.metadata = b; }), setCurrentNode: (d) => { e.currentNode = e.nodes[d]; }, setConfig: s, reset: r }; } const ee = { class: "pinpoint-tree" }, te = ["innerHTML"], ne = { key: 0 }, V = /* @__PURE__ */ $({ __name: "Tree", props: { node: {}, coupletNumber: {} }, setup(o) { const t = L("store"); return (e, n) => (i(), a("ul", ee, [ l("li", null, [ l("span", { onClick: n[0] || (n[0] = () => u(t).setCurrentNode(e.node.parentId)) }, [ y(" [" + v(e.coupletNumber) + "] ", 1), l("span", { innerHTML: e.node.text }, null, 8, te), isNaN(e.node.targetLabel) ? (i(), a("span", ne, "[" + v(e.node.targetLabel) + "]", 1)) : p("", !0) ]), (i(!0), a(N, null, E(e.node.children, (s) => (i(), a(N, null, [ u(t).state.nodes[s] ? (i(), k(V, { key: 0, node: u(t).state.nodes[s], "couplet-number": e.node.coupletNumber }, null, 8, ["node", "couplet-number"])) : p("", !0) ], 64))), 256)) ]) ])); } }), oe = { class: "pinpoint-modal-panel" }, se = { __name: "Modal", emits: ["close"], setup(o, { emit: t }) { const e = t, n = (s) => { s.key === "Escape" && (s.stopPropagation(), e("close")); }; return H(() => { document.addEventListener("keydown", n), document.body.classList.add("overflow-hidden"); }), q(() => { document.removeEventListener("keydown", n), document.body.classList.remove("overflow-hidden"); }), (s, r) => (i(), a("div", { class: "pinpoint-modal-wrapper", onClick: r[1] || (r[1] = (c) => e("close")), onKey: r[2] || (r[2] = O((c) => e("close"), ["stop"])) }, [ l("div", { class: "pinpoint-modal-container", onClick: r[0] || (r[0] = O(() => { }, ["stop"])) }, [ l("div", oe, [ g(s.$slots, "default") ]) ]) ], 32)); } }, re = ["src"], ie = ["src"], ae = /* @__PURE__ */ $({ __name: "FigureItem", props: { figure: {} }, setup(o) { const t = K(!1); return (e, n) => (i(), a("div", null, [ l("img", { src: e.figure.image, class: "pinpoint-figure", onClick: n[0] || (n[0] = () => t.value = !t.value) }, null, 8, re), t.value ? (i(), k(se, { key: 0, onClose: n[2] || (n[2] = () => t.value = !1) }, { default: h(() => [ l("img", { class: "pinpoint-figure-image", src: e.figure.original, onClick: n[1] || (n[1] = () => t.value = !0) }, null, 8, ie) ]), _: 1 })) : p("", !0) ])); } }), le = { class: "pinpoint-figure-list" }, ue = /* @__PURE__ */ $({ __name: "FigureList", props: { figures: {} }, setup(o) { return (t, e) => (i(), a("div", le, [ (i(!0), a(N, null, E(t.figures, (n) => (i(), k(ae, { key: n.image, figure: n }, null, 8, ["figure"]))), 128)) ])); } }), de = { class: "pinpoint-node-container" }, pe = { class: "pinpoint-node" }, ce = { class: "pinpoint-node-text" }, me = { key: 1, class: "pinpoint-node-target" }, be = { key: 0, class: "pinpoint-node-children-container" }, ge = { class: "pinpoint-node-next-container" }, _e = /* @__PURE__ */ $({ __name: "Node", props: { node: {} }, setup(o) { const t = L("store"); return (e, n) => (i(), a("div", de, [ e.node ? (i(), a(N, { key: 0 }, [ l("div", pe, [ e.node.children.length ? (i(), a("button", { key: 0, class: "pinpoint-button-go", type: "button", onClick: n[0] || (n[0] = () => u(t).state.currentNode = e.node) }, " Go ")) : p("", !0), l("p", ce, v(e.node.text), 1), isNaN(e.node.targetLabel) ? (i(), a("p", me, [ g(e.$slots, "target", { label: e.node.targetLabel, id: e.node.targetId }, () => [ y(v(e.node.targetLabel), 1) ]) ])) : p("", !0), T(ue, { figures: e.node.figures }, null, 8, ["figures"]) ]), e.node.children.length ? (i(), a("div", be, [ l("div", ge, [ l("button", { class: "pinpoint-node-next-button", type: "button", onClick: n[1] || (n[1] = (s) => u(t).setCurrentNode(u(t).state.nodes[e.node.children[0]].parentId)) }, [ g(e.$slots, "button-next-label", {}, () => [ n[2] || (n[2] = y(" Next ")) ]) ]) ]), (i(!0), a(N, null, E(e.node.children.map((s) => u(t).state.nodes[s]), (s) => (i(), k(V, { "couplet-number": e.node.coupletNumber, node: s }, null, 8, ["couplet-number", "node"]))), 256)) ])) : p("", !0) ], 64)) : p("", !0) ])); } }), ve = { class: "pinpoint-couplet" }, fe = { class: "pinpoint-couplet-container" }, ke = { class: "pinpoint-couplet-node" }, $e = { key: 0 }, he = { key: 1, class: "pinpoint-node-target" }, ye = { class: "pinpoint-couplet-children-container" }, Ne = { __name: "Couplet", setup(o) { const t = L("store"), e = I(() => t.state.currentNode), n = I(() => t.state.currentNode.children.map((r) => t.state.nodes[r])); return (s, r) => (i(), a("div", ve, [ l("div", fe, [ u(t).state.currentNode.parentId ? (i(), a("button", { key: 0, class: "pinpoint-button-up", type: "button", onClick: r[0] || (r[0] = () => u(t).state.currentNode = u(t).state.nodes[e.value.parentId]) }, [ g(s.$slots, "button-up-label", {}, () => [ r[1] || (r[1] = y("Up")) ]) ])) : p("", !0), l("div", ke, [ e.value.parentId ? (i(), a("h1", $e, " Couplet " + v(e.value.coupletNumber), 1)) : p("", !0), isNaN(e.value.targetLabel) && !e.value.parentId ? (i(), a("p", he, [ g(s.$slots, "target", { label: e.value.targetLabel, id: e.value.targetId }, () => [ y(v(e.value.targetLabel), 1) ]) ])) : p("", !0) ]) ]), l("div", ye, [ (i(!0), a(N, null, E(n.value, (c) => (i(), k(_e, { node: c, key: c.id }, { target: h(({ id: f, label: m }) => [ g(s.$slots, "target", { id: f, label: m }) ]), "button-next-label": h(() => [ g(s.$slots, "button-next-label") ]), _: 2 }, 1032, ["node"]))), 128)) ]) ])); } }, Ce = { key: 0 }, M = /* @__PURE__ */ $({ __name: "PreviousList", props: { nodes: {} }, setup(o) { const t = L("store"); return (e, n) => { var s; return (s = e.nodes) != null && s.length ? (i(), a("ul", Ce, [ l("li", null, [ l("span", { class: "pinpoint-previous-list-item", onClick: n[0] || (n[0] = () => u(t).setCurrentNode(e.nodes[0].parentId)) }, "[" + v(u(W)(e.nodes[0].coupletNumber)) + "] " + v(e.nodes[0].text), 1), T(M, { nodes: e.nodes.slice(1) }, null, 8, ["nodes"]) ]) ])) : p("", !0); }; } }), Le = { class: "pinpoint-previous-couplets" }, je = { class: "pinpoint-previous-list" }, Ie = /* @__PURE__ */ $({ __name: "PreviousCouplets", props: { node: {} }, setup(o) { const t = o, e = L("store"), n = I(() => { const s = []; let r = t.node.id; for (; r !== null; ) { const c = e.state.nodes[r]; r = c.parentId, s.unshift(c); } return s.splice(0, 1), s; }); return (s, r) => (i(), a("div", Le, [ r[0] || (r[0] = l("h2", null, "Previous couplets", -1)), l("div", je, [ T(M, { nodes: n.value }, null, 8, ["nodes"]) ]) ])); } }), C = { Loading: "loading", Error: "error", End: "end", Start: "start" }, Ee = { class: "pinpoint-app" }, we = { key: 0, class: "pinpoint-key-title" }, Te = { key: 3 }, Se = /* @__PURE__ */ $({ __name: "VuePinpoint", props: { leadId: {}, projectToken: {}, baseUrl: {} }, emits: Object.values(C), setup(o, { expose: t, emit: e }) { const n = o, s = e, r = x(n), c = I(() => r.state.currentNode), f = K(null); return A("store", r), J( [() => n.leadId, () => n.projectToken, () => n.baseUrl], () => { r.reset(), r.setConfig(n), f.value = null, n.leadId && n.baseUrl && n.projectToken && n.baseUrl && (s(C.Start), s(C.Loading), r.loadKey(n.leadId).then((m) => { s(C.End, m); }).catch((m) => { s(C.Error, m), f.value = m; })); }, { immediate: !0 } ), t({ getState: () => r.state }), (m, F) => { var d; return i(), a("div", Ee, [ u(r).state.metadata ? (i(), a("div", we, [ g(m.$slots, "title", { title: u(r).state.metadata.title, metadata: u(r).state.metadata }, () => [ y(v(u(r).state.metadata.title), 1) ]) ])) : p("", !0), (d = c.value) != null && d.parentId ? (i(), k(Ie, { key: 1, node: c.value }, null, 8, ["node"])) : p("", !0), c.value ? (i(), k(Ne, { key: 2 }, { target: h(({ id: _, label: b }) => [ g(m.$slots, "target", { label: b, id: _ }) ]), "button-up-label": h(() => [ g(m.$slots, "button-up-label") ]), "button-next-label": h(() => [ g(m.$slots, "button-next-label") ]), _: 3 })) : p("", !0), f.value ? (i(), a("div", Te, v(f.value.message), 1)) : p("", !0) ]); }; } }); export { Se as VuePinpoint };