@cfbender/cesium 0.3.5
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/ARCHITECTURE.md +304 -0
- package/CHANGELOG.md +335 -0
- package/LICENSE +21 -0
- package/README.md +479 -0
- package/agents/cesium.md +39 -0
- package/assets/styleguide.html +857 -0
- package/package.json +61 -0
- package/src/cli/commands/ls.ts +186 -0
- package/src/cli/commands/open.ts +208 -0
- package/src/cli/commands/prune.ts +348 -0
- package/src/cli/commands/restart.ts +38 -0
- package/src/cli/commands/serve.ts +214 -0
- package/src/cli/commands/stop.ts +130 -0
- package/src/cli/commands/theme.ts +333 -0
- package/src/cli/index.ts +78 -0
- package/src/config.ts +94 -0
- package/src/index.ts +35 -0
- package/src/prompt/system-fragment.md +97 -0
- package/src/render/client-js.ts +316 -0
- package/src/render/controls.ts +302 -0
- package/src/render/critique.ts +360 -0
- package/src/render/extract.ts +83 -0
- package/src/render/scrub.ts +141 -0
- package/src/render/theme.ts +712 -0
- package/src/render/validate.ts +524 -0
- package/src/render/wrap.ts +165 -0
- package/src/server/api.ts +166 -0
- package/src/server/http.ts +195 -0
- package/src/server/lifecycle.ts +331 -0
- package/src/server/stop.ts +124 -0
- package/src/storage/index-cache.ts +71 -0
- package/src/storage/index-gen.ts +447 -0
- package/src/storage/lock.ts +108 -0
- package/src/storage/mutate.ts +396 -0
- package/src/storage/paths.ts +159 -0
- package/src/storage/project-summaries.ts +19 -0
- package/src/storage/theme-write.ts +19 -0
- package/src/storage/write.ts +75 -0
- package/src/tools/ask.ts +353 -0
- package/src/tools/critique.ts +66 -0
- package/src/tools/publish.ts +404 -0
- package/src/tools/stop.ts +53 -0
- package/src/tools/styleguide.ts +23 -0
- package/src/tools/wait.ts +192 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Cesium — beautiful HTML artifacts
|
|
2
|
+
|
|
3
|
+
You have access to six tools:
|
|
4
|
+
|
|
5
|
+
- `cesium_publish` — write a substantive response as a self-contained HTML document
|
|
6
|
+
- `cesium_ask` — publish an interactive Q&A artifact; returns `{ id, httpUrl, ... }`
|
|
7
|
+
- `cesium_wait` — block until the user completes a `cesium_ask` artifact (polls disk)
|
|
8
|
+
- `cesium_styleguide` — fetch the full HTML design system reference (call this before writing anything complex)
|
|
9
|
+
- `cesium_critique` — analyze a draft body for design-system adherence; returns a 0-100 score and findings
|
|
10
|
+
- `cesium_stop` — stop the running cesium HTTP server
|
|
11
|
+
|
|
12
|
+
## When to publish (vs. reply in terminal)
|
|
13
|
+
|
|
14
|
+
Publish when:
|
|
15
|
+
|
|
16
|
+
- Your response would be ≥ 400 words
|
|
17
|
+
- It contains a comparison, decision matrix, or multi-section plan/PRD/RFC
|
|
18
|
+
- It is a code review with more than 3 findings
|
|
19
|
+
- It is a design proposal, audit, post-mortem, or explainer
|
|
20
|
+
- The user is likely to re-read, share, or come back to it
|
|
21
|
+
|
|
22
|
+
Stay in terminal for:
|
|
23
|
+
|
|
24
|
+
- Short factual answers
|
|
25
|
+
- Status updates ("done", "running tests", "fixed")
|
|
26
|
+
- Mid-tool-call chatter
|
|
27
|
+
- Single-paragraph replies
|
|
28
|
+
- Acknowledgements
|
|
29
|
+
|
|
30
|
+
User overrides:
|
|
31
|
+
|
|
32
|
+
- "/cesium", "publish this", "make me an HTML report" → publish
|
|
33
|
+
- "in terminal", "just tell me", "don't make a doc" → don't publish
|
|
34
|
+
|
|
35
|
+
When uncertain: publish AND emit a 2-3 line terminal summary pointing at the doc. Cheap to over-publish, expensive to under-publish.
|
|
36
|
+
|
|
37
|
+
## How to write the body
|
|
38
|
+
|
|
39
|
+
The `html` argument is body-only (no `<!doctype>`, `<html>`, `<head>`, `<body>` wrappers — the plugin adds them).
|
|
40
|
+
|
|
41
|
+
Use these classes (full reference via `cesium_styleguide`):
|
|
42
|
+
|
|
43
|
+
- `.eyebrow` `.h-display` `.h-section` `.section-num`
|
|
44
|
+
- `.card` `.tldr` `.callout` (`.note`/`.warn`/`.risk`)
|
|
45
|
+
- `.code` (with `.kw` `.str` `.cm` `.fn` highlights)
|
|
46
|
+
- `.timeline` `.diagram` `.compare-table` `.risk-table`
|
|
47
|
+
- `.kbd` `.pill` `.tag`
|
|
48
|
+
|
|
49
|
+
Inline `style="..."` and inline `<svg>` are encouraged for bespoke diagrams. NEVER reference external resources (no `<script src>`, no remote fonts, no CDN images).
|
|
50
|
+
|
|
51
|
+
## Tone
|
|
52
|
+
|
|
53
|
+
Warm, considered, not flashy. Match the aesthetic of a thoughtful design document, not marketing material.
|
|
54
|
+
|
|
55
|
+
## Self-check before publishing
|
|
56
|
+
|
|
57
|
+
For substantial artifacts (plans, reviews, comparisons, explainers > 500 words),
|
|
58
|
+
call `cesium_critique` with your draft body BEFORE calling `cesium_publish`. Act
|
|
59
|
+
on warn-level findings; consider suggest-level. info-level is FYI.
|
|
60
|
+
|
|
61
|
+
If critique reports score < 70, revise the body before publishing.
|
|
62
|
+
|
|
63
|
+
## After publishing
|
|
64
|
+
|
|
65
|
+
The tool returns URLs (file://, http://). Print a short 2-line terminal summary like:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Cesium · <Title> (<kind>)
|
|
69
|
+
http://localhost:3030/projects/.../...
|
|
70
|
+
file:///.../...html
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Do not paste the full document content into the terminal after publishing.
|
|
74
|
+
|
|
75
|
+
## Stopping the server
|
|
76
|
+
|
|
77
|
+
If the user asks to stop, restart, or recycle the cesium server (e.g. after a
|
|
78
|
+
config change), call `cesium_stop`. The next `cesium_publish` will lazy-start
|
|
79
|
+
a fresh server with the latest config.
|
|
80
|
+
|
|
81
|
+
## Interactive Q&A: cesium_ask + cesium_wait
|
|
82
|
+
|
|
83
|
+
When you need structured user input before producing a final artifact (design tradeoffs,
|
|
84
|
+
plan branches, confirmation gates), publish an interactive artifact:
|
|
85
|
+
|
|
86
|
+
1. `cesium_ask({ title, body, questions: [...] })` → returns `{ id, httpUrl, ... }`
|
|
87
|
+
2. Print the terminalSummary so the user knows where to click.
|
|
88
|
+
3. `cesium_wait({ id })` → blocks until user finishes (or 10-min timeout).
|
|
89
|
+
4. Decide next step from `result.answers` — typically `cesium_publish` with the chosen path.
|
|
90
|
+
|
|
91
|
+
Question types: pick_one, pick_many, confirm, ask_text, slider, react. The artifact
|
|
92
|
+
is a permanent record of the conversation; once answered, controls freeze into a static
|
|
93
|
+
markup that captures the user's decisions. Set `optional: true` on an `ask_text` question
|
|
94
|
+
to add a Skip button (useful for "anything else?"-type follow-ups).
|
|
95
|
+
|
|
96
|
+
Don't use cesium_ask for trivial yes/no questions you can ask in the terminal. Use it
|
|
97
|
+
when the question deserves to live on disk as a decision record.
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// Inline client JS bundle for interactive artifacts.
|
|
2
|
+
// This script is embedded in artifacts with interactive.status === "open".
|
|
3
|
+
// It POSTs answers to /api/sessions/:id/answers/:qid and handles UI state.
|
|
4
|
+
//
|
|
5
|
+
// Server response shape (Phase C will implement):
|
|
6
|
+
// { ok: boolean, status: "open" | "complete" | "expired" | "cancelled", remaining: string[], replacementHtml: string }
|
|
7
|
+
|
|
8
|
+
/** Returns the standalone JS string to embed in interactive artifacts. */
|
|
9
|
+
export function getClientJs(): string {
|
|
10
|
+
return `(function cesiumClient() {
|
|
11
|
+
"use strict";
|
|
12
|
+
|
|
13
|
+
// ─── API base URL derived from window.location.pathname ────────────────────
|
|
14
|
+
// Artifacts are served at /projects/<projectSlug>/artifacts/<filename>.html
|
|
15
|
+
// If not served via cesium HTTP server (e.g. file://), apiBase will be null.
|
|
16
|
+
var m = window.location.pathname.match(/^\\/projects\\/([^\\/]+)\\/artifacts\\/([^\\/]+)$/);
|
|
17
|
+
var apiBase = m ? "/api/sessions/" + m[1] + "/" + m[2] : null;
|
|
18
|
+
|
|
19
|
+
// ─── File:// / offline banner ───────────────────────────────────────────────
|
|
20
|
+
if (!apiBase) {
|
|
21
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
22
|
+
if (document.querySelector(".cs-banner-offline")) return;
|
|
23
|
+
var banner = document.createElement("div");
|
|
24
|
+
banner.className = "cs-banner cs-banner-offline";
|
|
25
|
+
banner.textContent =
|
|
26
|
+
"Interactive controls require viewing this artifact via the cesium HTTP server. " +
|
|
27
|
+
"Run cesium open or visit localhost:3030";
|
|
28
|
+
document.body.insertBefore(banner, document.body.firstChild);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─── Session-ended banner ───────────────────────────────────────────────────
|
|
33
|
+
function showSessionEndedBanner() {
|
|
34
|
+
if (document.querySelector(".cs-banner-ended")) return;
|
|
35
|
+
var banner = document.createElement("div");
|
|
36
|
+
banner.className = "cs-banner cs-banner-ended";
|
|
37
|
+
banner.textContent = "Session ended — answers can no longer be submitted.";
|
|
38
|
+
document.body.insertBefore(banner, document.body.firstChild);
|
|
39
|
+
// Disable all interactive controls
|
|
40
|
+
var disabled = document.querySelectorAll(
|
|
41
|
+
".cs-submit, .cs-skip, .cs-pick, .cs-confirm, .cs-react"
|
|
42
|
+
);
|
|
43
|
+
for (var i = 0; i < disabled.length; i++) {
|
|
44
|
+
var el = disabled[i];
|
|
45
|
+
if (el instanceof HTMLButtonElement || el instanceof HTMLInputElement) {
|
|
46
|
+
el.disabled = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ─── POST answer ────────────────────────────────────────────────────────────
|
|
52
|
+
function postAnswer(qid, value) {
|
|
53
|
+
if (!apiBase) {
|
|
54
|
+
return Promise.reject(new Error("not served via cesium HTTP server"));
|
|
55
|
+
}
|
|
56
|
+
return fetch(apiBase + "/answers/" + qid, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify({ value: value }),
|
|
60
|
+
}).then(function (r) {
|
|
61
|
+
if (r.status === 410) {
|
|
62
|
+
showSessionEndedBanner();
|
|
63
|
+
throw new Error("session ended");
|
|
64
|
+
}
|
|
65
|
+
if (!r.ok) throw new Error("HTTP " + r.status);
|
|
66
|
+
return r.json();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ─── Section replacement ────────────────────────────────────────────────────
|
|
71
|
+
function replaceSection(qid, replacementHtml) {
|
|
72
|
+
var section = document.querySelector(
|
|
73
|
+
"section[data-question-id=\\"" + qid + "\\"]"
|
|
74
|
+
);
|
|
75
|
+
if (!section) return;
|
|
76
|
+
var tmp = document.createElement("div");
|
|
77
|
+
tmp.innerHTML = replacementHtml;
|
|
78
|
+
var newSection = tmp.firstElementChild;
|
|
79
|
+
if (newSection && section.parentNode) {
|
|
80
|
+
section.parentNode.replaceChild(newSection, section);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── Pending / error state ──────────────────────────────────────────────────
|
|
85
|
+
function setPending(section, pending) {
|
|
86
|
+
if (pending) {
|
|
87
|
+
section.dataset["pending"] = "true";
|
|
88
|
+
section.classList.add("cs-saving");
|
|
89
|
+
var btns = section.querySelectorAll("button, input");
|
|
90
|
+
for (var i = 0; i < btns.length; i++) {
|
|
91
|
+
var b = btns[i];
|
|
92
|
+
if (b instanceof HTMLButtonElement || b instanceof HTMLInputElement) {
|
|
93
|
+
b.disabled = true;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
delete section.dataset["pending"];
|
|
98
|
+
section.classList.remove("cs-saving");
|
|
99
|
+
var btns2 = section.querySelectorAll("button, input");
|
|
100
|
+
for (var i2 = 0; i2 < btns2.length; i2++) {
|
|
101
|
+
var b2 = btns2[i2];
|
|
102
|
+
if (b2 instanceof HTMLButtonElement || b2 instanceof HTMLInputElement) {
|
|
103
|
+
b2.disabled = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function showError(section, message) {
|
|
110
|
+
var existing = section.querySelector(".cs-error");
|
|
111
|
+
if (existing) existing.remove();
|
|
112
|
+
var errEl = document.createElement("p");
|
|
113
|
+
errEl.className = "cs-error";
|
|
114
|
+
errEl.setAttribute("role", "alert");
|
|
115
|
+
errEl.textContent = "Failed to save: " + message;
|
|
116
|
+
section.appendChild(errEl);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function clearError(section) {
|
|
120
|
+
var existing = section.querySelector(".cs-error");
|
|
121
|
+
if (existing) existing.remove();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ─── Submit helper ──────────────────────────────────────────────────────────
|
|
125
|
+
function submitAnswer(section, qid, value) {
|
|
126
|
+
clearError(section);
|
|
127
|
+
setPending(section, true);
|
|
128
|
+
postAnswer(qid, value)
|
|
129
|
+
.then(function (resp) {
|
|
130
|
+
if (resp && resp.replacementHtml) {
|
|
131
|
+
replaceSection(qid, resp.replacementHtml);
|
|
132
|
+
} else {
|
|
133
|
+
setPending(section, false);
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
.catch(function (err) {
|
|
137
|
+
setPending(section, false);
|
|
138
|
+
showError(section, err instanceof Error ? err.message : String(err));
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ─── pick_one wiring ─────────────────────────────────────────────────────────
|
|
143
|
+
function wirePickOne(section) {
|
|
144
|
+
var qid = section.dataset["questionId"] || "";
|
|
145
|
+
var btns = section.querySelectorAll("button.cs-pick");
|
|
146
|
+
for (var i = 0; i < btns.length; i++) {
|
|
147
|
+
(function (btn) {
|
|
148
|
+
btn.addEventListener("click", function () {
|
|
149
|
+
var dataValue = btn.dataset["value"] || "";
|
|
150
|
+
submitAnswer(section, qid, { type: "pick_one", selected: dataValue });
|
|
151
|
+
});
|
|
152
|
+
})(btns[i]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ─── pick_many wiring ────────────────────────────────────────────────────────
|
|
157
|
+
function wirePickMany(section) {
|
|
158
|
+
var qid = section.dataset["questionId"] || "";
|
|
159
|
+
var submitBtn = section.querySelector("button.cs-submit");
|
|
160
|
+
var minAttr = section.dataset["min"];
|
|
161
|
+
var maxAttr = section.dataset["max"];
|
|
162
|
+
var min = minAttr ? parseInt(minAttr, 10) : 1;
|
|
163
|
+
var max = maxAttr ? parseInt(maxAttr, 10) : Infinity;
|
|
164
|
+
|
|
165
|
+
function updateSubmitState() {
|
|
166
|
+
var checked = section.querySelectorAll("input[type=checkbox]:checked");
|
|
167
|
+
var count = checked.length;
|
|
168
|
+
if (submitBtn instanceof HTMLButtonElement) {
|
|
169
|
+
submitBtn.disabled = count < min || count > max;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
var checkboxes = section.querySelectorAll("input[type=checkbox]");
|
|
174
|
+
for (var i = 0; i < checkboxes.length; i++) {
|
|
175
|
+
checkboxes[i].addEventListener("change", updateSubmitState);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (submitBtn) {
|
|
179
|
+
submitBtn.addEventListener("click", function () {
|
|
180
|
+
var checked = section.querySelectorAll("input[type=checkbox]:checked");
|
|
181
|
+
var selected = [];
|
|
182
|
+
for (var i2 = 0; i2 < checked.length; i2++) {
|
|
183
|
+
var cb = checked[i2];
|
|
184
|
+
if (cb instanceof HTMLInputElement) {
|
|
185
|
+
selected.push(cb.dataset["value"] || "");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
submitAnswer(section, qid, { type: "pick_many", selected: selected });
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ─── confirm wiring ──────────────────────────────────────────────────────────
|
|
194
|
+
function wireConfirm(section) {
|
|
195
|
+
var qid = section.dataset["questionId"] || "";
|
|
196
|
+
var btns = section.querySelectorAll("button.cs-confirm");
|
|
197
|
+
for (var i = 0; i < btns.length; i++) {
|
|
198
|
+
(function (btn) {
|
|
199
|
+
btn.addEventListener("click", function () {
|
|
200
|
+
var choice = btn.dataset["value"] || "";
|
|
201
|
+
submitAnswer(section, qid, { type: "confirm", choice: choice });
|
|
202
|
+
});
|
|
203
|
+
})(btns[i]);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ─── ask_text wiring ─────────────────────────────────────────────────────────
|
|
208
|
+
function wireAskText(section) {
|
|
209
|
+
var qid = section.dataset["questionId"] || "";
|
|
210
|
+
var input = section.querySelector("input.cs-text, textarea.cs-text");
|
|
211
|
+
var submitBtn = section.querySelector("button.cs-submit");
|
|
212
|
+
var skipBtn = section.querySelector("button.cs-skip");
|
|
213
|
+
|
|
214
|
+
function updateSubmitState() {
|
|
215
|
+
if (submitBtn instanceof HTMLButtonElement && input) {
|
|
216
|
+
var val = input instanceof HTMLInputElement
|
|
217
|
+
? input.value
|
|
218
|
+
: input instanceof HTMLTextAreaElement
|
|
219
|
+
? input.value
|
|
220
|
+
: "";
|
|
221
|
+
submitBtn.disabled = val.trim() === "";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (input) {
|
|
226
|
+
input.addEventListener("input", updateSubmitState);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (submitBtn) {
|
|
230
|
+
submitBtn.addEventListener("click", function () {
|
|
231
|
+
var text = "";
|
|
232
|
+
if (input instanceof HTMLInputElement || input instanceof HTMLTextAreaElement) {
|
|
233
|
+
text = input.value;
|
|
234
|
+
}
|
|
235
|
+
submitAnswer(section, qid, { type: "ask_text", text: text });
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (skipBtn) {
|
|
240
|
+
skipBtn.addEventListener("click", function () {
|
|
241
|
+
submitAnswer(section, qid, { type: "ask_text", text: "" });
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ─── slider wiring ───────────────────────────────────────────────────────────
|
|
247
|
+
function wireSlider(section) {
|
|
248
|
+
var qid = section.dataset["questionId"] || "";
|
|
249
|
+
var sliderInput = section.querySelector("input.cs-slider");
|
|
250
|
+
var outputEl = section.querySelector("output.cs-slider-out");
|
|
251
|
+
var submitBtn = section.querySelector("button.cs-submit");
|
|
252
|
+
|
|
253
|
+
if (sliderInput) {
|
|
254
|
+
sliderInput.addEventListener("input", function () {
|
|
255
|
+
if (outputEl && sliderInput instanceof HTMLInputElement) {
|
|
256
|
+
outputEl.textContent = sliderInput.value;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (submitBtn) {
|
|
262
|
+
submitBtn.addEventListener("click", function () {
|
|
263
|
+
var value = sliderInput instanceof HTMLInputElement
|
|
264
|
+
? Number(sliderInput.value)
|
|
265
|
+
: 0;
|
|
266
|
+
submitAnswer(section, qid, { type: "slider", value: value });
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ─── react wiring ────────────────────────────────────────────────────────────
|
|
272
|
+
function wireReact(section) {
|
|
273
|
+
var qid = section.dataset["questionId"] || "";
|
|
274
|
+
var btns = section.querySelectorAll("button.cs-react");
|
|
275
|
+
var commentArea = section.querySelector("textarea.cs-react-comment");
|
|
276
|
+
|
|
277
|
+
for (var i = 0; i < btns.length; i++) {
|
|
278
|
+
(function (btn) {
|
|
279
|
+
btn.addEventListener("click", function () {
|
|
280
|
+
var decision = btn.dataset["value"] || "";
|
|
281
|
+
var comment = commentArea instanceof HTMLTextAreaElement && commentArea.value !== ""
|
|
282
|
+
? commentArea.value
|
|
283
|
+
: undefined;
|
|
284
|
+
var value = comment !== undefined
|
|
285
|
+
? { type: "react", decision: decision, comment: comment }
|
|
286
|
+
: { type: "react", decision: decision };
|
|
287
|
+
submitAnswer(section, qid, value);
|
|
288
|
+
});
|
|
289
|
+
})(btns[i]);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ─── Wire all sections on DOMContentLoaded ───────────────────────────────────
|
|
294
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
295
|
+
var sections = document.querySelectorAll("section[data-question-id]");
|
|
296
|
+
for (var i = 0; i < sections.length; i++) {
|
|
297
|
+
var section = sections[i];
|
|
298
|
+
if (!(section instanceof HTMLElement)) continue;
|
|
299
|
+
var cls = section.className || "";
|
|
300
|
+
if (cls.indexOf("cs-control-pick_one") !== -1) {
|
|
301
|
+
wirePickOne(section);
|
|
302
|
+
} else if (cls.indexOf("cs-control-pick_many") !== -1) {
|
|
303
|
+
wirePickMany(section);
|
|
304
|
+
} else if (cls.indexOf("cs-control-confirm") !== -1) {
|
|
305
|
+
wireConfirm(section);
|
|
306
|
+
} else if (cls.indexOf("cs-control-ask_text") !== -1) {
|
|
307
|
+
wireAskText(section);
|
|
308
|
+
} else if (cls.indexOf("cs-control-slider") !== -1) {
|
|
309
|
+
wireSlider(section);
|
|
310
|
+
} else if (cls.indexOf("cs-control-react") !== -1) {
|
|
311
|
+
wireReact(section);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
})();`;
|
|
316
|
+
}
|