@guidelytech/guide-runtime 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capture.cjs +183 -34
- package/dist/capture.cjs.map +1 -1
- package/dist/capture.js +9 -14
- package/dist/capture.js.map +1 -1
- package/dist/chunk-GUH2PQJ7.js +462 -0
- package/dist/chunk-GUH2PQJ7.js.map +1 -0
- package/dist/chunk-H3CROHPR.js +585 -0
- package/dist/chunk-H3CROHPR.js.map +1 -0
- package/dist/chunk-VJSQM23R.js +359 -0
- package/dist/chunk-VJSQM23R.js.map +1 -0
- package/dist/chunk-VQJ7MZ2K.js +463 -0
- package/dist/chunk-VQJ7MZ2K.js.map +1 -0
- package/dist/index.cjs +501 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -9
- package/dist/index.d.ts +70 -9
- package/dist/index.js +150 -25
- package/dist/index.js.map +1 -1
- package/dist/messenger.cjs +1171 -167
- package/dist/messenger.cjs.map +1 -1
- package/dist/messenger.d.cts +55 -5
- package/dist/messenger.d.ts +55 -5
- package/dist/messenger.js +1029 -96
- package/dist/messenger.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
import {
|
|
2
|
+
prefersReducedMotion
|
|
3
|
+
} from "./chunk-VJSQM23R.js";
|
|
4
|
+
|
|
5
|
+
// src/sanitize.ts
|
|
6
|
+
import { EMBED_IFRAME_ATTRS, VIDEO_ATTRS, isAllowedEmbedSrc, isSafeMediaUrl } from "@guidelytech/shared/runtime";
|
|
7
|
+
var ALLOWED_TAGS = /* @__PURE__ */ new Set(["p", "br", "strong", "b", "em", "i", "u", "a", "ul", "ol", "li", "img", "h1", "h2", "h3", "h4", "code", "pre", "blockquote", "span", "div", "hr", "button"]);
|
|
8
|
+
var DROP_TAGS = /* @__PURE__ */ new Set(["script", "style", "object", "embed", "form", "input", "textarea", "select", "link", "meta", "base", "template", "svg", "math", "frame", "frameset", "noscript"]);
|
|
9
|
+
var ALLOWED_ATTRS = /* @__PURE__ */ new Set(["href", "src", "alt", "title", "target", "rel", "class", "width", "height", "data-g-action", "data-g-value"]);
|
|
10
|
+
function isSafeUrl(value, attr, tag) {
|
|
11
|
+
const v = value.trim().replace(/[\u0000-\u001f\s]/g, "").toLowerCase();
|
|
12
|
+
if (!v) return false;
|
|
13
|
+
const m = /^([a-z][a-z0-9+.-]*):/.exec(v);
|
|
14
|
+
if (!m) return true;
|
|
15
|
+
const scheme = m[1];
|
|
16
|
+
if (scheme === "data") return tag === "img" && attr === "src" && v.startsWith("data:image/");
|
|
17
|
+
return scheme === "http" || scheme === "https" || scheme === "mailto" || scheme === "tel";
|
|
18
|
+
}
|
|
19
|
+
function sanitizeElement(el2) {
|
|
20
|
+
const tag = el2.tagName.toLowerCase();
|
|
21
|
+
for (const attr of Array.from(el2.attributes)) {
|
|
22
|
+
const name = attr.name.toLowerCase();
|
|
23
|
+
if (name.startsWith("on") || !ALLOWED_ATTRS.has(name)) {
|
|
24
|
+
el2.removeAttribute(attr.name);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if ((name === "href" || name === "src") && !isSafeUrl(attr.value, name, tag)) el2.removeAttribute(attr.name);
|
|
28
|
+
}
|
|
29
|
+
if (tag === "a") {
|
|
30
|
+
const target = el2.getAttribute("target");
|
|
31
|
+
if (target && target !== "_blank" && target !== "_self") el2.removeAttribute("target");
|
|
32
|
+
if (el2.getAttribute("target") === "_blank") el2.setAttribute("rel", "noopener noreferrer");
|
|
33
|
+
}
|
|
34
|
+
if (tag === "button") el2.setAttribute("type", "button");
|
|
35
|
+
if (tag === "img") {
|
|
36
|
+
for (const dim of ["width", "height"]) if (el2.hasAttribute(dim) && !/^\d{1,5}$/.test(el2.getAttribute(dim))) el2.removeAttribute(dim);
|
|
37
|
+
el2.setAttribute("loading", "lazy");
|
|
38
|
+
if (!el2.getAttribute("alt")) el2.setAttribute("alt", "");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function rebuildMedia(el2) {
|
|
42
|
+
const doc = el2.ownerDocument;
|
|
43
|
+
const tag = el2.tagName.toLowerCase();
|
|
44
|
+
const src = el2.getAttribute("src");
|
|
45
|
+
let out;
|
|
46
|
+
if (tag === "iframe") {
|
|
47
|
+
if (!isAllowedEmbedSrc(src)) return null;
|
|
48
|
+
out = doc.createElement("iframe");
|
|
49
|
+
out.setAttribute("src", src);
|
|
50
|
+
out.setAttribute("title", el2.getAttribute("title") || "Embedded video");
|
|
51
|
+
for (const [k, v] of Object.entries(EMBED_IFRAME_ATTRS)) out.setAttribute(k, v);
|
|
52
|
+
} else {
|
|
53
|
+
if (!isSafeMediaUrl(src)) return null;
|
|
54
|
+
out = doc.createElement("video");
|
|
55
|
+
out.setAttribute("src", src);
|
|
56
|
+
const poster = el2.getAttribute("poster");
|
|
57
|
+
if (isSafeMediaUrl(poster)) out.setAttribute("poster", poster);
|
|
58
|
+
for (const [k, v] of Object.entries(VIDEO_ATTRS)) out.setAttribute(k, v);
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
function walk(node) {
|
|
63
|
+
const children = Array.from(node.childNodes);
|
|
64
|
+
for (const child of children) {
|
|
65
|
+
if (child.nodeType === 8) {
|
|
66
|
+
node.removeChild(child);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (child.nodeType !== 1) continue;
|
|
70
|
+
const el2 = child;
|
|
71
|
+
const tag = el2.tagName.toLowerCase();
|
|
72
|
+
if (DROP_TAGS.has(tag)) {
|
|
73
|
+
node.removeChild(el2);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (tag === "iframe" || tag === "video") {
|
|
77
|
+
const media = rebuildMedia(el2);
|
|
78
|
+
if (media) node.replaceChild(media, el2);
|
|
79
|
+
else node.removeChild(el2);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (!ALLOWED_TAGS.has(tag)) {
|
|
83
|
+
while (el2.firstChild) node.insertBefore(el2.firstChild, el2);
|
|
84
|
+
node.removeChild(el2);
|
|
85
|
+
walk(node);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
sanitizeElement(el2);
|
|
89
|
+
walk(el2);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function sanitizeToFragment(html, doc = document) {
|
|
93
|
+
const tpl = doc.createElement("template");
|
|
94
|
+
tpl.innerHTML = html || "";
|
|
95
|
+
walk(tpl.content);
|
|
96
|
+
return tpl.content;
|
|
97
|
+
}
|
|
98
|
+
function sanitizeHtml(html, doc = document) {
|
|
99
|
+
const frag = sanitizeToFragment(html, doc);
|
|
100
|
+
const div = doc.createElement("div");
|
|
101
|
+
div.appendChild(frag);
|
|
102
|
+
return div.innerHTML;
|
|
103
|
+
}
|
|
104
|
+
function setSanitizedHtml(el2, html) {
|
|
105
|
+
el2.textContent = "";
|
|
106
|
+
el2.appendChild(sanitizeToFragment(html, el2.ownerDocument));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/pdf-viewer.ts
|
|
110
|
+
import { FILE_LINK_CLASS, PDF_BLOCK_CLASS, PDF_PAGES_CLASS } from "@guidelytech/shared/runtime";
|
|
111
|
+
function enhancePdfViewers(root, doc = root.ownerDocument) {
|
|
112
|
+
for (const block of Array.from(root.querySelectorAll(`div.${PDF_BLOCK_CLASS}`))) {
|
|
113
|
+
const link = block.querySelector(`a.${FILE_LINK_CLASS}`);
|
|
114
|
+
const strip = block.querySelector(`.${PDF_PAGES_CLASS}`);
|
|
115
|
+
if (!link || !strip || block.hasAttribute("data-g-ready")) continue;
|
|
116
|
+
for (const img of Array.from(strip.querySelectorAll("img:not([src])"))) img.remove();
|
|
117
|
+
const pages = Array.from(strip.querySelectorAll("img"));
|
|
118
|
+
if (!pages.length) {
|
|
119
|
+
strip.remove();
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
block.setAttribute("data-g-ready", "");
|
|
123
|
+
const name = (link.textContent || "").trim() || "PDF";
|
|
124
|
+
block.setAttribute("role", "group");
|
|
125
|
+
block.setAttribute("aria-label", `${name}, ${pages.length} ${pages.length === 1 ? "page" : "pages"}`);
|
|
126
|
+
link.setAttribute("aria-label", `Read ${name} full screen`);
|
|
127
|
+
link.addEventListener("click", (e) => {
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
openReader(doc, block, link, pages, 0);
|
|
130
|
+
});
|
|
131
|
+
const viewport = doc.createElement("div");
|
|
132
|
+
viewport.className = "g-pdf-viewport";
|
|
133
|
+
strip.replaceWith(viewport);
|
|
134
|
+
viewport.appendChild(strip);
|
|
135
|
+
strip.tabIndex = 0;
|
|
136
|
+
strip.setAttribute("aria-label", `${name} pages`);
|
|
137
|
+
const counter = doc.createElement("span");
|
|
138
|
+
counter.className = "g-pdf-count";
|
|
139
|
+
counter.setAttribute("aria-live", "polite");
|
|
140
|
+
const prev = navButton(doc, "prev", "Previous page", "\u2039");
|
|
141
|
+
const next = navButton(doc, "next", "Next page", "\u203A");
|
|
142
|
+
viewport.append(prev, next, counter);
|
|
143
|
+
const stride = () => Math.max(1, pages.length > 1 ? pages[1].offsetLeft - pages[0].offsetLeft : strip.clientWidth);
|
|
144
|
+
const current = () => Math.round(strip.scrollLeft / stride());
|
|
145
|
+
const go = (i) => strip.scrollTo({ left: Math.max(0, Math.min(pages.length - 1, i)) * stride(), behavior: prefersReducedMotion() ? "auto" : "smooth" });
|
|
146
|
+
const update = () => {
|
|
147
|
+
const i = Math.min(pages.length - 1, current());
|
|
148
|
+
counter.textContent = `${i + 1} / ${pages.length}`;
|
|
149
|
+
prev.disabled = i === 0;
|
|
150
|
+
next.disabled = i >= pages.length - 1;
|
|
151
|
+
};
|
|
152
|
+
prev.addEventListener("click", () => go(current() - 1));
|
|
153
|
+
next.addEventListener("click", () => go(current() + 1));
|
|
154
|
+
strip.addEventListener("scroll", update, { passive: true });
|
|
155
|
+
strip.addEventListener("keydown", (e) => {
|
|
156
|
+
if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
go(current() + (e.key === "ArrowRight" ? 1 : -1));
|
|
159
|
+
} else if (e.key === "Enter") openReader(doc, block, link, pages, current());
|
|
160
|
+
});
|
|
161
|
+
pages.forEach((img, i) => img.addEventListener("click", () => openReader(doc, block, link, pages, i)));
|
|
162
|
+
if (pages.length === 1) viewport.classList.add("g-pdf-single");
|
|
163
|
+
update();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function navButton(doc, cls, label, text) {
|
|
167
|
+
const b = doc.createElement("button");
|
|
168
|
+
b.type = "button";
|
|
169
|
+
b.className = `g-pdf-nav g-pdf-${cls}`;
|
|
170
|
+
b.setAttribute("aria-label", label);
|
|
171
|
+
b.textContent = text;
|
|
172
|
+
return b;
|
|
173
|
+
}
|
|
174
|
+
function openReader(doc, block, link, pages, start) {
|
|
175
|
+
const host = block.closest(".g-scope") ?? doc.body;
|
|
176
|
+
const returnFocus = block.getRootNode().activeElement;
|
|
177
|
+
const name = (link.textContent || "").trim() || "PDF";
|
|
178
|
+
const reader = doc.createElement("div");
|
|
179
|
+
reader.className = "g-pdf-reader";
|
|
180
|
+
reader.setAttribute("role", "dialog");
|
|
181
|
+
reader.setAttribute("aria-modal", "true");
|
|
182
|
+
reader.setAttribute("aria-label", name);
|
|
183
|
+
const bar = doc.createElement("div");
|
|
184
|
+
bar.className = "g-pdf-bar";
|
|
185
|
+
const title = doc.createElement("span");
|
|
186
|
+
title.className = "g-pdf-title";
|
|
187
|
+
title.textContent = name;
|
|
188
|
+
const original = doc.createElement("a");
|
|
189
|
+
original.className = "g-btn g-btn-secondary";
|
|
190
|
+
original.href = link.href;
|
|
191
|
+
original.target = "_blank";
|
|
192
|
+
original.rel = "noopener noreferrer";
|
|
193
|
+
original.textContent = "Open PDF \u2197";
|
|
194
|
+
const close = doc.createElement("button");
|
|
195
|
+
close.type = "button";
|
|
196
|
+
close.className = "g-close g-pdf-close";
|
|
197
|
+
close.setAttribute("aria-label", "Close");
|
|
198
|
+
close.textContent = "\xD7";
|
|
199
|
+
bar.append(title, original, close);
|
|
200
|
+
const scroller = doc.createElement("div");
|
|
201
|
+
scroller.className = "g-pdf-scroll";
|
|
202
|
+
scroller.tabIndex = 0;
|
|
203
|
+
for (const page of pages) {
|
|
204
|
+
const img = doc.createElement("img");
|
|
205
|
+
img.src = page.src;
|
|
206
|
+
img.alt = page.alt;
|
|
207
|
+
img.decoding = "async";
|
|
208
|
+
for (const dim of ["width", "height"]) if (page.hasAttribute(dim)) img.setAttribute(dim, page.getAttribute(dim));
|
|
209
|
+
scroller.appendChild(img);
|
|
210
|
+
}
|
|
211
|
+
reader.append(bar, scroller);
|
|
212
|
+
const onKey = (e) => {
|
|
213
|
+
if (e.key === "Escape") {
|
|
214
|
+
e.stopPropagation();
|
|
215
|
+
done();
|
|
216
|
+
} else if (e.key === "Tab") {
|
|
217
|
+
const items = [original, close, scroller];
|
|
218
|
+
const at = items.indexOf(reader.getRootNode().activeElement);
|
|
219
|
+
e.preventDefault();
|
|
220
|
+
items[(at + (e.shiftKey ? items.length - 1 : 1)) % items.length].focus();
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const done = () => {
|
|
224
|
+
reader.remove();
|
|
225
|
+
returnFocus?.focus?.({ preventScroll: true });
|
|
226
|
+
};
|
|
227
|
+
close.addEventListener("click", done);
|
|
228
|
+
reader.addEventListener("keydown", onKey);
|
|
229
|
+
host.appendChild(reader);
|
|
230
|
+
close.focus();
|
|
231
|
+
const target = scroller.children[start];
|
|
232
|
+
if (target && start > 0) {
|
|
233
|
+
const land = () => scroller.scrollTop = target.offsetTop - 12;
|
|
234
|
+
requestAnimationFrame(land);
|
|
235
|
+
if (!target.hasAttribute("height")) for (const img of Array.from(scroller.children).slice(0, start)) img.addEventListener("load", land, { once: true });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/help-view.ts
|
|
240
|
+
import { isArticleListed, matchesHelpQuery, RC_MODULE_IDS, RC_MODULE_LABELS, resourceCenterSections, showMeKeyFromHref, SHOW_ME_HREF_PREFIX } from "@guidelytech/shared/runtime";
|
|
241
|
+
var SHOW_ME_KINDS = /* @__PURE__ */ new Set(["flow", "modal", "tooltip", "announcement"]);
|
|
242
|
+
function startableGuide(guides, keyOrId) {
|
|
243
|
+
if (!keyOrId || !guides) return null;
|
|
244
|
+
return guides.find((g) => (g.key === keyOrId || g.id === keyOrId) && SHOW_ME_KINDS.has(g.kind)) ?? null;
|
|
245
|
+
}
|
|
246
|
+
function resultRow(doc, icon, title, summary, onOpen, showMe) {
|
|
247
|
+
const item = listItem(doc, icon, title, summary);
|
|
248
|
+
item.addEventListener("click", onOpen);
|
|
249
|
+
if (!showMe) return item;
|
|
250
|
+
const row = el(doc, "div", "g-rc-row");
|
|
251
|
+
const b = el(doc, "button", "g-btn g-btn-primary g-rc-showme", "\u25B6 Show me");
|
|
252
|
+
b.type = "button";
|
|
253
|
+
b.setAttribute("aria-label", `Show me: ${title}`);
|
|
254
|
+
b.addEventListener("click", showMe);
|
|
255
|
+
row.append(item, b);
|
|
256
|
+
return row;
|
|
257
|
+
}
|
|
258
|
+
function enhanceShowMe(root, doc, canStart, start) {
|
|
259
|
+
for (const a of Array.from(root.querySelectorAll(`a[href^="${SHOW_ME_HREF_PREFIX}"]`))) {
|
|
260
|
+
const key = showMeKeyFromHref(a.getAttribute("href"));
|
|
261
|
+
const holder = a.closest("p.gd-show-me") ?? a;
|
|
262
|
+
if (!key || !canStart(key)) {
|
|
263
|
+
if (holder !== a) holder.remove();
|
|
264
|
+
else a.replaceWith(doc.createTextNode(a.textContent ?? ""));
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const b = el(doc, "button", "g-btn g-btn-primary g-help-showme", `\u25B6 ${(a.textContent ?? "").trim() || "Show me"}`);
|
|
268
|
+
b.type = "button";
|
|
269
|
+
b.addEventListener("click", () => start(key));
|
|
270
|
+
a.replaceWith(b);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function el(doc, tag, cls, text) {
|
|
274
|
+
const e = doc.createElement(tag);
|
|
275
|
+
if (cls) e.className = cls;
|
|
276
|
+
if (text != null) e.textContent = text;
|
|
277
|
+
return e;
|
|
278
|
+
}
|
|
279
|
+
function listItem(doc, icon, title, summary) {
|
|
280
|
+
const b = el(doc, "button", "g-rc-item");
|
|
281
|
+
b.type = "button";
|
|
282
|
+
const i = el(doc, "span", "g-rc-icon", icon);
|
|
283
|
+
i.setAttribute("aria-hidden", "true");
|
|
284
|
+
const text = el(doc, "span");
|
|
285
|
+
text.appendChild(el(doc, "div", "g-rc-title", title));
|
|
286
|
+
if (summary) text.appendChild(el(doc, "div", "g-rc-sum", summary));
|
|
287
|
+
b.append(i, text);
|
|
288
|
+
return b;
|
|
289
|
+
}
|
|
290
|
+
function createHelpView(options) {
|
|
291
|
+
const { doc } = options;
|
|
292
|
+
let query = "";
|
|
293
|
+
let serverResults = [];
|
|
294
|
+
let searchSeq = 0;
|
|
295
|
+
let openSeq = 0;
|
|
296
|
+
let active = null;
|
|
297
|
+
const setActive = (next) => {
|
|
298
|
+
const was = !!active;
|
|
299
|
+
active = next;
|
|
300
|
+
if (was !== !!next) options.onArticleChange?.(!!next);
|
|
301
|
+
};
|
|
302
|
+
const root = el(doc, "div", "g-help");
|
|
303
|
+
const searchWrap = el(doc, "div", "g-rc-search");
|
|
304
|
+
const input = el(doc, "input", "g-input");
|
|
305
|
+
input.type = "search";
|
|
306
|
+
input.placeholder = "Search help articles\u2026";
|
|
307
|
+
input.setAttribute("aria-label", "Search help articles");
|
|
308
|
+
searchWrap.appendChild(input);
|
|
309
|
+
const body = el(doc, "div", "g-panel-body");
|
|
310
|
+
root.append(searchWrap, body);
|
|
311
|
+
const hasBody = (a) => typeof a.body === "string" && !a.bodyOmitted;
|
|
312
|
+
const canShowMe = (key) => !!options.onShowMe && !!startableGuide(options.guides?.(), key);
|
|
313
|
+
const showMe = (key) => options.onShowMe?.(startableGuide(options.guides?.(), key)?.key ?? key);
|
|
314
|
+
const openArticle = (article) => {
|
|
315
|
+
if (article.externalUrl) {
|
|
316
|
+
window.open(article.externalUrl, "_blank", "noopener,noreferrer");
|
|
317
|
+
if (hasBody(article)) options.onArticleView?.(article);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const seq = ++openSeq;
|
|
321
|
+
if (hasBody(article) || !options.loadArticle) {
|
|
322
|
+
setActive({ article, loading: false });
|
|
323
|
+
if (hasBody(article)) options.onArticleView?.(article);
|
|
324
|
+
return render();
|
|
325
|
+
}
|
|
326
|
+
setActive({ article, loading: true });
|
|
327
|
+
render();
|
|
328
|
+
options.loadArticle(article.id).then((full) => {
|
|
329
|
+
if (seq !== openSeq || !active) return;
|
|
330
|
+
setActive({ article: full ?? { ...article, body: "" }, loading: false });
|
|
331
|
+
if (full) options.onArticleView?.(full);
|
|
332
|
+
render();
|
|
333
|
+
}).catch(() => {
|
|
334
|
+
if (seq !== openSeq || !active) return;
|
|
335
|
+
setActive({ article: { ...article, body: "" }, loading: false });
|
|
336
|
+
render();
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
const renderArticle = ({ article, loading }) => {
|
|
340
|
+
const wrap = el(doc, "div", "g-rc-article");
|
|
341
|
+
const back = el(doc, "button", "g-btn g-btn-link g-rc-back", "\u2190 Back");
|
|
342
|
+
back.type = "button";
|
|
343
|
+
back.addEventListener("click", () => {
|
|
344
|
+
openSeq++;
|
|
345
|
+
setActive(null);
|
|
346
|
+
render();
|
|
347
|
+
});
|
|
348
|
+
const title = el(doc, "h3", "g-title", article.title);
|
|
349
|
+
const content = el(doc, "div", "g-body");
|
|
350
|
+
if (loading) content.appendChild(el(doc, "div", "g-rc-empty", "Loading\u2026"));
|
|
351
|
+
else if (article.body) {
|
|
352
|
+
setSanitizedHtml(content, article.body);
|
|
353
|
+
enhancePdfViewers(content, doc);
|
|
354
|
+
enhanceShowMe(content, doc, canShowMe, showMe);
|
|
355
|
+
} else content.appendChild(el(doc, "div", "g-rc-empty", "This article couldn't be loaded."));
|
|
356
|
+
wrap.append(back, title, content);
|
|
357
|
+
body.appendChild(wrap);
|
|
358
|
+
back.focus?.({ preventScroll: true });
|
|
359
|
+
};
|
|
360
|
+
const section = (label, depth = 0) => {
|
|
361
|
+
const s = body.appendChild(el(doc, "div", "g-rc-section", label));
|
|
362
|
+
if (depth) s.dataset.depth = String(depth);
|
|
363
|
+
return s;
|
|
364
|
+
};
|
|
365
|
+
const articleButton = (a) => {
|
|
366
|
+
const key = a.walkthroughs?.find(canShowMe);
|
|
367
|
+
const summary = a.hasVideo ? a.summary ? `Video \xB7 ${a.summary}` : "Video" : a.summary;
|
|
368
|
+
body.appendChild(resultRow(doc, a.hasVideo ? "\u25B6" : "\u{1F4C4}", a.title, summary, () => openArticle(a), key ? () => showMe(key) : void 0));
|
|
369
|
+
};
|
|
370
|
+
function render() {
|
|
371
|
+
body.textContent = "";
|
|
372
|
+
if (active) return renderArticle(active);
|
|
373
|
+
const data = options.data();
|
|
374
|
+
const member = options.audienceIds?.() ?? [];
|
|
375
|
+
searchWrap.hidden = !!data.modules && !data.modules.includes("search");
|
|
376
|
+
const sections = resourceCenterSections(data.collections, data.articles, member);
|
|
377
|
+
const q = query.trim().toLowerCase();
|
|
378
|
+
if (q) {
|
|
379
|
+
const walkthroughs = (data.recommended ?? []).filter((g) => matchesHelpQuery(g.name, q) && startableGuide(options.guides?.() ?? data.recommended, g.id));
|
|
380
|
+
if (walkthroughs.length) {
|
|
381
|
+
section(`Walkthroughs (${walkthroughs.length})`);
|
|
382
|
+
for (const g of walkthroughs) body.appendChild(resultRow(doc, "\u25B6", g.name, "Show me, step by step", () => options.onStartGuide?.(g.id)));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
body.append(...options.extra?.(q) ?? []);
|
|
386
|
+
if (q) {
|
|
387
|
+
const visible = sections.flatMap((s) => s.articles);
|
|
388
|
+
const local = visible.filter((a) => matchesHelpQuery(`${a.title} ${a.summary}`, q));
|
|
389
|
+
const seen = new Set(local.map((a) => a.id));
|
|
390
|
+
const hidden = new Set(data.articles.map((a) => a.id).filter((id) => !visible.some((v) => v.id === id)));
|
|
391
|
+
const merged = [...local, ...serverResults.filter((a) => !seen.has(a.id) && !hidden.has(a.id) && isArticleListed(data.collections, a, member))];
|
|
392
|
+
section(`Results (${merged.length})`);
|
|
393
|
+
if (!merged.length) body.appendChild(el(doc, "div", "g-rc-empty", "No articles match your search."));
|
|
394
|
+
merged.forEach(articleButton);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (data.suggested?.items.length) {
|
|
398
|
+
section(data.suggested.title);
|
|
399
|
+
const glyph = { guide: "\u25B6", howto: "\u2630", article: "\u{1F4C4}" };
|
|
400
|
+
data.suggested.items.forEach((item) => {
|
|
401
|
+
const b = listItem(doc, glyph[item.kind], item.title, item.summary);
|
|
402
|
+
b.addEventListener("click", item.run);
|
|
403
|
+
body.appendChild(b);
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
const renderers = {
|
|
407
|
+
search: () => {
|
|
408
|
+
},
|
|
409
|
+
announcements: () => {
|
|
410
|
+
if (!data.announcements?.length) return;
|
|
411
|
+
section(RC_MODULE_LABELS.announcements);
|
|
412
|
+
const seen = data.announcementsSeenAt ? Date.parse(data.announcementsSeenAt) : NaN;
|
|
413
|
+
data.announcements.slice(0, 20).forEach((n) => body.appendChild(announcementItem(n, Number.isNaN(seen) || Date.parse(n.publishedAt) > seen)));
|
|
414
|
+
},
|
|
415
|
+
guides: () => {
|
|
416
|
+
if (!data.recommended?.length) return;
|
|
417
|
+
section("Recommended");
|
|
418
|
+
data.recommended.forEach((g) => {
|
|
419
|
+
const b = listItem(doc, "\u25B6", g.name, "Start guide");
|
|
420
|
+
b.addEventListener("click", () => options.onStartGuide?.(g.id));
|
|
421
|
+
body.appendChild(b);
|
|
422
|
+
});
|
|
423
|
+
},
|
|
424
|
+
checklists: () => {
|
|
425
|
+
if (!data.checklists?.length) return;
|
|
426
|
+
section("Checklists");
|
|
427
|
+
data.checklists.forEach((g) => {
|
|
428
|
+
const b = listItem(doc, "\u2611", g.name, "Open checklist");
|
|
429
|
+
b.addEventListener("click", () => options.onOpenChecklist?.(g.id));
|
|
430
|
+
body.appendChild(b);
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
articles: () => {
|
|
434
|
+
for (const s of sections) {
|
|
435
|
+
section(s.collection ? s.path.join(" \u203A ") : "Articles", s.depth);
|
|
436
|
+
s.articles.forEach(articleButton);
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
faqs: () => {
|
|
440
|
+
if (!data.faqs?.length) return;
|
|
441
|
+
section("FAQ");
|
|
442
|
+
data.faqs.forEach((f) => {
|
|
443
|
+
const b = listItem(doc, "?", f.question);
|
|
444
|
+
b.setAttribute("aria-expanded", "false");
|
|
445
|
+
const a = el(doc, "div", "g-faq-a");
|
|
446
|
+
a.id = `g-faq-${f.id}`;
|
|
447
|
+
b.setAttribute("aria-controls", a.id);
|
|
448
|
+
setSanitizedHtml(a, f.answer);
|
|
449
|
+
a.hidden = true;
|
|
450
|
+
b.addEventListener("click", () => {
|
|
451
|
+
a.hidden = !a.hidden;
|
|
452
|
+
b.setAttribute("aria-expanded", String(!a.hidden));
|
|
453
|
+
});
|
|
454
|
+
body.append(b, a);
|
|
455
|
+
});
|
|
456
|
+
},
|
|
457
|
+
links: () => {
|
|
458
|
+
if (!data.links?.length) return;
|
|
459
|
+
section("Links");
|
|
460
|
+
data.links.forEach((l) => {
|
|
461
|
+
const a = el(doc, "a", "g-rc-item");
|
|
462
|
+
a.href = l.url;
|
|
463
|
+
a.target = "_blank";
|
|
464
|
+
a.rel = "noopener noreferrer";
|
|
465
|
+
const i = el(doc, "span", "g-rc-icon", "\u2197");
|
|
466
|
+
i.setAttribute("aria-hidden", "true");
|
|
467
|
+
a.append(i, el(doc, "span", "g-rc-title", l.label));
|
|
468
|
+
a.setAttribute("aria-label", `${l.label} (opens in a new tab)`);
|
|
469
|
+
body.appendChild(a);
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
for (const id of data.modules ?? RC_MODULE_IDS) renderers[id]?.();
|
|
474
|
+
if (!body.childNodes.length) body.appendChild(el(doc, "div", "g-rc-empty", "Nothing here yet."));
|
|
475
|
+
}
|
|
476
|
+
function announcementItem(n, unread) {
|
|
477
|
+
const item = el(doc, "article", `g-rc-news${unread ? " g-rc-news-unread" : ""}`);
|
|
478
|
+
const head = el(doc, "div", "g-rc-news-head");
|
|
479
|
+
const title = el(doc, "h3", "g-rc-news-title", n.title);
|
|
480
|
+
head.appendChild(title);
|
|
481
|
+
if (unread) {
|
|
482
|
+
const dot = el(doc, "span", "g-rc-news-new", "New");
|
|
483
|
+
head.appendChild(dot);
|
|
484
|
+
}
|
|
485
|
+
const date = el(doc, "time", "g-rc-news-date");
|
|
486
|
+
date.dateTime = n.publishedAt;
|
|
487
|
+
try {
|
|
488
|
+
date.textContent = new Date(n.publishedAt).toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
|
|
489
|
+
} catch {
|
|
490
|
+
date.textContent = n.publishedAt.slice(0, 10);
|
|
491
|
+
}
|
|
492
|
+
item.append(head, date);
|
|
493
|
+
if (n.body) {
|
|
494
|
+
const b = el(doc, "div", "g-body g-rc-news-body");
|
|
495
|
+
setSanitizedHtml(b, n.body);
|
|
496
|
+
item.appendChild(b);
|
|
497
|
+
}
|
|
498
|
+
const actions = el(doc, "div", "g-rc-news-actions");
|
|
499
|
+
const guide = n.guideId ? startableGuide(options.guides?.(), n.guideId) : null;
|
|
500
|
+
if (guide) {
|
|
501
|
+
const b = el(doc, "button", "g-btn g-btn-primary", n.linkLabel || "Show me");
|
|
502
|
+
b.type = "button";
|
|
503
|
+
b.addEventListener("click", () => options.onShowMe ? options.onShowMe(guide.key) : options.onStartGuide?.(guide.id));
|
|
504
|
+
actions.appendChild(b);
|
|
505
|
+
}
|
|
506
|
+
if (n.articleId) {
|
|
507
|
+
const listed = options.data().articles.find((a) => a.id === n.articleId);
|
|
508
|
+
if (listed) {
|
|
509
|
+
const b = el(doc, "button", "g-btn g-btn-secondary", guide ? "Read more" : n.linkLabel || "Read more");
|
|
510
|
+
b.type = "button";
|
|
511
|
+
b.addEventListener("click", () => openArticle(listed));
|
|
512
|
+
actions.appendChild(b);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (n.url && /^https?:\/\//i.test(n.url)) {
|
|
516
|
+
const a = el(doc, "a", "g-btn g-btn-link", !guide && !n.articleId && n.linkLabel ? n.linkLabel : "Learn more");
|
|
517
|
+
a.href = n.url;
|
|
518
|
+
a.target = "_blank";
|
|
519
|
+
a.rel = "noopener noreferrer";
|
|
520
|
+
actions.appendChild(a);
|
|
521
|
+
}
|
|
522
|
+
if (actions.childNodes.length) item.appendChild(actions);
|
|
523
|
+
return item;
|
|
524
|
+
}
|
|
525
|
+
let debounce = null;
|
|
526
|
+
const onInput = () => {
|
|
527
|
+
query = input.value;
|
|
528
|
+
openSeq++;
|
|
529
|
+
setActive(null);
|
|
530
|
+
render();
|
|
531
|
+
if (debounce) clearTimeout(debounce);
|
|
532
|
+
if (!options.search || !query.trim()) {
|
|
533
|
+
serverResults = [];
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const seq = ++searchSeq;
|
|
537
|
+
debounce = setTimeout(() => {
|
|
538
|
+
options.search?.(query.trim()).then((results) => {
|
|
539
|
+
if (seq !== searchSeq) return;
|
|
540
|
+
serverResults = Array.isArray(results) ? results : [];
|
|
541
|
+
render();
|
|
542
|
+
}).catch(() => {
|
|
543
|
+
});
|
|
544
|
+
}, 250);
|
|
545
|
+
};
|
|
546
|
+
input.addEventListener("input", onInput);
|
|
547
|
+
return {
|
|
548
|
+
el: root,
|
|
549
|
+
render,
|
|
550
|
+
reset() {
|
|
551
|
+
openSeq++;
|
|
552
|
+
setActive(null);
|
|
553
|
+
query = "";
|
|
554
|
+
input.value = "";
|
|
555
|
+
serverResults = [];
|
|
556
|
+
},
|
|
557
|
+
openArticle(id) {
|
|
558
|
+
const listed = options.data().articles.find((a) => a.id === id) ?? { id, slug: id, title: "Article", summary: "", updatedAt: "", bodyOmitted: true };
|
|
559
|
+
openArticle(listed);
|
|
560
|
+
},
|
|
561
|
+
isArticleOpen: () => !!active,
|
|
562
|
+
focusSearch: () => input.focus?.({ preventScroll: true }),
|
|
563
|
+
setQuery(q) {
|
|
564
|
+
input.value = q;
|
|
565
|
+
onInput();
|
|
566
|
+
},
|
|
567
|
+
destroy() {
|
|
568
|
+
if (debounce) clearTimeout(debounce);
|
|
569
|
+
input.removeEventListener("input", onInput);
|
|
570
|
+
root.remove();
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export {
|
|
576
|
+
sanitizeToFragment,
|
|
577
|
+
sanitizeHtml,
|
|
578
|
+
setSanitizedHtml,
|
|
579
|
+
enhancePdfViewers,
|
|
580
|
+
startableGuide,
|
|
581
|
+
resultRow,
|
|
582
|
+
el,
|
|
583
|
+
createHelpView
|
|
584
|
+
};
|
|
585
|
+
//# sourceMappingURL=chunk-H3CROHPR.js.map
|