ProcessGit skatītājs MI stratēģijai
- viewer/MI_strategijas_datukopa.html (+ template.html): pīlāri, visas rīcības, principi un resursi, Par - data/processgit.viewer.json: pppa-mis-*.xml → skatītājs - tools/build_viewer.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016679RwmHsuTFfxt26wP6rk
This commit is contained in:
294
viewer/template.html
Normal file
294
viewer/template.html
Normal file
@@ -0,0 +1,294 @@
|
||||
<!doctype html>
|
||||
<html lang="lv">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>MI stratēģijas datukopa</title>
|
||||
<style>
|
||||
:root{--bg:#f6f7f9;--panel:#fff;--ink:#16202c;--muted:#5d6b7a;--line:#dde3ea;--acc:#1f5fbf;--acc-bg:#e8f0fc;--tag:#7a4a00;--tag-bg:#fff2d6;--rec:#6b2d8a;--rec-bg:#f3e8fa;--src:#0d6b4f;--src-bg:#e3f5ee;--hl:#fff7c2;--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
|
||||
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#11161d;--panel:#18202a;--ink:#e6ebf1;--muted:#9aa8b8;--line:#2a3542;--acc:#7fb0ff;--acc-bg:#1d2b40;--tag:#ffcf7a;--tag-bg:#3a2d12;--rec:#d9a8f5;--rec-bg:#33224a;--src:#7fe0bd;--src-bg:#123328;--hl:#4a4415}}
|
||||
:root[data-theme="dark"]{--bg:#11161d;--panel:#18202a;--ink:#e6ebf1;--muted:#9aa8b8;--line:#2a3542;--acc:#7fb0ff;--acc-bg:#1d2b40;--tag:#ffcf7a;--tag-bg:#3a2d12;--rec:#d9a8f5;--rec-bg:#33224a;--src:#7fe0bd;--src-bg:#123328;--hl:#4a4415}
|
||||
*{box-sizing:border-box}
|
||||
body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}
|
||||
.wrap{max-width:1080px;margin:0 auto;padding:0 16px}
|
||||
header{background:var(--panel);border-bottom:1px solid var(--line);padding:18px 0 0}
|
||||
.meta{display:flex;flex-wrap:wrap;gap:6px 10px;align-items:center;font-size:12.5px;color:var(--muted)}
|
||||
.chip{text-transform:none;letter-spacing:0;font-family:var(--mono);font-size:11.5px;background:var(--acc-bg);color:var(--acc);border-radius:6px;padding:1px 7px;white-space:nowrap}
|
||||
h1{margin:6px 0 2px;font-size:26px;line-height:1.2}
|
||||
.slogan{font-weight:600;color:var(--acc);letter-spacing:.02em}
|
||||
.vision{color:var(--muted);max-width:860px;margin:8px 0 12px}
|
||||
.tabs{display:flex;gap:2px;overflow-x:auto;scrollbar-width:none;margin-top:6px}
|
||||
.tabs button{border:0;background:none;color:var(--muted);font:inherit;font-weight:600;padding:10px 14px;border-bottom:3px solid transparent;cursor:pointer;white-space:nowrap}
|
||||
.tabs button.on{color:var(--ink);border-bottom-color:var(--acc)}
|
||||
main.wrap{padding-top:18px;padding-bottom:40px}
|
||||
.phead{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px 18px;margin-bottom:16px}
|
||||
.kicker{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--acc);margin:0}
|
||||
.phead h2{margin:4px 0 6px;font-size:21px}
|
||||
.phead p{margin:0}
|
||||
.goal{margin:22px 0 10px;display:flex;gap:10px;align-items:baseline}
|
||||
.goal .n{font-size:20px;font-weight:800;color:var(--acc)}
|
||||
.goal h3{margin:0;font-size:17px}
|
||||
.goal p{margin:4px 0 0;color:var(--muted)}
|
||||
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:12px}
|
||||
.card{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:14px 16px;display:flex;flex-direction:column;gap:7px;min-width:0;scroll-margin-top:14px;transition:background .6s}
|
||||
.card.flash{background:var(--hl)}
|
||||
.top{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
|
||||
.num{font-weight:800}
|
||||
.dl{margin-left:auto;font-size:12.5px;font-weight:600;white-space:nowrap}
|
||||
.dl.open{color:var(--tag)}
|
||||
.tag{font-size:11.5px;font-weight:600;border-radius:999px;padding:1px 8px;background:var(--tag-bg);color:var(--tag)}
|
||||
.tag.rec{background:var(--rec-bg);color:var(--rec)}
|
||||
.tag.src{background:var(--src-bg);color:var(--src)}
|
||||
.card h4{margin:0;font-size:15.5px;line-height:1.35}
|
||||
.card p{margin:0}
|
||||
.measure{font-size:13.5px;background:var(--bg);border-radius:8px;padding:7px 10px}
|
||||
.measure b{display:block;font-size:11.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
|
||||
.ref{font-size:13px;color:var(--muted);overflow-wrap:anywhere}
|
||||
.ref b{font-weight:600}
|
||||
a{color:var(--acc)}
|
||||
a.act{font-weight:600;text-decoration:none;border-bottom:1px dotted}
|
||||
.resp{font-size:12.5px;color:var(--muted);font-style:italic}
|
||||
.tools{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:12px}
|
||||
input[type=search],select{font:inherit;padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--panel);color:var(--ink);min-width:0}
|
||||
input[type=search]{flex:1 1 220px}
|
||||
table{width:100%;border-collapse:collapse;background:var(--panel);border:1px solid var(--line);border-radius:12px;overflow:hidden;font-size:14px}
|
||||
th,td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:top}
|
||||
th{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;cursor:pointer;user-select:none;white-space:nowrap}
|
||||
tr:last-child td{border-bottom:0}
|
||||
tbody tr{cursor:pointer}
|
||||
tbody tr:hover{background:var(--bg)}
|
||||
.tw{overflow-x:auto}
|
||||
.box{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px 18px;margin-bottom:14px}
|
||||
.box h2{margin:0 0 8px;font-size:18px}
|
||||
.box h3{margin:14px 0 6px;font-size:15px}
|
||||
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:10px;margin:10px 0}
|
||||
.tile{background:var(--bg);border-radius:10px;padding:10px 12px}
|
||||
.tile b{display:block;font-size:24px;line-height:1.1}
|
||||
.tile span{font-size:12.5px;color:var(--muted)}
|
||||
.prin{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px}
|
||||
.prin div{background:var(--bg);border-radius:10px;padding:10px 12px}
|
||||
.prin b{display:block;font-size:12.5px;color:var(--acc);text-transform:uppercase;letter-spacing:.05em}
|
||||
pre{font-family:var(--mono);font-size:12px;background:var(--bg);border-radius:8px;padding:10px;overflow-x:auto;margin:6px 0}
|
||||
code{font-family:var(--mono);font-size:12.5px}
|
||||
details summary{cursor:pointer;font-weight:600}
|
||||
.pgvbar{font-family:var(--mono);font-size:11.5px;color:var(--muted)}
|
||||
.hidden{display:none!important}
|
||||
.empty{padding:40px 0;text-align:center;color:var(--muted)}
|
||||
@media (max-width:560px){h1{font-size:21px}.grid{grid-template-columns:1fr}.dl{margin-left:0}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="wrap">
|
||||
<div class="meta" id="meta"></div>
|
||||
<h1 id="title">MI stratēģijas datukopa</h1>
|
||||
<div class="slogan" id="slogan"></div>
|
||||
<p class="vision" id="vision"></p>
|
||||
<nav class="tabs" id="tabs"></nav>
|
||||
</div>
|
||||
</header>
|
||||
<main class="wrap" id="main"><div class="empty">Ielādē…</div></main>
|
||||
<script id="embedded" type="application/xml">__XML__</script>
|
||||
<script id="xsd" type="application/xml">__XSD__</script>
|
||||
<script>
|
||||
"use strict";
|
||||
const NS = "urn:pppa:cac:mi-strategija:0.1";
|
||||
const $ = id => document.getElementById(id);
|
||||
const esc = s => String(s ?? "").replace(/[&<>"]/g, c => ({"&":"&","<":"<",">":">",'"':"""}[c]));
|
||||
const kids = (el, name) => el ? [...el.children].filter(c => c.localName === name) : [];
|
||||
const kid = (el, name) => kids(el, name)[0] || null;
|
||||
const tx = (el, name) => { const k = kid(el, name); return k ? k.textContent : ""; };
|
||||
let S = null, tab = "p1", ctx = {};
|
||||
|
||||
function parse(text){
|
||||
const doc = new DOMParser().parseFromString(text, "application/xml");
|
||||
const r = doc.documentElement;
|
||||
if (doc.querySelector("parsererror") || r.localName !== "AIStrategy") throw new Error("Nav MI stratēģijas XML (sagaidīts AIStrategy).");
|
||||
const s = {id: r.getAttribute("id"), version: r.getAttribute("version"), title: tx(r, "Title"), author: tx(r, "Author"),
|
||||
status: tx(r, "Status"), updated: tx(r, "Updated"), opened: tx(r, "ProposalsOpened"), url: tx(r, "SourceUrl"),
|
||||
slogan: kids(kid(r, "Slogan"), "Word").map(w => w.textContent), vision: tx(r, "Vision"), pillars: [], actions: {}, goals: 0};
|
||||
for (const p of kids(r, "Pillar")) {
|
||||
const P = {id: p.getAttribute("id"), n: p.getAttribute("number"), name: tx(p, "Name"), short: tx(p, "ShortTitle"),
|
||||
heading: tx(p, "Heading"), summary: tx(p, "Summary"), desc: tx(p, "Description"), goals: []};
|
||||
for (const g of kids(p, "Goal")) {
|
||||
const G = {id: g.getAttribute("id"), n: g.getAttribute("number"), title: tx(g, "Title"), desc: tx(g, "Description"), actions: []};
|
||||
s.goals++;
|
||||
for (const a of kids(g, "Action")) {
|
||||
const dl = kid(a, "Deadline");
|
||||
const A = {id: a.getAttribute("id"), n: +a.getAttribute("number"), title: tx(a, "Title"), text: tx(a, "Text"),
|
||||
measure: tx(a, "Measurement"), deadline: dl ? dl.textContent : "", dv: dl ? dl.getAttribute("value") || "" : "",
|
||||
tags: kids(a, "Tag").map(t => ({t: t.textContent, kind: t.getAttribute("kind") || ""})),
|
||||
resp: kids(a, "Responsible").map(x => ({t: x.textContent, org: x.getAttribute("org") || ""})),
|
||||
refs: kids(a, "Reference").map(x => ({t: x.textContent, kind: x.getAttribute("kind") || "",
|
||||
actions: (x.getAttribute("actions") || "").split(/\s+/).filter(Boolean),
|
||||
href: (x.getAttribute("href") || "").split(/\s+/).filter(Boolean)})),
|
||||
pillar: P, goal: G};
|
||||
A.proposal = A.refs.some(x => x.kind === "avots");
|
||||
G.actions.push(A); s.actions[A.id] = A;
|
||||
}
|
||||
P.goals.push(G);
|
||||
}
|
||||
s.pillars.push(P);
|
||||
}
|
||||
const pr = kid(r, "Principles");
|
||||
s.principles = pr ? {heading: tx(pr, "Heading"), intro: tx(pr, "Intro"),
|
||||
items: kids(pr, "Principle").map(x => ({id: x.getAttribute("id"), label: tx(x, "Label"), text: tx(x, "Text")}))} : null;
|
||||
const pn = kid(r, "ProposalsNote");
|
||||
s.proposals = pn ? {text: pn.textContent, actions: (pn.getAttribute("actions") || "").split(/\s+/).filter(Boolean)} : null;
|
||||
s.resources = kids(kid(r, "Resources"), "Resource").map(x => ({id: x.getAttribute("id"), href: x.getAttribute("href"),
|
||||
country: tx(x, "Country"), title: tx(x, "Title"), text: tx(x, "Text")}));
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Rīcību atsauces „Rīcība 10 (…)” un „(19)” → klikšķināmas saites uz rīcību */
|
||||
function linkActs(text, ids){
|
||||
let h = esc(text);
|
||||
const byN = Object.fromEntries(ids.map(id => [S.actions[id] ? S.actions[id].n : null, id]));
|
||||
h = h.replace(/Rīcība (\d+)/g, (m, n) => byN[n] ? `<a class="act" href="#${byN[n]}" data-act="${byN[n]}" title="${esc(S.actions[byN[n]].title)}">${m}</a>` : m);
|
||||
h = h.replace(/\((\d+)\)/g, (m, n) => byN[n] ? `(<a class="act" href="#${byN[n]}" data-act="${byN[n]}" title="${esc(S.actions[byN[n]].title)}">${n}</a>)` : m);
|
||||
return h;
|
||||
}
|
||||
const short = id => id.slice(S.id.length + 1);
|
||||
|
||||
function card(A){
|
||||
const tags = A.tags.map(t => `<span class="tag${t.kind ? " rec" : ""}">${esc(t.t)}</span>`).join("")
|
||||
+ (A.proposal ? `<span class="tag src" title="Avots: nozares priekšlikums">Nozares priekšlikums</span>` : "");
|
||||
const refs = A.refs.map(r => {
|
||||
const lab = {saistits: "Saistīts ar", avots: "Avots", piemers: "Piemērs"}[r.kind];
|
||||
const links = r.href.map(u => ` <a href="${esc(u)}" target="_blank" rel="noopener">↗</a>`).join("");
|
||||
return `<p class="ref">${lab ? `<b>${lab}:</b> ` : ""}${linkActs(r.t, r.actions)}${links}</p>`;
|
||||
}).join("");
|
||||
const resp = A.resp.length ? `<p class="ref"><b>Atbildīgais:</b> ${A.resp.map(x => esc(x.t) + (x.org ? ` <span class="chip">${esc(x.org)}</span>` : "")).join(", ")}</p>`
|
||||
: `<p class="resp">Atbildīgā institūcija nav noteikta</p>`;
|
||||
return `<article class="card" id="${esc(A.id)}">
|
||||
<div class="top"><span class="num">Rīcība ${A.n}</span><span class="chip" title="${esc(A.id)}">${esc(short(A.id))}</span>${tags}
|
||||
<span class="dl${A.dv ? "" : " open"}" title="Termiņš">${A.dv ? "⏱ " : ""}${esc(A.deadline)}</span></div>
|
||||
<h4>${esc(A.title)}</h4>
|
||||
<p>${esc(A.text)}</p>
|
||||
<div class="measure"><b>Mērķa izpildes mērījums</b>${esc(A.measure)}</div>
|
||||
${resp}${refs}
|
||||
</article>`;
|
||||
}
|
||||
|
||||
function renderPillar(P){
|
||||
return `<section class="phead"><p class="kicker">${esc(P.n)} pīlārs · ${esc(P.name)} <span class="chip">${esc(short(P.id))}</span></p>
|
||||
<h2>${esc(P.heading)}</h2><p>${esc(P.desc)}</p></section>`
|
||||
+ P.goals.map(G => `<div class="goal"><span class="n">${esc(G.n)}</span><div><h3>${esc(G.title)} <span class="chip">${esc(short(G.id))}</span></h3><p>${esc(G.desc)}</p></div></div>
|
||||
<div class="grid">${G.actions.map(card).join("")}</div>`).join("");
|
||||
}
|
||||
|
||||
function renderAll(){
|
||||
const pills = S.pillars.map(P => `<option value="${esc(P.id)}">${esc(P.n)} · ${esc(P.name)}</option>`).join("");
|
||||
return `<div class="tools"><input type="search" id="q" placeholder="Meklēt rīcībās…" value="${esc(ctx.q || "")}">
|
||||
<select id="fp"><option value="">Visi pīlāri</option>${pills}</select>
|
||||
<select id="ft"><option value="">Visas rīcības</option><option value="prop">Nozares priekšlikumi</option><option value="rec">Pārvaldības rekomendācijas</option><option value="open">Bez termiņa</option></select>
|
||||
<span class="meta" id="cnt"></span></div>
|
||||
<div class="tw"><table><thead><tr><th data-s="n">Nr.</th><th data-s="title">Rīcība</th><th data-s="p">Pīlārs · mērķis</th><th data-s="dv">Termiņš</th></tr></thead><tbody id="rows"></tbody></table></div>`;
|
||||
}
|
||||
function fillRows(){
|
||||
const q = ($("q").value || "").toLowerCase(), fp = $("fp").value, ft = $("ft").value, s = ctx.sort || "n";
|
||||
ctx.q = $("q").value;
|
||||
let list = Object.values(S.actions).filter(A =>
|
||||
(!fp || A.pillar.id === fp) &&
|
||||
(!ft || (ft === "prop" && A.proposal) || (ft === "rec" && A.tags.some(t => t.kind)) || (ft === "open" && !A.dv)) &&
|
||||
(!q || [A.title, A.text, A.measure, ...A.refs.map(r => r.t)].join(" ").toLowerCase().includes(q)));
|
||||
const key = {n: A => A.n, title: A => A.title, p: A => A.pillar.n + A.goal.n, dv: A => A.dv || "9999"}[s];
|
||||
list.sort((a, b) => key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : a.n - b.n);
|
||||
$("rows").innerHTML = list.map(A => `<tr data-act="${esc(A.id)}"><td><b>${A.n}</b></td>
|
||||
<td>${esc(A.title)}${A.tags.map(t => ` <span class="tag${t.kind ? " rec" : ""}">${esc(t.t)}</span>`).join("")}${A.proposal ? ` <span class="tag src">Nozares priekšlikums</span>` : ""}</td>
|
||||
<td>${esc(A.pillar.n)} · ${esc(A.pillar.name)}<br><span class="meta">${esc(A.goal.n)} ${esc(A.goal.title)}</span></td>
|
||||
<td style="white-space:nowrap">${esc(A.deadline)}</td></tr>`).join("") || `<tr><td colspan="4" class="empty">Nekas nav atrasts</td></tr>`;
|
||||
$("cnt").textContent = `${list.length} no ${Object.keys(S.actions).length}`;
|
||||
}
|
||||
|
||||
function renderPrinciples(){
|
||||
let h = "";
|
||||
if (S.principles) h += `<div class="box"><h2>${esc(S.principles.heading)}</h2><p>${esc(S.principles.intro)}</p>
|
||||
<div class="prin">${S.principles.items.map(x => `<div><b>${esc(x.label)}</b>${esc(x.text)}</div>`).join("")}</div></div>`;
|
||||
if (S.proposals) h += `<div class="box"><h2>Saņemtie priekšlikumi</h2><p>${linkActs(S.proposals.text, S.proposals.actions)}</p></div>`;
|
||||
if (S.resources.length) h += `<div class="box"><h2>Starptautiskā pieredze</h2><div class="prin">${S.resources.map(x =>
|
||||
`<div><b>${esc(x.country)}</b><a href="${esc(x.href)}" target="_blank" rel="noopener">${esc(x.title)} ↗</a><br><span class="meta">${esc(x.text)}</span></div>`).join("")}</div></div>`;
|
||||
return h;
|
||||
}
|
||||
|
||||
function renderAbout(){
|
||||
const acts = Object.values(S.actions), nores = acts.filter(a => !a.resp.length).length;
|
||||
const open = acts.filter(a => !a.dv).length, prop = acts.filter(a => a.proposal).length;
|
||||
const xsd = $("xsd").textContent.trim();
|
||||
return `<div class="box"><h2>Par datukopu</h2>
|
||||
<p>PPP Asociācijas (PPPA) piedāvātā Latvijas Nacionālā MI stratēģija mašīnlasāmā formā — daļa no iniciatīvas <i>Country as Code</i> (Valsts kā Kods). Teksts pārņemts burtiski, kā publicēts: <a href="${esc(S.url)}" target="_blank" rel="noopener">${esc(S.url)}</a>.</p>
|
||||
<div class="tiles">
|
||||
<div class="tile"><b>${S.pillars.length}</b><span>pīlāri</span></div>
|
||||
<div class="tile"><b>${S.goals}</b><span>stratēģiskie mērķi</span></div>
|
||||
<div class="tile"><b>${acts.length}</b><span>rīcības</span></div>
|
||||
<div class="tile"><b>${prop}</b><span>nozares priekšlikumi</span></div>
|
||||
<div class="tile"><b>${open}</b><span>bez noteikta termiņa</span></div>
|
||||
<div class="tile"><b>${nores}</b><span>bez atbildīgās institūcijas</span></div>
|
||||
</div>
|
||||
${nores ? `<p><b>Atbildīgās institūcijas nav noteiktas</b> ${nores} no ${acts.length} rīcībām. Shēmā katrai rīcībai paredzēts elements <code>Responsible</code> ar CaC ID (<code>SS-IIII</code>) no Organizāciju reģistra, lai izpildi varētu sasaistīt ar konkrētu iestādi.</p>` : ""}
|
||||
<h3>Identifikatori</h3>
|
||||
<div class="tw"><table><thead><tr><th>Elements</th><th>ID</th><th>Piemērs</th></tr></thead><tbody>
|
||||
<tr><td>Stratēģija</td><td><code>pppa-mis-GGGG-MM-DD</code> (atjaunošanas datums)</td><td><code>${esc(S.id)}</code></td></tr>
|
||||
<tr><td>Pīlārs</td><td><code>.pN</code></td><td><code>${esc(S.id)}.p2</code></td></tr>
|
||||
<tr><td>Mērķis</td><td><code>.mN</code> (vienota numerācija)</td><td><code>${esc(S.id)}.m3</code></td></tr>
|
||||
<tr><td>Rīcība</td><td><code>.rNN</code> (= drukātais numurs)</td><td><code>${esc(S.id)}.r09</code></td></tr>
|
||||
<tr><td>Princips / resurss</td><td><code>.prN</code> / <code>.aN</code></td><td><code>${esc(S.id)}.pr1</code></td></tr>
|
||||
</tbody></table></div>
|
||||
<p style="margin-top:8px;font-size:12.5px;color:var(--muted)">Datne = dokumenta ID (<code>${esc(S.id)}.xml</code>). Termiņi glabāti kā publicēti un atribūtā <code>@value</code> ISO formā. Atsauces uz citām rīcībām — atribūtā <code>@actions</code>.</p>
|
||||
${xsd && !xsd.startsWith("__") ? `<h3>Shēma</h3><details><summary>mi-strategija-0.1.xsd</summary><pre>${esc(xsd)}</pre></details>` : ""}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const TABS = () => [...S.pillars.map(P => [P.id.slice(S.id.length + 1), `${P.n} · ${P.name}`]), ["all", "Visas rīcības"], ["prin", "Principi un resursi"], ["about", "Par"]];
|
||||
function render(){
|
||||
document.title = `${S.title} · ${S.version}`;
|
||||
$("title").textContent = S.title;
|
||||
$("slogan").textContent = S.slogan.join(" · ");
|
||||
$("vision").textContent = S.vision;
|
||||
$("meta").innerHTML = `<span>${esc(S.author)}</span><span>· ${esc(S.status)} ${esc(S.version)}</span><span>· atjaunots ${esc(S.updated)}</span><span class="chip">${esc(S.id)}</span>`
|
||||
+ (ctx.pgv ? `<span class="pgvbar">· ${esc(ctx.pgv)}</span>` : "");
|
||||
$("tabs").innerHTML = TABS().map(([k, l]) => `<button data-tab="${k}" class="${k === tab ? "on" : ""}">${esc(l)}</button>`).join("");
|
||||
const P = S.pillars.find(p => short(p.id) === tab);
|
||||
$("main").innerHTML = P ? renderPillar(P) : tab === "all" ? renderAll() : tab === "prin" ? renderPrinciples() : renderAbout();
|
||||
if (tab === "all") { fillRows(); ["q", "fp", "ft"].forEach(i => $(i).addEventListener("input", fillRows)); if (ctx.fp) $("fp").value = ctx.fp; }
|
||||
}
|
||||
function setTab(t){ tab = t; render(); try { history.replaceState(null, "", "#" + t); } catch (e) {} scrollTo(0, 0); }
|
||||
function goAction(id){
|
||||
const A = S.actions[id]; if (!A) return;
|
||||
tab = short(A.pillar.id); render();
|
||||
const el = $(id); if (!el) return;
|
||||
el.scrollIntoView({behavior: "smooth", block: "start"}); el.classList.add("flash"); setTimeout(() => el.classList.remove("flash"), 1400);
|
||||
}
|
||||
document.addEventListener("click", ev => {
|
||||
const t = ev.target.closest("[data-tab]"); if (t) { setTab(t.dataset.tab); return; }
|
||||
const a = ev.target.closest("[data-act]"); if (a) { ev.preventDefault(); goAction(a.dataset.act); return; }
|
||||
const th = ev.target.closest("th[data-s]"); if (th) { ctx.sort = th.dataset.s; fillRows(); }
|
||||
});
|
||||
|
||||
function load(text){
|
||||
try { S = parse(text); } catch (e) { $("main").innerHTML = `<div class="empty">${esc(e.message)}</div>`; return; }
|
||||
const h = location.hash.slice(1);
|
||||
if (S.actions[h]) { goAction(h); return; }
|
||||
tab = TABS().some(([k]) => k === h) ? h : short(S.pillars[0].id);
|
||||
render();
|
||||
}
|
||||
|
||||
/* ===== ProcessGit skatītājs (processgit.viewer.json): PGV_READY → PGV_INIT → PGV_FETCH ===== */
|
||||
function pgvFetch(url){ return new Promise((res, rej) => {
|
||||
const tm = setTimeout(() => { removeEventListener("message", hd); rej(new Error("PGV_FETCH timeout")); }, 15000);
|
||||
function hd(ev){ const m = ev.data; if (!m || m.type !== "PGV_FETCH_RESULT" || m.url !== url) return; clearTimeout(tm); removeEventListener("message", hd); m.ok ? res(m.text) : rej(new Error(m.error || "fetch failed")); }
|
||||
addEventListener("message", hd); parent.postMessage({type: "PGV_FETCH", url}, "*"); }); }
|
||||
async function pgvInit(p){
|
||||
const url = (p.targets && p.targets.xml) || `${p.repoLink}/raw/branch/${p.branch}/${p.path}`;
|
||||
ctx.pgv = `ProcessGit · ${p.branch || ""} · ${p.path || ""}${p.lastCommit ? " · " + p.lastCommit.slice(0, 7) : ""}`;
|
||||
try { load(await pgvFetch(url)); } catch (e) { $("main").innerHTML = `<div class="empty">Neizdevās ielādēt datni no repozitorija: ${esc(e.message)}</div>`; }
|
||||
}
|
||||
const inFrame = window.parent && window.parent !== window;
|
||||
if (inFrame) {
|
||||
addEventListener("message", ev => { const m = ev.data; if (m && typeof m === "object" && m.type === "PGV_INIT") pgvInit(m.payload || {}); });
|
||||
try { parent.postMessage({type: "PGV_READY"}, "*"); } catch (e) {}
|
||||
setTimeout(() => { if (!S) $("main").innerHTML = `<div class="empty">Gaida datni no ProcessGit…</div>`; }, 4000);
|
||||
} else load($("embedded").textContent.trim());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user