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 / quiz / index.js

index.js in Blockenberg — 600+ Advanced Gutenberg Blocks & AI Agent for WordPress Block Editor 2.0.7, at blocks/quiz/index.js

647 lines 48.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function () {
2 var el = wp.element.createElement;
3 var Fragment = wp.element.Fragment;
4 var useState = wp.element.useState;
5 var __ = wp.i18n.__;
6 var registerBlockType = wp.blocks.registerBlockType;
7 var InspectorControls = wp.blockEditor.InspectorControls;
8 var RichText = wp.blockEditor.RichText;
9 var useBlockProps = wp.blockEditor.useBlockProps;
10 var MediaUpload = wp.blockEditor.MediaUpload;
11 var MediaUploadCheck = wp.blockEditor.MediaUploadCheck;
12 var PanelBody = wp.components.PanelBody;
13 var Button = wp.components.Button;
14 var ToggleControl = wp.components.ToggleControl;
15 var RangeControl = wp.components.RangeControl;
16 var SelectControl = wp.components.SelectControl;
17 var TextControl = wp.components.TextControl;
18 var TextareaControl = wp.components.TextareaControl;
19 var ColorPicker = wp.components.ColorPicker;
20 var Popover = wp.components.Popover;
21
22 var PROGRESS_STYLE_OPTIONS = [
23 { label: __('Progress bar', 'blockenberg'), value: 'bar' },
24 { label: __('Dots', 'blockenberg'), value: 'dots' },
25 { label: __('Fraction (1/3)','blockenberg'), value: 'fraction' },
26 ];
27
28 function makeId() { return 'qz' + Math.random().toString(36).substr(2, 5); }
29 var IP = function () { return window.bkbgIconPicker; };
30
31 var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); }
32 var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); }
33
34 function buildWrapStyle(a) {
35 var _tv = getTypoCssVars();
36 var s = {
37 '--bkbg-qz-accent': a.accentColor,
38 '--bkbg-qz-selected-bg': a.selectedBg,
39 '--bkbg-qz-selected-color': a.selectedColor,
40 '--bkbg-qz-selected-border': a.selectedBorder,
41 '--bkbg-qz-option-bg': a.optionBg,
42 '--bkbg-qz-option-border': a.optionBorder,
43 '--bkbg-qz-option-text': a.optionText,
44 '--bkbg-qz-btn-bg': a.btnBg,
45 '--bkbg-qz-btn-color': a.btnColor,
46 '--bkbg-qz-retake-bg': a.retakeBg,
47 '--bkbg-qz-retake-color': a.retakeColor,
48 '--bkbg-qz-progress-fill': a.progressFill,
49 '--bkbg-qz-progress-track': a.progressTrack,
50 '--bkbg-qz-card-bg': a.cardBg,
51 '--bkbg-qz-card-border': a.cardBorder,
52 '--bkbg-qz-result-card-bg': a.resultCardBg,
53 '--bkbg-qz-title-color': a.titleColor,
54 '--bkbg-qz-question-color': a.questionColor,
55 '--bkbg-qz-result-title': a.resultTitleColor,
56 '--bkbg-qz-result-desc': a.resultDescColor,
57 '--bkbg-qz-card-r': a.cardRadius + 'px',
58 '--bkbg-qz-card-pad': a.cardPadding + 'px',
59 '--bkbg-qz-opt-r': a.optionRadius + 'px',
60 '--bkbg-qz-opt-pad': a.optionPadding + 'px',
61 '--bkbg-qz-btn-r': a.btnRadius + 'px',
62 '--bkbg-qz-result-icon-sz': a.resultIconSize + 'px',
63 paddingTop: a.paddingTop + 'px',
64 paddingBottom: a.paddingBottom + 'px',
65 backgroundColor: a.bgColor || undefined,
66 };
67 if (_tv) {
68 Object.assign(s, _tv(a.titleTypo || {}, '--bkbg-qz-tt-'));
69 Object.assign(s, _tv(a.descTypo || {}, '--bkbg-qz-ds-'));
70 Object.assign(s, _tv(a.questionTypo || {}, '--bkbg-qz-qt-'));
71 Object.assign(s, _tv(a.optionTypo || {}, '--bkbg-qz-op-'));
72 Object.assign(s, _tv(a.resTitleTypo || {}, '--bkbg-qz-rt-'));
73 Object.assign(s, _tv(a.resDescTypo || {}, '--bkbg-qz-rd-'));
74 }
75 return s;
76 }
77
78 function renderColorControl(key, label, value, onChange, openKey, setOpenKey) {
79 var isOpen = openKey === key;
80 return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } },
81 el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label),
82 el('div', { style: { position: 'relative', flexShrink: 0 } },
83 el('button', { type: 'button', onClick: function () { setOpenKey(isOpen ? null : key); }, style: { width: '28px', height: '28px', borderRadius: '4px', border: isOpen ? '2px solid #007cba' : '2px solid #ddd', cursor: 'pointer', padding: 0, background: value || '#ccc' } }),
84 isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } },
85 el('div', { style: { padding: '8px' } },
86 el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange })
87 )
88 )
89 )
90 );
91 }
92
93 /* ── Progress indicator ─────────────────────────────────────────── */
94 function ProgressIndicator(props) {
95 var current = props.current;
96 var total = props.total;
97 var a = props.a;
98
99 if (!a.showProgress || total === 0) return null;
100
101 if (a.progressStyle === 'fraction') {
102 return el('div', { className: 'bkbg-qz-progress bkbg-qz-progress--fraction', style: { textAlign: 'right', color: a.questionColor, marginBottom: '12px', opacity: 0.7 } },
103 (current + 1) + ' / ' + total
104 );
105 }
106
107 if (a.progressStyle === 'dots') {
108 return el('div', { className: 'bkbg-qz-progress bkbg-qz-progress--dots', style: { display: 'flex', gap: '6px', justifyContent: 'center', marginBottom: '20px' } },
109 Array.from({ length: total }, function (_, i) {
110 return el('div', { key: i, style: { width: i <= current ? '20px' : '8px', height: '8px', borderRadius: '99px', background: i <= current ? a.progressFill : a.progressTrack, transition: 'all 0.3s' } });
111 })
112 );
113 }
114
115 /* bar (default) */
116 var pct = total > 1 ? ((current) / (total - 1)) * 100 : 0;
117 return el('div', { className: 'bkbg-qz-progress bkbg-qz-progress--bar', style: { marginBottom: '20px' } },
118 el('div', { style: { display: 'flex', justifyContent: 'space-between', fontSize: '12px', color: a.questionColor, opacity: 0.6, marginBottom: '6px' } },
119 el('span', null, __('Question', 'blockenberg') + ' ' + (current + 1)),
120 el('span', null, total + ' ' + __('total', 'blockenberg'))
121 ),
122 el('div', { style: { height: '6px', borderRadius: '99px', background: a.progressTrack, overflow: 'hidden' } },
123 el('div', { className: 'bkbg-qz-progress-fill', style: { height: '100%', width: pct + '%', background: a.progressFill, borderRadius: '99px', transition: 'width 0.4s ease' } })
124 )
125 );
126 }
127
128 /* ── Question preview ───────────────────────────────────────────── */
129 function QuestionPreview(props) {
130 var q = props.question;
131 var idx = props.idx;
132 var total = props.total;
133 var a = props.a;
134 var selected = props.selected;
135 var onSelect = props.onSelect;
136
137 var optionBase = {
138 display: 'flex', alignItems: 'center', gap: '10px',
139 padding: a.optionPadding + 'px',
140 borderRadius: a.optionRadius + 'px',
141 border: '2px solid ' + a.optionBorder,
142 background: a.optionBg,
143 cursor: 'pointer',
144 marginBottom: '10px',
145 color: a.optionText,
146 transition: 'all 0.15s',
147 fontFamily: 'inherit',
148 textAlign: 'left',
149 width: '100%',
150 boxSizing: 'border-box',
151 };
152
153 return el('div', { className: 'bkbg-qz-question' },
154 el(ProgressIndicator, { current: idx, total: total, a: a }),
155 el('h3', { className: 'bkbg-qz-question-text', style: { color: a.questionColor, marginBottom: '20px' } }, q.question),
156 el('div', { className: 'bkbg-qz-options' },
157 q.options.map(function (opt) {
158 var isSelected = selected === opt.id;
159 return el('button', {
160 key: opt.id, type: 'button',
161 className: 'bkbg-qz-option' + (isSelected ? ' is-selected' : ''),
162 onClick: function () { onSelect(opt.id); },
163 style: Object.assign({}, optionBase, isSelected ? {
164 background: a.selectedBg,
165 color: a.selectedColor,
166 borderColor: a.selectedBorder,
167 fontWeight: 700,
168 } : {}),
169 },
170 el('span', { className: 'bkbg-qz-option-dot', style: { width: '18px', height: '18px', borderRadius: '50%', border: '2px solid ' + (isSelected ? a.selectedBorder : a.optionBorder), flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' } }),
171 el('span', null, opt.text)
172 );
173 })
174 )
175 );
176 }
177
178 /* ── Result preview ─────────────────────────────────────────────── */
179 function ResultPreview(props) {
180 var result = props.result;
181 var a = props.a;
182
183 return el('div', { className: 'bkbg-qz-result', style: { background: a.resultCardBg, borderRadius: a.cardRadius + 'px', padding: a.cardPadding + 'px', textAlign: 'center' } },
184 el('div', { className: 'bkbg-qz-result-icon', style: { fontSize: a.resultIconSize + 'px', marginBottom: '16px' } }, (result.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(result.iconType, result.icon, result.iconDashicon, result.iconImageUrl, result.iconDashiconColor) : result.icon),
185 el('p', { className: 'bkbg-qz-result-heading', style: { fontWeight: 700, color: a.accentColor, margin: '0 0 6px', textTransform: 'uppercase', letterSpacing: '0.08em' } }, a.resultHeading),
186 el('h3', { className: 'bkbg-qz-result-title', style: { color: a.resultTitleColor, margin: '0 0 12px' } }, result.title),
187 el('p', { className: 'bkbg-qz-result-desc', style: { color: a.resultDescColor, margin: 0 } }, result.description),
188 result.imageUrl && el('img', { src: result.imageUrl, alt: result.title, style: { maxWidth: '100%', borderRadius: '8px', marginTop: '16px' } }),
189 a.showRetake && el('button', { type: 'button', style: { marginTop: '24px', padding: '12px 28px', borderRadius: a.btnRadius + 'px', border: 'none', background: a.retakeBg, color: a.retakeColor, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit' } }, a.retakeLabel)
190 );
191 }
192
193 var v1Attributes = {
194 quizTitle: { type: 'string', default: "What's Your Productivity Style?" },
195 quizDescription: { type: 'string', default: 'Answer 3 quick questions to discover which work style fits you best.' },
196 showTitle: { type: 'boolean', default: true },
197 showDescription: { type: 'boolean', default: true },
198 questions: { type: 'array', default: [
199 { id: 'q1', question: 'How do you prefer to organise your day?', options: [
200 { id: 'q1o1', text: 'Strict timed blocks — every hour is scheduled', points: 3 },
201 { id: 'q1o2', text: 'A prioritised to-do list I work through flexibly', points: 2 },
202 { id: 'q1o3', text: 'I react to what comes up as the day unfolds', points: 1 },
203 { id: 'q1o4', text: 'I have a general direction but no set plan', points: 0 }
204 ] },
205 { id: 'q2', question: 'When distractions hit, you usually…', options: [
206 { id: 'q2o1', text: 'Block notifications and return to deep focus fast', points: 3 },
207 { id: 'q2o2', text: 'Finish the distraction then get back on track', points: 2 },
208 { id: 'q2o3', text: 'Find it hard to return with the same momentum', points: 1 },
209 { id: 'q2o4', text: 'Rarely recover focus the same day', points: 0 }
210 ] },
211 { id: 'q3', question: 'How do you feel about planning tomorrow the night before?', options: [
212 { id: 'q3o1', text: "I always do it — it's non-negotiable", points: 3 },
213 { id: 'q3o2', text: 'Usually yes, if I remember', points: 2 },
214 { id: 'q3o3', text: 'Sometimes, but I often skip it', points: 1 },
215 { id: 'q3o4', text: 'Rarely — I prefer to improvise', points: 0 }
216 ] }
217 ] },
218 resultRanges: { type: 'array', default: [
219 { id: 'r1', minScore: 0, maxScore: 3, icon: '🌱', title: 'The Free-Spirited Explorer', description: 'You prefer spontaneity over structure. Embracing a few simple habits could unlock a big jump in your output without sacrificing your flexibility.', imageUrl: '', imageId: 0 },
220 { id: 'r2', minScore: 4, maxScore: 6, icon: '', title: 'The Balanced Achiever', description: 'You mix structure with adaptability well. Fine-tuning your focus rituals and planning consistency could push you from good to exceptional.', imageUrl: '', imageId: 0 },
221 { id: 'r3', minScore: 7, maxScore: 9, icon: '🏆', title: 'The Power Planner', description: "You're a productivity powerhouse! Your systems are strong — focus now on protecting energy and avoiding burnout while scaling what works.", imageUrl: '', imageId: 0 }
222 ] },
223 progressStyle: { type: 'string', default: 'bar' },
224 showProgress: { type: 'boolean', default: true },
225 oneAtATime: { type: 'boolean', default: true },
226 randomize: { type: 'boolean', default: false },
227 submitLabel: { type: 'string', default: 'See My Results' },
228 retakeLabel: { type: 'string', default: 'Retake Quiz' },
229 showRetake: { type: 'boolean', default: true },
230 resultHeading: { type: 'string', default: 'Your Result' },
231 formMaxWidth: { type: 'integer', default: 640 },
232 cardRadius: { type: 'integer', default: 20 },
233 cardPadding: { type: 'integer', default: 40 },
234 optionRadius: { type: 'integer', default: 10 },
235 optionPadding: { type: 'integer', default: 16 },
236 btnRadius: { type: 'integer', default: 10 },
237 titleSize: { type: 'integer', default: 26 },
238 descSize: { type: 'integer', default: 15 },
239 questionSize: { type: 'integer', default: 20 },
240 optionSize: { type: 'integer', default: 15 },
241 resultTitleSize: { type: 'integer', default: 24 },
242 resultDescSize: { type: 'integer', default: 15 },
243 accentColor: { type: 'string', default: '#6c3fb5' },
244 selectedBg: { type: 'string', default: '#ede9f7' },
245 selectedColor: { type: 'string', default: '#6c3fb5' },
246 selectedBorder: { type: 'string', default: '#6c3fb5' },
247 optionBg: { type: 'string', default: '#f9fafb' },
248 optionBorder: { type: 'string', default: '#e5e7eb' },
249 optionText: { type: 'string', default: '#374151' },
250 btnBg: { type: 'string', default: '#6c3fb5' },
251 btnColor: { type: 'string', default: '#ffffff' },
252 retakeBg: { type: 'string', default: '#f3f4f6' },
253 retakeColor: { type: 'string', default: '#374151' },
254 progressFill: { type: 'string', default: '#6c3fb5' },
255 progressTrack: { type: 'string', default: '#e5e7eb' },
256 cardBg: { type: 'string', default: '#ffffff' },
257 cardBorder: { type: 'string', default: '#e5e7eb' },
258 resultCardBg: { type: 'string', default: '#f9fafb' },
259 resultIconSize: { type: 'integer', default: 48 },
260 titleColor: { type: 'string', default: '#111827' },
261 questionColor: { type: 'string', default: '#1f2937' },
262 resultTitleColor: { type: 'string', default: '#111827' },
263 resultDescColor: { type: 'string', default: '#6b7280' },
264 bgColor: { type: 'string', default: '' },
265 paddingTop: { type: 'integer', default: 64 },
266 paddingBottom: { type: 'integer', default: 64 }
267 };
268
269 function buildWrapStyleV1(a) {
270 return {
271 '--bkbg-qz-accent': a.accentColor,
272 '--bkbg-qz-selected-bg': a.selectedBg,
273 '--bkbg-qz-selected-color': a.selectedColor,
274 '--bkbg-qz-selected-border': a.selectedBorder,
275 '--bkbg-qz-option-bg': a.optionBg,
276 '--bkbg-qz-option-border': a.optionBorder,
277 '--bkbg-qz-option-text': a.optionText,
278 '--bkbg-qz-btn-bg': a.btnBg,
279 '--bkbg-qz-btn-color': a.btnColor,
280 '--bkbg-qz-retake-bg': a.retakeBg,
281 '--bkbg-qz-retake-color': a.retakeColor,
282 '--bkbg-qz-progress-fill': a.progressFill,
283 '--bkbg-qz-progress-track': a.progressTrack,
284 '--bkbg-qz-card-bg': a.cardBg,
285 '--bkbg-qz-card-border': a.cardBorder,
286 '--bkbg-qz-result-card-bg': a.resultCardBg,
287 '--bkbg-qz-title-color': a.titleColor,
288 '--bkbg-qz-question-color': a.questionColor,
289 '--bkbg-qz-result-title': a.resultTitleColor,
290 '--bkbg-qz-result-desc': a.resultDescColor,
291 '--bkbg-qz-card-r': a.cardRadius + 'px',
292 '--bkbg-qz-card-pad': a.cardPadding + 'px',
293 '--bkbg-qz-opt-r': a.optionRadius + 'px',
294 '--bkbg-qz-opt-pad': a.optionPadding + 'px',
295 '--bkbg-qz-btn-r': a.btnRadius + 'px',
296 '--bkbg-qz-title-sz': a.titleSize + 'px',
297 '--bkbg-qz-desc-sz': a.descSize + 'px',
298 '--bkbg-qz-question-sz': a.questionSize + 'px',
299 '--bkbg-qz-option-sz': a.optionSize + 'px',
300 '--bkbg-qz-result-title-sz': a.resultTitleSize + 'px',
301 '--bkbg-qz-result-desc-sz': a.resultDescSize + 'px',
302 '--bkbg-qz-result-icon-sz': a.resultIconSize + 'px',
303 paddingTop: a.paddingTop + 'px',
304 paddingBottom: a.paddingBottom + 'px',
305 backgroundColor: a.bgColor || undefined,
306 };
307 }
308
309 registerBlockType('blockenberg/quiz', {
310 title: __('Scored Quiz', 'blockenberg'),
311 icon: 'clipboard',
312 category: 'bkbg-interactive',
313
314 edit: function (props) {
315 var a = props.attributes;
316 var setAttributes = props.setAttributes;
317 var TC = getTypoControl();
318
319 var openColorKeyState = useState(null);
320 var openColorKey = openColorKeyState[0];
321 var setOpenColorKey = openColorKeyState[1];
322
323 /* Editor preview state */
324 var previewModeState = useState('question'); /* 'question' | 'result' */
325 var previewMode = previewModeState[0];
326 var setPreviewMode = previewModeState[1];
327
328 var previewQIdxState = useState(0);
329 var previewQIdx = previewQIdxState[0];
330 var setPreviewQIdx = previewQIdxState[1];
331
332 var selectedOptsState = useState({});
333 var selectedOpts = selectedOptsState[0];
334 var setSelectedOpts = selectedOptsState[1];
335
336 var previewResultIdxState = useState(0);
337 var previewResultIdx = previewResultIdxState[0];
338 var setPreviewResultIdx = previewResultIdxState[1];
339
340 var blockProps = useBlockProps({ style: buildWrapStyle(a) });
341
342 function cc(key, label, attrKey) {
343 return renderColorControl(key, label, a[attrKey], function (val) {
344 var upd = {}; upd[attrKey] = val; setAttributes(upd);
345 }, openColorKey, setOpenColorKey);
346 }
347
348 function updateQuestion(qId, key, val) {
349 setAttributes({ questions: a.questions.map(function (q) {
350 if (q.id !== qId) return q;
351 var u = Object.assign({}, q); u[key] = val; return u;
352 }) });
353 }
354
355 function updateOption(qId, oId, key, val) {
356 setAttributes({ questions: a.questions.map(function (q) {
357 if (q.id !== qId) return q;
358 return Object.assign({}, q, { options: q.options.map(function (o) {
359 if (o.id !== oId) return o;
360 var u = Object.assign({}, o); u[key] = val; return u;
361 }) });
362 }) });
363 }
364
365 function addOption(qId) {
366 setAttributes({ questions: a.questions.map(function (q) {
367 if (q.id !== qId) return q;
368 return Object.assign({}, q, { options: q.options.concat([{ id: makeId(), text: __('New option', 'blockenberg'), points: 1 }]) });
369 }) });
370 }
371
372 function updateResult(rId, key, val) {
373 setAttributes({ resultRanges: a.resultRanges.map(function (r) {
374 if (r.id !== rId) return r;
375 var u = Object.assign({}, r); u[key] = val; return u;
376 }) });
377 }
378
379 var safeQIdx = Math.min(previewQIdx, a.questions.length - 1);
380 var currentQ = a.questions[safeQIdx];
381 var currentResult = a.resultRanges[previewResultIdx] || a.resultRanges[0];
382
383 /* card wrapper style */
384 var cardStyle = {
385 background: a.cardBg,
386 border: '1px solid ' + a.cardBorder,
387 borderRadius: a.cardRadius + 'px',
388 padding: a.cardPadding + 'px',
389 boxSizing: 'border-box',
390 };
391
392 /* preview toolbar */
393 var toolbar = el('div', { style: { display: 'flex', gap: '8px', marginBottom: '16px', flexWrap: 'wrap' } },
394 el('div', { style: { display: 'flex', gap: '4px', background: '#f3f4f6', borderRadius: '8px', padding: '4px' } },
395 el(Button, { variant: previewMode === 'question' ? 'primary' : 'tertiary', size: 'compact', onClick: function () { setPreviewMode('question'); } }, __('Questions', 'blockenberg')),
396 el(Button, { variant: previewMode === 'result' ? 'primary' : 'tertiary', size: 'compact', onClick: function () { setPreviewMode('result'); } }, __('Results', 'blockenberg'))
397 ),
398 previewMode === 'question' && a.questions.length > 1 && el('div', { style: { display: 'flex', gap: '4px', alignItems: 'center' } },
399 el(Button, { size: 'compact', variant: 'secondary', disabled: safeQIdx <= 0, onClick: function () { setPreviewQIdx(Math.max(0, safeQIdx - 1)); } }, ''),
400 el('span', { style: { fontSize: '12px', padding: '0 4px' } }, (safeQIdx + 1) + ' / ' + a.questions.length),
401 el(Button, { size: 'compact', variant: 'secondary', disabled: safeQIdx >= a.questions.length - 1, onClick: function () { setPreviewQIdx(Math.min(a.questions.length - 1, safeQIdx + 1)); } }, '')
402 ),
403 previewMode === 'result' && a.resultRanges.length > 1 && el('div', { style: { display: 'flex', gap: '4px', alignItems: 'center' } },
404 el(Button, { size: 'compact', variant: 'secondary', disabled: previewResultIdx <= 0, onClick: function () { setPreviewResultIdx(Math.max(0, previewResultIdx - 1)); } }, ''),
405 el('span', { style: { fontSize: '12px', padding: '0 4px' } }, (previewResultIdx + 1) + ' / ' + a.resultRanges.length),
406 el(Button, { size: 'compact', variant: 'secondary', disabled: previewResultIdx >= a.resultRanges.length - 1, onClick: function () { setPreviewResultIdx(previewResultIdx + 1); } }, '')
407 )
408 );
409
410 return el(Fragment, null,
411 el(InspectorControls, null,
412 el(PanelBody, { title: __('Quiz Settings', 'blockenberg'), initialOpen: true },
413 el(ToggleControl, { label: __('Show title', 'blockenberg'), checked: a.showTitle, onChange: function (v) { setAttributes({ showTitle: v }); }, __nextHasNoMarginBottom: true }),
414 el(ToggleControl, { label: __('Show description', 'blockenberg'), checked: a.showDescription, onChange: function (v) { setAttributes({ showDescription: v }); }, __nextHasNoMarginBottom: true }),
415 el(ToggleControl, { label: __('Show progress', 'blockenberg'), checked: a.showProgress, onChange: function (v) { setAttributes({ showProgress: v }); }, __nextHasNoMarginBottom: true }),
416 a.showProgress && el(SelectControl, { label: __('Progress style', 'blockenberg'), value: a.progressStyle, options: PROGRESS_STYLE_OPTIONS, onChange: function (v) { setAttributes({ progressStyle: v }); } }),
417 el(ToggleControl, { label: __('One question at a time', 'blockenberg'), checked: a.oneAtATime, onChange: function (v) { setAttributes({ oneAtATime: v }); }, __nextHasNoMarginBottom: true }),
418 el(ToggleControl, { label: __('Randomize questions', 'blockenberg'), checked: a.randomize, onChange: function (v) { setAttributes({ randomize: v }); }, __nextHasNoMarginBottom: true }),
419 el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: a.formMaxWidth, min: 400, max: 900, onChange: function (v) { setAttributes({ formMaxWidth: v }); } })
420 ),
421 el(PanelBody, { title: __('Labels', 'blockenberg'), initialOpen: false },
422 el(TextControl, { label: __('Submit button', 'blockenberg'), value: a.submitLabel, onChange: function (v) { setAttributes({ submitLabel: v }); } }),
423 el(TextControl, { label: __('Result heading', 'blockenberg'), value: a.resultHeading, onChange: function (v) { setAttributes({ resultHeading: v }); } }),
424 el(ToggleControl, { label: __('Show retake button', 'blockenberg'), checked: a.showRetake, onChange: function (v) { setAttributes({ showRetake: v }); }, __nextHasNoMarginBottom: true }),
425 a.showRetake && el(TextControl, { label: __('Retake label', 'blockenberg'), value: a.retakeLabel, onChange: function (v) { setAttributes({ retakeLabel: v }); } })
426 ),
427 el(PanelBody, { title: __('Card & Option Style', 'blockenberg'), initialOpen: false },
428 el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } }),
429 el(RangeControl, { label: __('Card padding (px)', 'blockenberg'), value: a.cardPadding, min: 12, max: 64, onChange: function (v) { setAttributes({ cardPadding: v }); } }),
430 el(RangeControl, { label: __('Option radius (px)', 'blockenberg'), value: a.optionRadius, min: 0, max: 24, onChange: function (v) { setAttributes({ optionRadius: v }); } }),
431 el(RangeControl, { label: __('Option padding (px)','blockenberg'), value: a.optionPadding, min: 8, max: 32, onChange: function (v) { setAttributes({ optionPadding: v }); } }),
432 el(RangeControl, { label: __('Button radius (px)', 'blockenberg'), value: a.btnRadius, min: 0, max: 99, onChange: function (v) { setAttributes({ btnRadius: v }); } }),
433 el(RangeControl, { label: __('Result icon (px)', 'blockenberg'), value: a.resultIconSize, min: 28, max: 80, onChange: function (v) { setAttributes({ resultIconSize: v }); } })
434 ),
435 el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false },
436 TC && el(TC, { label: __('Title', 'blockenberg'), value: a.titleTypo || {}, onChange: function(v) { setAttributes({ titleTypo: v }); } }),
437 TC && el(TC, { label: __('Description', 'blockenberg'), value: a.descTypo || {}, onChange: function(v) { setAttributes({ descTypo: v }); } }),
438 TC && el(TC, { label: __('Question', 'blockenberg'), value: a.questionTypo || {}, onChange: function(v) { setAttributes({ questionTypo: v }); } }),
439 TC && el(TC, { label: __('Option', 'blockenberg'), value: a.optionTypo || {}, onChange: function(v) { setAttributes({ optionTypo: v }); } }),
440 TC && el(TC, { label: __('Result Title', 'blockenberg'), value: a.resTitleTypo || {}, onChange: function(v) { setAttributes({ resTitleTypo: v }); } }),
441 TC && el(TC, { label: __('Result Description', 'blockenberg'), value: a.resDescTypo || {}, onChange: function(v) { setAttributes({ resDescTypo: v }); } })
442 ),
443 el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false },
444 cc('accentColor', __('Accent', 'blockenberg'), 'accentColor'),
445 cc('titleColor', __('Title', 'blockenberg'), 'titleColor'),
446 cc('questionColor', __('Question text', 'blockenberg'), 'questionColor'),
447 cc('optionBg', __('Option bg', 'blockenberg'), 'optionBg'),
448 cc('optionBorder', __('Option border', 'blockenberg'), 'optionBorder'),
449 cc('optionText', __('Option text', 'blockenberg'), 'optionText'),
450 cc('selectedBg', __('Selected bg', 'blockenberg'), 'selectedBg'),
451 cc('selectedColor', __('Selected text', 'blockenberg'), 'selectedColor'),
452 cc('selectedBorder', __('Selected border', 'blockenberg'), 'selectedBorder'),
453 cc('btnBg', __('Submit btn bg', 'blockenberg'), 'btnBg'),
454 cc('btnColor', __('Submit btn text', 'blockenberg'), 'btnColor'),
455 cc('retakeBg', __('Retake btn bg', 'blockenberg'), 'retakeBg'),
456 cc('retakeColor', __('Retake btn text', 'blockenberg'), 'retakeColor'),
457 cc('progressFill', __('Progress fill', 'blockenberg'), 'progressFill'),
458 cc('progressTrack', __('Progress track', 'blockenberg'), 'progressTrack'),
459 cc('cardBg', __('Card bg', 'blockenberg'), 'cardBg'),
460 cc('cardBorder', __('Card border', 'blockenberg'), 'cardBorder'),
461 cc('resultCardBg', __('Result card bg', 'blockenberg'), 'resultCardBg'),
462 cc('resultTitleColor', __('Result title', 'blockenberg'), 'resultTitleColor'),
463 cc('resultDescColor', __('Result desc', 'blockenberg'), 'resultDescColor'),
464 cc('bgColor', __('Section bg', 'blockenberg'), 'bgColor')
465 ),
466 el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false },
467 el(RangeControl, { label: __('Padding top (px)', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }),
468 el(RangeControl, { label: __('Padding bottom (px)', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } })
469 ),
470 el(PanelBody, { title: __('Questions', 'blockenberg'), initialOpen: false },
471 a.questions.map(function (q, qi) {
472 return el(PanelBody, { key: q.id, title: 'Q' + (qi + 1) + ': ' + (q.question ? q.question.substring(0, 30) : ''), initialOpen: false },
473 el(TextareaControl, { label: __('Question', 'blockenberg'), value: q.question, rows: 2, onChange: function (v) { updateQuestion(q.id, 'question', v); } }),
474 el('p', { style: { fontSize: '12px', fontWeight: 600, margin: '6px 0 4px' } }, __('Options', 'blockenberg')),
475 q.options.map(function (o, oi) {
476 return el('div', { key: o.id, style: { display: 'flex', gap: '6px', alignItems: 'flex-start', marginBottom: '8px' } },
477 el('div', { style: { flex: 1 } },
478 el(TextareaControl, { label: __('Text', 'blockenberg'), value: o.text, rows: 1, onChange: function (v) { updateOption(q.id, o.id, 'text', v); }, hideLabelFromVision: true }),
479 el(RangeControl, { label: __('Points', 'blockenberg'), value: o.points, min: 0, max: 10, onChange: function (v) { updateOption(q.id, o.id, 'points', v); } })
480 ),
481 el(Button, { onClick: function () { updateQuestion(q.id, 'options', q.options.filter(function (x) { return x.id !== o.id; })); }, isDestructive: true, variant: 'tertiary', size: 'compact', icon: 'trash', label: __('Remove', 'blockenberg') })
482 );
483 }),
484 el(Button, { variant: 'secondary', size: 'compact', onClick: function () { addOption(q.id); } }, '+ ' + __('Add option', 'blockenberg')),
485 el(Button, { onClick: function () { setAttributes({ questions: a.questions.filter(function (x) { return x.id !== q.id; }) }); }, isDestructive: true, variant: 'tertiary', size: 'compact', style: { marginTop: '8px', display: 'block' } }, __('Remove question', 'blockenberg'))
486 );
487 }),
488 el(Button, { variant: 'primary', style: { marginTop: '8px' }, onClick: function () { setAttributes({ questions: a.questions.concat([{ id: makeId(), question: __('New question', 'blockenberg'), options: [{ id: makeId(), text: __('Option A', 'blockenberg'), points: 0 }, { id: makeId(), text: __('Option B', 'blockenberg'), points: 1 }] }]) }); } }, '+ ' + __('Add question', 'blockenberg'))
489 ),
490 el(PanelBody, { title: __('Result Ranges', 'blockenberg'), initialOpen: false },
491 a.resultRanges.map(function (r, ri) {
492 return el(PanelBody, { key: r.id, title: ((r.iconType || 'custom-char') === 'custom-char' ? (r.icon || '') : '') + ' ' + (r.title ? r.title.substring(0, 22) : 'Range ' + (ri + 1)) + ' (' + r.minScore + '' + r.maxScore + ')', initialOpen: false },
493 el(IP().IconPickerControl, {
494 iconType: r.iconType || 'custom-char',
495 customChar: r.icon,
496 dashicon: r.iconDashicon || '',
497 imageUrl: r.iconImageUrl || '',
498 onChangeType: function (v) { updateResult(r.id, 'iconType', v); },
499 onChangeChar: function (v) { updateResult(r.id, 'icon', v); },
500 onChangeDashicon: function (v) { updateResult(r.id, 'iconDashicon', v); },
501 onChangeImageUrl: function (v) { updateResult(r.id, 'iconImageUrl', v); }
502 }),
503 el(TextControl, { label: __('Title', 'blockenberg'), value: r.title, onChange: function (v) { updateResult(r.id, 'title', v); } }),
504 el(TextareaControl, { label: __('Description', 'blockenberg'), value: r.description, rows: 3, onChange: function (v) { updateResult(r.id, 'description', v); } }),
505 el(RangeControl, { label: __('Min score', 'blockenberg'), value: r.minScore, min: 0, max: 100, onChange: function (v) { updateResult(r.id, 'minScore', v); } }),
506 el(RangeControl, { label: __('Max score', 'blockenberg'), value: r.maxScore, min: 0, max: 100, onChange: function (v) { updateResult(r.id, 'maxScore', v); } }),
507 el(MediaUploadCheck, null, el(MediaUpload, { onSelect: function (m) { updateResult(r.id, 'imageUrl', m.url); updateResult(r.id, 'imageId', m.id); }, allowedTypes: ['image'], value: r.imageId, render: function (rp) { return el(Button, { variant: 'secondary', size: 'compact', onClick: rp.open }, r.imageUrl ? __('Change image', 'blockenberg') : __('Upload image', 'blockenberg')); } })),
508 el(Button, { onClick: function () { setAttributes({ resultRanges: a.resultRanges.filter(function (x) { return x.id !== r.id; }) }); }, isDestructive: true, variant: 'tertiary', size: 'compact', style: { marginTop: '8px', display: 'block' } }, __('Remove range', 'blockenberg'))
509 );
510 }),
511 el(Button, { variant: 'primary', style: { marginTop: '8px' }, onClick: function () { setAttributes({ resultRanges: a.resultRanges.concat([{ id: makeId(), minScore: 0, maxScore: 10, icon: '', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '', title: __('New Result', 'blockenberg'), description: '', imageUrl: '', imageId: 0 }]) }); } }, '+ ' + __('Add result range', 'blockenberg'))
512 )
513 ),
514
515 el('div', blockProps,
516 el('div', { className: 'bkbg-qz-outer', style: { maxWidth: a.formMaxWidth + 'px', margin: '0 auto' } },
517 /* quiz header */
518 (a.showTitle || a.showDescription) && el('div', { className: 'bkbg-qz-header', style: { marginBottom: '28px', textAlign: 'center' } },
519 a.showTitle && el(RichText, { tagName: 'h2', className: 'bkbg-qz-title', value: a.quizTitle, onChange: function (v) { setAttributes({ quizTitle: v }); }, placeholder: __('Quiz title…', 'blockenberg'), style: { color: a.titleColor, margin: '0 0 10px' } }),
520 a.showDescription && el(RichText, { tagName: 'p', className: 'bkbg-qz-description', value: a.quizDescription, onChange: function (v) { setAttributes({ quizDescription: v }); }, placeholder: __('Short description…', 'blockenberg'), style: { color: a.questionColor, opacity: 0.75, margin: 0 } })
521 ),
522 /* editor toolbar */
523 toolbar,
524 /* preview card */
525 el('div', { className: 'bkbg-qz-card', style: cardStyle },
526 previewMode === 'question' && a.questions.length > 0 && el(Fragment, null,
527 el(QuestionPreview, { question: currentQ, idx: safeQIdx, total: a.questions.length, a: a, selected: selectedOpts[currentQ.id], onSelect: function (oId) { var u = Object.assign({}, selectedOpts); u[currentQ.id] = oId; setSelectedOpts(u); } }),
528 el('div', { style: { display: 'flex', justifyContent: 'space-between', marginTop: '20px', gap: '10px' } },
529 el('div', null),
530 el('button', { type: 'button', style: { padding: '12px 28px', borderRadius: a.btnRadius + 'px', border: 'none', background: a.btnBg, color: a.btnColor, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit' } },
531 safeQIdx < a.questions.length - 1 ? __('Next →', 'blockenberg') : a.submitLabel
532 )
533 )
534 ),
535 previewMode === 'result' && currentResult && el(ResultPreview, { result: currentResult, a: a }),
536 a.questions.length === 0 && el('p', { style: { textAlign: 'center', color: '#9ca3af', padding: '24px 0' } }, __('Add questions in the panel →', 'blockenberg'))
537 )
538 )
539 )
540 );
541 },
542
543 deprecated: [{
544 attributes: v1Attributes,
545 save: function (props) {
546 var a = props.attributes;
547 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-qz-wrapper', style: buildWrapStyleV1(a) }),
548 el('div', { className: 'bkbg-qz-outer', style: { maxWidth: a.formMaxWidth + 'px', margin: '0 auto' } },
549 (a.showTitle || a.showDescription) && el('div', { className: 'bkbg-qz-header' },
550 a.showTitle && el(RichText.Content, { tagName: 'h2', className: 'bkbg-qz-title', value: a.quizTitle }),
551 a.showDescription && el(RichText.Content, { tagName: 'p', className: 'bkbg-qz-description', value: a.quizDescription })
552 ),
553 el('div', { className: 'bkbg-qz-card', 'data-one-at-a-time': a.oneAtATime ? 'true' : 'false', 'data-randomize': a.randomize ? 'true' : 'false', 'data-progress-style': a.progressStyle, 'data-show-progress': a.showProgress ? 'true' : 'false' },
554 el('div', { className: 'bkbg-qz-progress-wrap', 'aria-hidden': 'true' }),
555 el('div', { className: 'bkbg-qz-questions-wrap' },
556 a.questions.map(function (q, qi) {
557 return el('div', { key: q.id, className: 'bkbg-qz-question', 'data-question-idx': qi, 'data-question-id': q.id, 'aria-hidden': qi === 0 ? 'false' : 'true', style: { display: qi === 0 ? 'block' : 'none' } },
558 el('h3', { className: 'bkbg-qz-question-text' }, q.question),
559 el('ul', { className: 'bkbg-qz-options', role: 'list' },
560 q.options.map(function (o) {
561 return el('li', { key: o.id, className: 'bkbg-qz-option-item' },
562 el('button', { type: 'button', className: 'bkbg-qz-option', 'data-points': o.points, 'data-option-id': o.id },
563 el('span', { className: 'bkbg-qz-option-dot', 'aria-hidden': 'true' }),
564 el('span', { className: 'bkbg-qz-option-text' }, o.text)
565 )
566 );
567 })
568 ),
569 el('div', { className: 'bkbg-qz-question-nav' },
570 el('div', null),
571 el('button', { type: 'button', className: 'bkbg-qz-btn-next', 'data-is-last': qi === a.questions.length - 1 ? 'true' : 'false', disabled: true },
572 qi < a.questions.length - 1 ? __('Next →', 'blockenberg') : a.submitLabel
573 )
574 )
575 );
576 })
577 ),
578 el('div', { className: 'bkbg-qz-results-wrap is-hidden', 'aria-live': 'polite' },
579 a.resultRanges.map(function (r) {
580 return el('div', { key: r.id, className: 'bkbg-qz-result', 'data-min': r.minScore, 'data-max': r.maxScore, style: { display: 'none' } },
581 el('div', { className: 'bkbg-qz-result-icon', 'aria-hidden': 'true' }, r.icon),
582 el('p', { className: 'bkbg-qz-result-heading' }, a.resultHeading),
583 el('h3', { className: 'bkbg-qz-result-title' }, r.title),
584 el('p', { className: 'bkbg-qz-result-desc' }, r.description),
585 r.imageUrl && el('img', { src: r.imageUrl, alt: r.title, loading: 'lazy', className: 'bkbg-qz-result-img' }),
586 a.showRetake && el('button', { type: 'button', className: 'bkbg-qz-retake' }, a.retakeLabel)
587 );
588 })
589 )
590 )
591 )
592 );
593 }
594 }],
595
596 save: function (props) {
597 var a = props.attributes;
598 return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-qz-wrapper', style: buildWrapStyle(a) }),
599 el('div', { className: 'bkbg-qz-outer', style: { maxWidth: a.formMaxWidth + 'px', margin: '0 auto' } },
600 (a.showTitle || a.showDescription) && el('div', { className: 'bkbg-qz-header' },
601 a.showTitle && el(RichText.Content, { tagName: 'h2', className: 'bkbg-qz-title', value: a.quizTitle }),
602 a.showDescription && el(RichText.Content, { tagName: 'p', className: 'bkbg-qz-description', value: a.quizDescription })
603 ),
604 el('div', { className: 'bkbg-qz-card', 'data-one-at-a-time': a.oneAtATime ? 'true' : 'false', 'data-randomize': a.randomize ? 'true' : 'false', 'data-progress-style': a.progressStyle, 'data-show-progress': a.showProgress ? 'true' : 'false' },
605 el('div', { className: 'bkbg-qz-progress-wrap', 'aria-hidden': 'true' }),
606 el('div', { className: 'bkbg-qz-questions-wrap' },
607 a.questions.map(function (q, qi) {
608 return el('div', { key: q.id, className: 'bkbg-qz-question', 'data-question-idx': qi, 'data-question-id': q.id, 'aria-hidden': qi === 0 ? 'false' : 'true', style: { display: qi === 0 ? 'block' : 'none' } },
609 el('h3', { className: 'bkbg-qz-question-text' }, q.question),
610 el('ul', { className: 'bkbg-qz-options', role: 'list' },
611 q.options.map(function (o) {
612 return el('li', { key: o.id, className: 'bkbg-qz-option-item' },
613 el('button', { type: 'button', className: 'bkbg-qz-option', 'data-points': o.points, 'data-option-id': o.id },
614 el('span', { className: 'bkbg-qz-option-dot', 'aria-hidden': 'true' }),
615 el('span', { className: 'bkbg-qz-option-text' }, o.text)
616 )
617 );
618 })
619 ),
620 el('div', { className: 'bkbg-qz-question-nav' },
621 el('div', null),
622 el('button', { type: 'button', className: 'bkbg-qz-btn-next', 'data-is-last': qi === a.questions.length - 1 ? 'true' : 'false', disabled: true },
623 qi < a.questions.length - 1 ? __('Next →', 'blockenberg') : a.submitLabel
624 )
625 )
626 );
627 })
628 ),
629 el('div', { className: 'bkbg-qz-results-wrap is-hidden', 'aria-live': 'polite' },
630 a.resultRanges.map(function (r) {
631 return el('div', { key: r.id, className: 'bkbg-qz-result', 'data-min': r.minScore, 'data-max': r.maxScore, style: { display: 'none' } },
632 el('div', { className: 'bkbg-qz-result-icon', 'aria-hidden': 'true' }, (r.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(r.iconType, r.icon, r.iconDashicon, r.iconImageUrl, r.iconDashiconColor) : r.icon),
633 el('p', { className: 'bkbg-qz-result-heading' }, a.resultHeading),
634 el('h3', { className: 'bkbg-qz-result-title' }, r.title),
635 el('p', { className: 'bkbg-qz-result-desc' }, r.description),
636 r.imageUrl && el('img', { src: r.imageUrl, alt: r.title, loading: 'lazy', className: 'bkbg-qz-result-img' }),
637 a.showRetake && el('button', { type: 'button', className: 'bkbg-qz-retake' }, a.retakeLabel)
638 );
639 })
640 )
641 )
642 )
643 );
644 }
645 });
646 }() );
647