PluginProbe
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor / 2.0.7
Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor v2.0.7
2.0.13 2.0.12 2.0.11 2.0.10 2.0.9 trunk 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8
blockenberg / blocks / decision-tree / frontend.js

frontend.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/decision-tree/frontend.js

312 lines 12.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 function typoCssVarsForEl(typo, prefix, el) {
5 if (!typo || typeof typo !== 'object') return;
6 var m = { family:'font-family', weight:'font-weight', transform:'text-transform', style:'font-style', decoration:'text-decoration',
7 sizeDesktop:'font-size-d', sizeTablet:'font-size-t', sizeMobile:'font-size-m',
8 lineHeightDesktop:'line-height-d', lineHeightTablet:'line-height-t', lineHeightMobile:'line-height-m',
9 letterSpacingDesktop:'letter-spacing-d', letterSpacingTablet:'letter-spacing-t', letterSpacingMobile:'letter-spacing-m',
10 wordSpacingDesktop:'word-spacing-d', wordSpacingTablet:'word-spacing-t', wordSpacingMobile:'word-spacing-m' };
11 Object.keys(m).forEach(function (k) {
12 if (typo[k] !== undefined && typo[k] !== '') {
13 var v = typo[k], u = typo[k + 'Unit'] || '';
14 if (/Desktop|Tablet|Mobile/.test(k) && typeof v === 'number') v = v + (u || 'px');
15 el.style.setProperty(prefix + m[k], '' + v);
16 }
17 });
18 }
19
20 function mk(tag, cls, styles) {
21 var d = document.createElement(tag);
22 if (cls) d.className = cls;
23 if (styles) Object.keys(styles).forEach(function (k) { d.style[k] = styles[k]; });
24 return d;
25 }
26 function tx(tag, cls, text, styles) {
27 var d = mk(tag, cls, styles);
28 d.textContent = text;
29 return d;
30 }
31 function ap(p) {
32 Array.prototype.slice.call(arguments, 1).forEach(function (c) { if (c) p.appendChild(c); });
33 return p;
34 }
35
36 function nodeById(nodes, id) {
37 return nodes.filter(function (n) { return n.id === id; })[0] || null;
38 }
39
40 // Count max depth from a node
41 function maxDepth(nodes, id, visited) {
42 visited = visited || {};
43 if (visited[id]) return 0;
44 visited[id] = true;
45 var node = nodeById(nodes, id);
46 if (!node || node.type === 'result') return 0;
47 return 1 + Math.max(maxDepth(nodes, node.yesId, visited), maxDepth(nodes, node.noId, visited));
48 }
49
50 function buildBlock(appEl) {
51 if (appEl.dataset.rendered) return;
52 appEl.dataset.rendered = '1';
53 var a;
54 try { a = JSON.parse(appEl.dataset.opts || '{}'); } catch (e) { a = {}; }
55
56 var nodes = a.nodes || [];
57 var rootId = a.rootId || (nodes[0] && nodes[0].id) || '';
58 var cardRadius = (a.cardRadius || 12) + 'px';
59 var borderRadius= (a.borderRadius || 16) + 'px';
60 var fs = (a.fontSize || 15) + 'px';
61 var qs = (a.questionSize || 18) + 'px';
62 var totalDepth = maxDepth(nodes, rootId, {});
63
64 // State
65 var history = []; // array of node ids
66 var currentId = rootId;
67
68 // ── Outer wrapper ────────────────────────────────────────────
69 var wrap = mk('div', 'bkbg-dt-wrap', {
70 background: a.bgColor || '#ffffff',
71 borderRadius: borderRadius,
72 paddingTop: (a.paddingTop || 48) + 'px',
73 paddingBottom:(a.paddingBottom || 48) + 'px',
74 paddingLeft: '32px',
75 paddingRight: '32px',
76 fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
77 });
78
79 /* Typography CSS vars */
80 wrap.style.setProperty('--bkbg-dtr-ttl-fs', (a.titleSize || 24) + 'px');
81 wrap.style.setProperty('--bkbg-dtr-sub-fs', (a.subtitleFontSize || 16) + 'px');
82 if (a.typoTitle) typoCssVarsForEl(a.typoTitle, '--bkbg-dtr-ttl-', wrap);
83 if (a.typoSubtitle) typoCssVarsForEl(a.typoSubtitle, '--bkbg-dtr-sub-', wrap);
84
85 // Title
86 if (a.showTitle !== false && a.title) {
87 ap(wrap, tx('h3', 'bkbg-dt-title', a.title, {
88 color: a.titleColor || '#0f172a',
89 margin: '0 0 8px', textAlign: 'center'
90 }));
91 }
92 if (a.showSubtitle !== false && a.subtitle) {
93 ap(wrap, tx('p', 'bkbg-dt-subtitle', a.subtitle, {
94 color: a.subtitleColor || '#64748b',
95 textAlign: 'center', margin: '0 0 28px'
96 }));
97 }
98
99 // Progress bar
100 var progressWrap = null, progressFill = null;
101 if (a.showProgress !== false && totalDepth > 0) {
102 progressWrap = mk('div', 'bkbg-dt-progress-bar');
103 progressFill = mk('div', 'bkbg-dt-progress-fill', { background: a.yesBg || '#22c55e', width: '0%' });
104 progressWrap.appendChild(progressFill);
105 wrap.appendChild(progressWrap);
106 }
107
108 // Breadcrumb
109 var breadcrumbEl = null;
110 if (a.showBreadcrumb !== false) {
111 breadcrumbEl = mk('div', 'bkbg-dt-breadcrumb', { color: a.breadcrumbColor || '#94a3b8', marginBottom: '16px' });
112 wrap.appendChild(breadcrumbEl);
113 }
114
115 // Card container
116 var cardContainer = mk('div', 'bkbg-dt-card-container');
117 wrap.appendChild(cardContainer);
118
119 function updateProgress() {
120 if (!progressFill || totalDepth === 0) return;
121 var pct = Math.min(100, Math.round((history.length / (totalDepth + 1)) * 100));
122 progressFill.style.width = pct + '%';
123 }
124
125 function updateBreadcrumb() {
126 if (!breadcrumbEl) return;
127 breadcrumbEl.innerHTML = '';
128 var crumbs = [rootId].concat(history);
129 crumbs.forEach(function (id, i) {
130 var node = nodeById(nodes, id);
131 if (!node) return;
132 if (i > 0) ap(breadcrumbEl, tx('span', 'bkbg-dt-breadcrumb-sep', ''));
133 var label = node.type === 'result' ? '🎯' : ('Q' + (i + 1));
134 ap(breadcrumbEl, tx('span', '', label, { fontWeight: i === crumbs.length - 1 ? '700' : '400', color: i === crumbs.length - 1 ? (a.questionColor || '#0f172a') : 'inherit' }));
135 });
136 }
137
138 function navigateTo(id, direction) {
139 var card = cardContainer.querySelector('.bkbg-dt-question-card, .bkbg-dt-result-card');
140 if (card && direction !== 'back') {
141 card.style.opacity = '0';
142 card.style.transform = 'translateX(' + (direction === 'yes' ? '-12px' : '12px') + ')';
143 card.style.transition = 'opacity .18s ease, transform .18s ease';
144 }
145 setTimeout(function () {
146 currentId = id;
147 renderCurrent();
148 updateBreadcrumb();
149 updateProgress();
150 }, card && direction !== 'back' ? 180 : 0);
151 }
152
153 function renderCurrent() {
154 cardContainer.innerHTML = '';
155 var node = nodeById(nodes, currentId);
156 if (!node) {
157 ap(cardContainer, tx('p', '', 'Node not found: ' + currentId, { color: 'red' }));
158 return;
159 }
160
161 if (node.type === 'result') {
162 renderResult(node);
163 } else {
164 renderQuestion(node);
165 }
166 }
167
168 function renderQuestion(node) {
169 var card = mk('div', 'bkbg-dt-question-card', {
170 background: a.cardBg || '#f8fafc',
171 border: '1px solid ' + (a.cardBorder || '#e2e8f0'),
172 borderRadius: cardRadius,
173 padding: '28px 32px',
174 });
175
176 ap(card, tx('p', '', node.text, {
177 fontSize: qs, fontWeight: '700',
178 color: a.questionColor || '#0f172a',
179 margin: '0 0 24px', lineHeight: '1.4'
180 }));
181
182 // Buttons
183 var btnRow = mk('div', 'bkbg-dt-btn-row');
184
185 var yesBtn = mk('button', 'bkbg-dt-btn', {
186 background: a.yesBg || '#22c55e',
187 color: a.yesText || '#ffffff',
188 fontSize: fs
189 });
190 var yesIconSpan = mk('span', 'bkbg-dt-btn-icon');
191 var yesIconType = a.yesIconType || 'custom-char';
192 if (yesIconType !== 'custom-char' && window.bkbgIconPicker) {
193 yesIconSpan.appendChild(window.bkbgIconPicker.buildFrontendIcon(yesIconType, a.yesIcon, a.yesIconDashicon, a.yesIconImageUrl, a.yesIconDashiconColor));
194 } else {
195 yesIconSpan.textContent = a.yesIcon || '';
196 }
197 ap(yesBtn, yesIconSpan, tx('span', '', node.yesLabel || 'Yes'));
198 yesBtn.addEventListener('click', function () {
199 history.push(currentId);
200 navigateTo(node.yesId, 'yes');
201 });
202
203 var noBtn = mk('button', 'bkbg-dt-btn', {
204 background: a.noBg || '#ef4444',
205 color: a.noText || '#ffffff',
206 fontSize: fs
207 });
208 var noIconSpan = mk('span', 'bkbg-dt-btn-icon');
209 var noIconType = a.noIconType || 'custom-char';
210 if (noIconType !== 'custom-char' && window.bkbgIconPicker) {
211 noIconSpan.appendChild(window.bkbgIconPicker.buildFrontendIcon(noIconType, a.noIcon, a.noIconDashicon, a.noIconImageUrl, a.noIconDashiconColor));
212 } else {
213 noIconSpan.textContent = a.noIcon || '';
214 }
215 ap(noBtn, noIconSpan, tx('span', '', node.noLabel || 'No'));
216 noBtn.addEventListener('click', function () {
217 history.push(currentId);
218 navigateTo(node.noId, 'no');
219 });
220
221 ap(btnRow, yesBtn, noBtn);
222 card.appendChild(btnRow);
223
224 // Back button
225 if (history.length > 0) {
226 var backRow = mk('div', 'bkbg-dt-back-row', { marginTop: '14px' });
227 var backBtn = mk('button', 'bkbg-dt-back-btn', {
228 background: a.backBg || '#f1f5f9',
229 color: a.backText || '#374151',
230 fontSize: '13px'
231 });
232 backBtn.textContent = '← Back';
233 backBtn.addEventListener('click', function () {
234 var prevId = history.pop();
235 navigateTo(prevId, 'back');
236 });
237 ap(backRow, backBtn);
238 card.appendChild(backRow);
239 }
240
241 cardContainer.appendChild(card);
242 // Animate in
243 card.style.opacity = '0';
244 card.style.transform = 'translateX(8px)';
245 card.style.transition = 'opacity .25s ease, transform .25s ease';
246 setTimeout(function () {
247 card.style.opacity = '1';
248 card.style.transform = 'translateX(0)';
249 }, 20);
250 }
251
252 function renderResult(node) {
253 var card = mk('div', 'bkbg-dt-result-card', {
254 background: node.resultColor || '#6c3fb5',
255 borderRadius: cardRadius,
256 padding: '36px 32px',
257 textAlign: 'center',
258 });
259
260 ap(card, tx('div', '', '🎯', { fontSize: '42px', marginBottom: '14px' }));
261 ap(card, tx('p', '', node.text, {
262 fontSize: fs,
263 lineHeight: '1.6',
264 color: a.resultTextColor || '#ffffff',
265 margin: '0',
266 fontWeight: '500'
267 }));
268
269 // Restart
270 var restartBtn = mk('button', 'bkbg-dt-restart-btn', {
271 color: a.resultTextColor || '#ffffff'
272 });
273 restartBtn.textContent = '↺ Start over';
274 restartBtn.addEventListener('click', function () {
275 history = [];
276 navigateTo(rootId, 'back');
277 });
278 card.appendChild(restartBtn);
279
280 // Back
281 if (history.length > 0) {
282 var backBtn = mk('button', 'bkbg-dt-restart-btn', {
283 color: a.resultTextColor || '#ffffff',
284 marginLeft: '10px'
285 });
286 backBtn.textContent = '← Back';
287 backBtn.addEventListener('click', function () {
288 var prevId = history.pop();
289 navigateTo(prevId, 'back');
290 });
291 card.appendChild(backBtn);
292 }
293
294 cardContainer.appendChild(card);
295 }
296
297 // Kick off
298 renderCurrent();
299 updateBreadcrumb();
300 updateProgress();
301
302 appEl.innerHTML = '';
303 appEl.appendChild(wrap);
304 }
305
306 function init() {
307 document.querySelectorAll('.bkbg-decision-tree-app').forEach(buildBlock);
308 }
309
310 if (document.readyState !== 'loading') { init(); } else { document.addEventListener('DOMContentLoaded', init); }
311 })();
312