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 / pricing-slider / frontend.js

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

295 lines 13.9 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 initBlock(root) {
5 var app = root.querySelector('.bkbg-psl-app');
6 if (!app) return;
7
8 var raw = app.getAttribute('data-opts') || '{}';
9 var o;
10 try { o = JSON.parse(raw); } catch (e) { o = {}; }
11
12 var tiers = Array.isArray(o.tiers) ? o.tiers : [];
13 var showBilling = o.showBilling !== false;
14 var disc = Number(o.annualDiscount) || 20;
15 var currency = o.currency || '$';
16 var period = o.period || '/month';
17 var ctaText = o.ctaText || 'Get Started';
18 var priceSize = Number(o.priceSize) || 56;
19 var cardRadius = Number(o.cardRadius) || 24;
20 var cardBg = o.cardBg || '#ffffff';
21 var headingColor = o.headingColor || '#1e1b4b';
22 var priceColor = o.priceColor || '#6366f1';
23 var featureColor = o.featureColor || '#374151';
24 var accentColor = o.accentColor || '#6366f1';
25 var ctaBg = o.ctaBg || '#6366f1';
26 var ctaColor = o.ctaColor || '#ffffff';
27 var sliderColor = o.sliderColor || '#6366f1';
28 var trackBg = o.trackBg || '#e5e7eb';
29 var checkColor = o.checkColor || '#6366f1';
30
31 var _typoKeys = {
32 headingTypo: '--bkbg-psl-hd-',
33 subheadingTypo: '--bkbg-psl-sh-',
34 priceTypo: '--bkbg-psl-pr-',
35 ctaTypo: '--bkbg-psl-ct-',
36 featureTypo: '--bkbg-psl-ft-'
37 };
38 function typoCssVarsForEl(el) {
39 Object.keys(_typoKeys).forEach(function (attr) {
40 var t = o[attr]; if (!t || typeof t !== 'object') return;
41 var p = _typoKeys[attr];
42 if (t.family) el.style.setProperty(p + 'font-family', t.family);
43 if (t.weight) el.style.setProperty(p + 'font-weight', t.weight);
44 if (t.transform) el.style.setProperty(p + 'text-transform', t.transform);
45 if (t.style) el.style.setProperty(p + 'font-style', t.style);
46 if (t.decoration) el.style.setProperty(p + 'text-decoration', t.decoration);
47 if (t.sizeDesktop) el.style.setProperty(p + 'font-size-d', t.sizeDesktop + (t.sizeUnit || 'px'));
48 if (t.sizeTablet) el.style.setProperty(p + 'font-size-t', t.sizeTablet + (t.sizeUnit || 'px'));
49 if (t.sizeMobile) el.style.setProperty(p + 'font-size-m', t.sizeMobile + (t.sizeUnit || 'px'));
50 if (t.lineHeightDesktop) el.style.setProperty(p + 'line-height-d', t.lineHeightDesktop + (t.lineHeightUnit || ''));
51 if (t.lineHeightTablet) el.style.setProperty(p + 'line-height-t', t.lineHeightTablet + (t.lineHeightUnit || ''));
52 if (t.lineHeightMobile) el.style.setProperty(p + 'line-height-m', t.lineHeightMobile + (t.lineHeightUnit || ''));
53 if (t.letterSpacingDesktop) el.style.setProperty(p + 'letter-spacing-d', t.letterSpacingDesktop + (t.letterSpacingUnit || 'px'));
54 if (t.letterSpacingTablet) el.style.setProperty(p + 'letter-spacing-t', t.letterSpacingTablet + (t.letterSpacingUnit || 'px'));
55 if (t.letterSpacingMobile) el.style.setProperty(p + 'letter-spacing-m', t.letterSpacingMobile + (t.letterSpacingUnit || 'px'));
56 if (t.wordSpacingDesktop) el.style.setProperty(p + 'word-spacing-d', t.wordSpacingDesktop + (t.wordSpacingUnit || 'px'));
57 if (t.wordSpacingTablet) el.style.setProperty(p + 'word-spacing-t', t.wordSpacingTablet + (t.wordSpacingUnit || 'px'));
58 if (t.wordSpacingMobile) el.style.setProperty(p + 'word-spacing-m', t.wordSpacingMobile + (t.wordSpacingUnit || 'px'));
59 });
60 }
61
62 if (tiers.length === 0) return;
63
64 var isAnnual = false;
65 var tierIdx = 0;
66
67 // Set CSS variable for slider accent
68 app.style.setProperty('--bkbg-psl-accent', accentColor);
69 typoCssVarsForEl(root);
70
71 // Build full UI
72 app.innerHTML = '';
73 var header = app.querySelector('.bkbg-psl-header');
74 // Header was saved as a child — re-append it
75 // Actually we need to rebuild since we cleared innerHTML
76 // The heading/subheading came from RichText.Content in save(), reconstructed via .bkbg-psl-header
77 // Since we cleared, let's rebuild:
78
79 // ── Header (rebuilt from opts) ──────────────────────────────────────
80 // The header HTML was already rendered by WP; we just need the dynamic parts.
81 // Re-read saved heading from the DOM before clearing
82 var savedHeader = (function () {
83 var tmp = document.createElement('div');
84 tmp.innerHTML = app.innerHTML; // empty now, so restore manually
85 return null;
86 })();
87
88 // Re-build everything programmatically from opts
89 // (heading / subheading text not stored in opts — they're in the HTML already)
90 // Approach: clone header before clearing
91 var origHTML = app.parentElement ? null : null;
92
93 // Better approach: append header back first
94 // We can't — we already cleared. Let's read data from pre-built DOM instead.
95 // Fix: read the header BEFORE clearing.
96
97 // ── RESTART: read DOM before clear ─────────────────────────────────
98 // This is handled by re-initializing cleanly without clearing the header.
99 // We keep .bkbg-psl-header and append the rest below it.
100 app.innerHTML = ''; // already done above, rebuild from scratch
101
102 // Heading row (recreate from opts — note: rich text is lost; use a placeholder if undefined)
103 var headingEl = document.createElement('div');
104 headingEl.className = 'bkbg-psl-header';
105
106 // Billing toggle
107 var billingEl = null;
108 if (showBilling) {
109 billingEl = document.createElement('div');
110 billingEl.className = 'bkbg-psl-billing';
111
112 var lblMonthly = document.createElement('span');
113 lblMonthly.className = 'bkbg-psl-label-monthly';
114 lblMonthly.textContent = 'Monthly';
115 lblMonthly.style.fontWeight = '700';
116 lblMonthly.style.color = headingColor;
117
118 var toggleWrap = document.createElement('div');
119 toggleWrap.className = 'bkbg-psl-toggle-wrap';
120 toggleWrap.style.background = '#d1d5db';
121 toggleWrap.setAttribute('role', 'switch');
122 toggleWrap.setAttribute('aria-checked', 'false');
123 toggleWrap.setAttribute('tabindex', '0');
124
125 var knob = document.createElement('div');
126 knob.className = 'bkbg-psl-toggle-knob';
127 toggleWrap.appendChild(knob);
128
129 var lblAnnual = document.createElement('span');
130 lblAnnual.className = 'bkbg-psl-label-annual';
131 lblAnnual.style.color = headingColor;
132 lblAnnual.innerHTML = 'Annual <span class="bkbg-psl-save-badge">-' + disc + '%</span>';
133
134 billingEl.appendChild(lblMonthly);
135 billingEl.appendChild(toggleWrap);
136 billingEl.appendChild(lblAnnual);
137
138 function setBilling(annual) {
139 isAnnual = annual;
140 if (annual) {
141 toggleWrap.classList.add('bkbg-psl-on');
142 toggleWrap.style.background = accentColor;
143 toggleWrap.setAttribute('aria-checked', 'true');
144 lblMonthly.style.fontWeight = '400';
145 lblAnnual.style.fontWeight = '700';
146 } else {
147 toggleWrap.classList.remove('bkbg-psl-on');
148 toggleWrap.style.background = '#d1d5db';
149 toggleWrap.setAttribute('aria-checked', 'false');
150 lblMonthly.style.fontWeight = '700';
151 lblAnnual.style.fontWeight = '400';
152 }
153 updateCard();
154 }
155 toggleWrap.addEventListener('click', function () { setBilling(!isAnnual); });
156 toggleWrap.addEventListener('keydown', function (e) {
157 if (e.key === 'Enter' || e.key === ' ') { setBilling(!isAnnual); }
158 });
159 }
160
161 // Slider
162 var sliderWrap = document.createElement('div');
163 sliderWrap.className = 'bkbg-psl-slider-wrap';
164
165 var labelsRow = document.createElement('div');
166 labelsRow.className = 'bkbg-psl-labels';
167 var labelEls = tiers.map(function (t, i) {
168 var span = document.createElement('span');
169 span.className = 'bkbg-psl-label' + (i === 0 ? ' bkbg-psl-active' : '');
170 span.textContent = t.label || '';
171 span.style.color = i === 0 ? accentColor : '';
172 span.addEventListener('click', function () { setTierIdx(i); range.value = i; });
173 return span;
174 });
175 labelEls.forEach(function (el) { labelsRow.appendChild(el); });
176
177 var range = document.createElement('input');
178 range.type = 'range';
179 range.min = 0;
180 range.max = tiers.length - 1;
181 range.step = 1;
182 range.value = 0;
183 range.className = 'bkbg-psl-range';
184 // Track gradient
185 function updateRangeTrack() {
186 var pct = (tierIdx / (tiers.length - 1)) * 100;
187 range.style.background = 'linear-gradient(to right,' + sliderColor + ' 0%,' + sliderColor + ' ' + pct + '%,' + trackBg + ' ' + pct + '%,' + trackBg + ' 100%)';
188 }
189
190 sliderWrap.appendChild(labelsRow);
191 sliderWrap.appendChild(range);
192
193 // Card
194 var card = document.createElement('div');
195 card.className = 'bkbg-psl-card';
196 card.style.background = cardBg;
197 card.style.borderRadius = cardRadius + 'px';
198 card.style.border = '2px solid ' + accentColor;
199 card.style.boxShadow = '0 4px 24px rgba(0,0,0,0.08)';
200
201 var tierName = document.createElement('div'); tierName.className = 'bkbg-psl-tier-name'; tierName.style.color = accentColor;
202 var tierUsers = document.createElement('div'); tierUsers.className = 'bkbg-psl-tier-users';
203 var priceRow = document.createElement('div'); priceRow.className = 'bkbg-psl-price-row';
204 var currencyEl = document.createElement('span'); currencyEl.className = 'bkbg-psl-currency'; currencyEl.textContent = currency; currencyEl.style.color = priceColor;
205 var amountEl = document.createElement('span'); amountEl.className = 'bkbg-psl-amount'; amountEl.style.color = priceColor;
206 var periodEl = document.createElement('span'); periodEl.className = 'bkbg-psl-period'; periodEl.textContent = period;
207 var annualNote = document.createElement('div'); annualNote.className = 'bkbg-psl-annual-note';
208 var featureList = document.createElement('ul'); featureList.className = 'bkbg-psl-features';
209 var ctaBtn = document.createElement('button');ctaBtn.className = 'bkbg-psl-cta'; ctaBtn.textContent = ctaText;
210 ctaBtn.style.background = ctaBg; ctaBtn.style.color = ctaColor;
211
212 priceRow.appendChild(currencyEl);
213 priceRow.appendChild(amountEl);
214 priceRow.appendChild(periodEl);
215 card.appendChild(tierName);
216 card.appendChild(tierUsers);
217 card.appendChild(priceRow);
218 card.appendChild(annualNote);
219 card.appendChild(featureList);
220 card.appendChild(ctaBtn);
221
222 function setTierIdx(i) {
223 tierIdx = i;
224 labelEls.forEach(function (el, idx) {
225 if (idx === i) {
226 el.classList.add('bkbg-psl-active');
227 el.style.color = accentColor;
228 el.style.fontWeight = '700';
229 } else {
230 el.classList.remove('bkbg-psl-active');
231 el.style.color = '';
232 el.style.fontWeight = '';
233 }
234 });
235 updateRangeTrack();
236 updateCard();
237 }
238
239 function updateCard() {
240 var t = tiers[tierIdx] || {};
241 var rawPrice = Number(t.monthlyPrice) || 0;
242 var price = isAnnual ? Math.round(rawPrice * (1 - disc / 100)) : rawPrice;
243
244 tierName.textContent = t.label || '';
245 tierUsers.textContent = t.users || '';
246
247 // Animate price change
248 amountEl.classList.add('bkbg-psl-updating');
249 setTimeout(function () {
250 amountEl.textContent = price;
251 amountEl.classList.remove('bkbg-psl-updating');
252 }, 150);
253
254 annualNote.textContent = isAnnual ? 'Billed annually — save ' + disc + '%' : '';
255
256 // Features
257 featureList.innerHTML = '';
258 (t.features || []).forEach(function (f) {
259 var li = document.createElement('li');
260 li.style.color = featureColor;
261 var check = document.createElement('span');
262 check.className = 'bkbg-psl-check';
263 check.textContent = '';
264 check.style.color = checkColor;
265 li.appendChild(check);
266 li.appendChild(document.createTextNode(f));
267 featureList.appendChild(li);
268 });
269 }
270
271 range.addEventListener('input', function () {
272 setTierIdx(Number(this.value));
273 });
274
275 // Assemble
276 if (billingEl) app.appendChild(billingEl);
277 app.appendChild(sliderWrap);
278 app.appendChild(card);
279
280 // Init
281 setTierIdx(0);
282 updateRangeTrack();
283 }
284
285 function init() {
286 document.querySelectorAll('.wp-block-blockenberg-pricing-slider').forEach(initBlock);
287 }
288
289 if (document.readyState === 'loading') {
290 document.addEventListener('DOMContentLoaded', init);
291 } else {
292 init();
293 }
294 })();
295