| 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 PanelBody = wp.components.PanelBody; |
| 11 |
var Button = wp.components.Button; |
| 12 |
var ToggleControl = wp.components.ToggleControl; |
| 13 |
var RangeControl = wp.components.RangeControl; |
| 14 |
var SelectControl = wp.components.SelectControl; |
| 15 |
var TextControl = wp.components.TextControl; |
| 16 |
var ColorPicker = wp.components.ColorPicker; |
| 17 |
var Popover = wp.components.Popover; |
| 18 |
|
| 19 |
var _tc; function getTypoControl() { return _tc || (_tc = window.bkbgTypographyControl); } |
| 20 |
var _tv; function getTypoCssVars() { return _tv || (_tv = window.bkbgTypoCssVars); } |
| 21 |
var IP = function () { return window.bkbgIconPicker; }; |
| 22 |
|
| 23 |
var CURRENCY_POS_OPTIONS = [ |
| 24 |
{ label: __('Before ($9)', 'blockenberg'), value: 'before' }, |
| 25 |
{ label: __('After (9€)', 'blockenberg'), value: 'after' }, |
| 26 |
]; |
| 27 |
|
| 28 |
function makeId() { return 'pc' + Math.random().toString(36).substr(2, 5); } |
| 29 |
|
| 30 |
function buildWrapStyle(a) { |
| 31 |
return { |
| 32 |
'--bkbg-pc-accent': a.accentColor, |
| 33 |
'--bkbg-pc-slider-track': a.sliderTrack, |
| 34 |
'--bkbg-pc-slider-fill': a.sliderFill, |
| 35 |
'--bkbg-pc-slider-thumb': a.sliderThumb, |
| 36 |
'--bkbg-pc-card-bg': a.cardBg, |
| 37 |
'--bkbg-pc-card-border': a.cardBorder, |
| 38 |
'--bkbg-pc-price-bg': a.priceBg, |
| 39 |
'--bkbg-pc-price-border': a.priceBorder, |
| 40 |
'--bkbg-pc-btn-bg': a.btnBg, |
| 41 |
'--bkbg-pc-btn-color': a.btnColor, |
| 42 |
'--bkbg-pc-title-color': a.titleColor, |
| 43 |
'--bkbg-pc-sub-color': a.subtitleColor, |
| 44 |
'--bkbg-pc-label-color': a.labelColor, |
| 45 |
'--bkbg-pc-price-color': a.priceColor, |
| 46 |
'--bkbg-pc-price-accent': a.priceAccent, |
| 47 |
'--bkbg-pc-card-r': a.cardRadius + 'px', |
| 48 |
'--bkbg-pc-card-pad': a.cardPadding + 'px', |
| 49 |
'--bkbg-pc-btn-r': a.btnRadius + 'px', |
| 50 |
paddingTop: a.paddingTop + 'px', |
| 51 |
paddingBottom: a.paddingBottom + 'px', |
| 52 |
backgroundColor: a.bgColor || undefined, |
| 53 |
}; |
| 54 |
} |
| 55 |
|
| 56 |
function renderColorControl(key, label, value, onChange, openKey, setOpenKey) { |
| 57 |
var isOpen = openKey === key; |
| 58 |
return el('div', { key: key, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px 0', gap: '8px' } }, |
| 59 |
el('span', { style: { fontSize: '12px', color: '#1e1e1e', flex: 1, lineHeight: 1.4 } }, label), |
| 60 |
el('div', { style: { position: 'relative', flexShrink: 0 } }, |
| 61 |
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' } }), |
| 62 |
isOpen && el(Popover, { position: 'bottom left', onClose: function () { setOpenKey(null); } }, |
| 63 |
el('div', { style: { padding: '8px' } }, |
| 64 |
el(ColorPicker, { color: value, enableAlpha: true, onChange: onChange }) |
| 65 |
) |
| 66 |
) |
| 67 |
) |
| 68 |
); |
| 69 |
} |
| 70 |
|
| 71 |
/* ── Compute price from current state ───────────────────────────── */ |
| 72 |
function calcPrice(a, sliderValues, addonChecked, isAnnual) { |
| 73 |
var base = a.basePrice || 0; |
| 74 |
var total = base; |
| 75 |
a.sliders.forEach(function (sl) { |
| 76 |
var val = sliderValues[sl.id] !== undefined ? sliderValues[sl.id] : sl.value; |
| 77 |
total += val * sl.pricePerUnit; |
| 78 |
}); |
| 79 |
a.addons.forEach(function (ad) { |
| 80 |
if (addonChecked[ad.id]) total += ad.price; |
| 81 |
}); |
| 82 |
if (isAnnual && a.annualDiscount > 0) { |
| 83 |
total = total * (1 - a.annualDiscount / 100); |
| 84 |
} |
| 85 |
return total; |
| 86 |
} |
| 87 |
|
| 88 |
function formatPrice(a, val) { |
| 89 |
var num = val.toFixed(2).replace(/\.00$/, ''); |
| 90 |
return a.currencyPos === 'before' |
| 91 |
? a.currency + num |
| 92 |
: num + a.currency; |
| 93 |
} |
| 94 |
|
| 95 |
/* ── Slider row ─────────────────────────────────────────────────── */ |
| 96 |
function SliderRow(props) { |
| 97 |
var sl = props.sl; |
| 98 |
var val = props.val; |
| 99 |
var onChangeVal = props.onChangeVal; |
| 100 |
var a = props.a; |
| 101 |
var pct = ((val - sl.min) / (sl.max - sl.min)) * 100; |
| 102 |
|
| 103 |
return el('div', { className: 'bkbg-pc-slider-row', style: { marginBottom: '22px' } }, |
| 104 |
el('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' } }, |
| 105 |
el('div', { style: { display: 'flex', alignItems: 'center', gap: '6px' } }, |
| 106 |
sl.icon && el('span', { className: 'bkbg-pc-slider-icon', style: { fontSize: '16px' } }, (sl.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(sl.iconType, sl.icon, sl.iconDashicon, sl.iconImageUrl, sl.iconDashiconColor) : sl.icon), |
| 107 |
el('span', { className: 'bkbg-pc-slider-label' }, sl.label) |
| 108 |
), |
| 109 |
el('span', { className: 'bkbg-pc-slider-val' }, val + ' ' + sl.unit) |
| 110 |
), |
| 111 |
el('div', { className: 'bkbg-pc-slider-track-wrap', style: { position: 'relative', height: '6px', borderRadius: '99px', background: a.sliderTrack } }, |
| 112 |
el('div', { className: 'bkbg-pc-slider-fill', style: { position: 'absolute', left: 0, top: 0, height: '100%', width: pct + '%', background: a.sliderFill, borderRadius: '99px', pointerEvents: 'none' } }), |
| 113 |
el('input', { type: 'range', min: sl.min, max: sl.max, step: sl.step, value: val, 'data-slider-id': sl.id, |
| 114 |
onChange: function (e) { onChangeVal(parseFloat(e.target.value)); }, |
| 115 |
className: 'bkbg-pc-range', |
| 116 |
style: { position: 'absolute', inset: 0, width: '100%', opacity: 0, cursor: 'pointer', height: '6px', margin: 0 } |
| 117 |
}) |
| 118 |
) |
| 119 |
); |
| 120 |
} |
| 121 |
|
| 122 |
/* ── Addon row ──────────────────────────────────────────────────── */ |
| 123 |
function AddonRow(props) { |
| 124 |
var ad = props.ad; |
| 125 |
var checked = props.checked; |
| 126 |
var onToggle = props.onToggle; |
| 127 |
var a = props.a; |
| 128 |
|
| 129 |
return el('label', { className: 'bkbg-pc-addon', 'data-addon-id': ad.id, style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '10px', padding: '12px 16px', borderRadius: '10px', border: '1.5px solid ' + (checked ? a.accentColor : a.cardBorder), cursor: 'pointer', marginBottom: '8px', background: checked ? 'rgba(108,63,181,0.05)' : 'transparent', transition: 'all 0.15s' } }, |
| 130 |
el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, |
| 131 |
el('input', { type: 'checkbox', checked: checked, onChange: onToggle, 'data-addon-id': ad.id, style: { accentColor: a.accentColor, width: '16px', height: '16px' } }), |
| 132 |
ad.icon && el('span', { className: 'bkbg-pc-addon-icon', style: { fontSize: '16px' } }, (ad.iconType || 'custom-char') !== 'custom-char' ? IP().buildEditorIcon(ad.iconType, ad.icon, ad.iconDashicon, ad.iconImageUrl, ad.iconDashiconColor) : ad.icon), |
| 133 |
el('span', { className: 'bkbg-pc-addon-label' }, ad.label) |
| 134 |
), |
| 135 |
el('span', { className: 'bkbg-pc-addon-price' }, |
| 136 |
'+' + formatPrice(a, ad.price) + '/mo' |
| 137 |
) |
| 138 |
); |
| 139 |
} |
| 140 |
|
| 141 |
registerBlockType('blockenberg/price-calculator', { |
| 142 |
title: __('Price Calculator', 'blockenberg'), |
| 143 |
icon: 'calculator', |
| 144 |
category: 'bkbg-calculators', |
| 145 |
|
| 146 |
edit: function (props) { |
| 147 |
var a = props.attributes; |
| 148 |
var setAttributes = props.setAttributes; |
| 149 |
|
| 150 |
var openColorKeyState = useState(null); |
| 151 |
var openColorKey = openColorKeyState[0]; |
| 152 |
var setOpenColorKey = openColorKeyState[1]; |
| 153 |
|
| 154 |
/* Interactive preview state */ |
| 155 |
var isAnnualState = useState(false); |
| 156 |
var isAnnual = isAnnualState[0]; |
| 157 |
var setIsAnnual = isAnnualState[1]; |
| 158 |
|
| 159 |
var initSliders = {}; |
| 160 |
a.sliders.forEach(function (sl) { initSliders[sl.id] = sl.value; }); |
| 161 |
var sliderValsState = useState(initSliders); |
| 162 |
var sliderVals = sliderValsState[0]; |
| 163 |
var setSliderVals = sliderValsState[1]; |
| 164 |
|
| 165 |
var initAddons = {}; |
| 166 |
a.addons.forEach(function (ad) { initAddons[ad.id] = ad.checked; }); |
| 167 |
var addonCheckedState = useState(initAddons); |
| 168 |
var addonChecked = addonCheckedState[0]; |
| 169 |
var setAddonChecked = addonCheckedState[1]; |
| 170 |
|
| 171 |
var blockProps = useBlockProps((function () { |
| 172 |
var _tvFn = getTypoCssVars(); |
| 173 |
var s = buildWrapStyle(a); |
| 174 |
if (_tvFn) { |
| 175 |
Object.assign(s, _tvFn(a.titleTypo, '--bkbg-pc-tt-')); |
| 176 |
Object.assign(s, _tvFn(a.subtitleTypo, '--bkbg-pc-st-')); |
| 177 |
Object.assign(s, _tvFn(a.priceTypo, '--bkbg-pc-pr-')); |
| 178 |
Object.assign(s, _tvFn(a.labelTypo, '--bkbg-pc-lb-')); |
| 179 |
} |
| 180 |
return { style: s }; |
| 181 |
})()); |
| 182 |
|
| 183 |
var price = calcPrice(a, sliderVals, addonChecked, isAnnual); |
| 184 |
var priceStr = formatPrice(a, price); |
| 185 |
var priceNote = isAnnual ? a.priceNoteAnnual : a.priceNote; |
| 186 |
|
| 187 |
function cc(key, label, attrKey) { |
| 188 |
return renderColorControl(key, label, a[attrKey], function (val) { |
| 189 |
var upd = {}; upd[attrKey] = val; setAttributes(upd); |
| 190 |
}, openColorKey, setOpenColorKey); |
| 191 |
} |
| 192 |
|
| 193 |
function updateSlider(id, key, val) { |
| 194 |
setAttributes({ sliders: a.sliders.map(function (sl) { |
| 195 |
if (sl.id !== id) return sl; |
| 196 |
var u = Object.assign({}, sl); u[key] = val; return u; |
| 197 |
}) }); |
| 198 |
/* Also reset preview value if key was 'value' */ |
| 199 |
if (key === 'value') { |
| 200 |
var nv = {}; nv[id] = val; |
| 201 |
setSliderVals(Object.assign({}, sliderVals, nv)); |
| 202 |
} |
| 203 |
} |
| 204 |
|
| 205 |
function updateAddon(id, key, val) { |
| 206 |
setAttributes({ addons: a.addons.map(function (ad) { |
| 207 |
if (ad.id !== id) return ad; |
| 208 |
var u = Object.assign({}, ad); u[key] = val; return u; |
| 209 |
}) }); |
| 210 |
} |
| 211 |
|
| 212 |
return el(Fragment, null, |
| 213 |
el(InspectorControls, null, |
| 214 |
el(PanelBody, { title: __('Sliders', 'blockenberg'), initialOpen: true }, |
| 215 |
a.sliders.map(function (sl) { |
| 216 |
return el('div', { key: sl.id, style: { border: '1px solid #e0e0e0', borderRadius: '8px', padding: '10px', marginBottom: '10px' } }, |
| 217 |
el(TextControl, { label: __('Label', 'blockenberg'), value: sl.label, onChange: function (v) { updateSlider(sl.id, 'label', v); } }), |
| 218 |
el(TextControl, { label: __('Unit', 'blockenberg'), value: sl.unit, onChange: function (v) { updateSlider(sl.id, 'unit', v); } }), |
| 219 |
el(IP().IconPickerControl, { |
| 220 |
iconType: sl.iconType || 'custom-char', |
| 221 |
customChar: sl.icon, |
| 222 |
dashicon: sl.iconDashicon || '', |
| 223 |
imageUrl: sl.iconImageUrl || '', |
| 224 |
onChangeType: function (v) { updateSlider(sl.id, 'iconType', v); }, |
| 225 |
onChangeChar: function (v) { updateSlider(sl.id, 'icon', v); }, |
| 226 |
onChangeDashicon: function (v) { updateSlider(sl.id, 'iconDashicon', v); }, |
| 227 |
onChangeImageUrl: function (v) { updateSlider(sl.id, 'iconImageUrl', v); } |
| 228 |
}), |
| 229 |
el('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' } }, |
| 230 |
el(TextControl, { label: __('Min', 'blockenberg'), type: 'number', value: String(sl.min), onChange: function (v) { updateSlider(sl.id, 'min', parseFloat(v)||0); } }), |
| 231 |
el(TextControl, { label: __('Max', 'blockenberg'), type: 'number', value: String(sl.max), onChange: function (v) { updateSlider(sl.id, 'max', parseFloat(v)||100); } }), |
| 232 |
el(TextControl, { label: __('Step', 'blockenberg'), type: 'number', value: String(sl.step), onChange: function (v) { updateSlider(sl.id, 'step', parseFloat(v)||1); } }), |
| 233 |
el(TextControl, { label: __('Default', 'blockenberg'), type: 'number', value: String(sl.value), onChange: function (v) { updateSlider(sl.id, 'value', parseFloat(v)||0); } }) |
| 234 |
), |
| 235 |
el(TextControl, { label: __('Price per unit ($/unit)', 'blockenberg'), type: 'number', value: String(sl.pricePerUnit), onChange: function (v) { updateSlider(sl.id, 'pricePerUnit', parseFloat(v)||0); } }), |
| 236 |
el(Button, { isDestructive: true, variant: 'tertiary', size: 'compact', onClick: function () { setAttributes({ sliders: a.sliders.filter(function (s) { return s.id !== sl.id; }) }); } }, __('Remove', 'blockenberg')) |
| 237 |
); |
| 238 |
}), |
| 239 |
el(Button, { variant: 'secondary', onClick: function () { setAttributes({ sliders: a.sliders.concat([{ id: makeId(), label: __('New Slider', 'blockenberg'), unit: 'units', min: 1, max: 100, step: 1, value: 10, pricePerUnit: 1, icon: '📦', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '' }]) }); }, style: { width: '100%', justifyContent: 'center' } }, '+ ' + __('Add Slider', 'blockenberg')) |
| 240 |
), |
| 241 |
el(PanelBody, { title: __('Add-ons', 'blockenberg'), initialOpen: false }, |
| 242 |
a.addons.map(function (ad) { |
| 243 |
return el('div', { key: ad.id, style: { border: '1px solid #e0e0e0', borderRadius: '8px', padding: '10px', marginBottom: '10px' } }, |
| 244 |
el(TextControl, { label: __('Label', 'blockenberg'), value: ad.label, onChange: function (v) { updateAddon(ad.id, 'label', v); } }), |
| 245 |
el(IP().IconPickerControl, { |
| 246 |
iconType: ad.iconType || 'custom-char', |
| 247 |
customChar: ad.icon, |
| 248 |
dashicon: ad.iconDashicon || '', |
| 249 |
imageUrl: ad.iconImageUrl || '', |
| 250 |
onChangeType: function (v) { updateAddon(ad.id, 'iconType', v); }, |
| 251 |
onChangeChar: function (v) { updateAddon(ad.id, 'icon', v); }, |
| 252 |
onChangeDashicon: function (v) { updateAddon(ad.id, 'iconDashicon', v); }, |
| 253 |
onChangeImageUrl: function (v) { updateAddon(ad.id, 'iconImageUrl', v); } |
| 254 |
}), |
| 255 |
el(TextControl, { label: __('Monthly price ($)', 'blockenberg'), type: 'number', value: String(ad.price), onChange: function (v) { updateAddon(ad.id, 'price', parseFloat(v)||0); } }), |
| 256 |
el(ToggleControl, { label: __('Checked by default', 'blockenberg'), checked: ad.checked, onChange: function (v) { updateAddon(ad.id, 'checked', v); }, __nextHasNoMarginBottom: true }), |
| 257 |
el(Button, { isDestructive: true, variant: 'tertiary', size: 'compact', onClick: function () { setAttributes({ addons: a.addons.filter(function (x) { return x.id !== ad.id; }) }); } }, __('Remove', 'blockenberg')) |
| 258 |
); |
| 259 |
}), |
| 260 |
el(Button, { variant: 'secondary', onClick: function () { setAttributes({ addons: a.addons.concat([{ id: makeId(), label: __('New Add-on', 'blockenberg'), price: 9, checked: false, icon: '✨', iconType: 'custom-char', iconDashicon: '', iconImageUrl: '' }]) }); }, style: { width: '100%', justifyContent: 'center' } }, '+ ' + __('Add Add-on', 'blockenberg')) |
| 261 |
), |
| 262 |
el(PanelBody, { title: __('Pricing Settings', 'blockenberg'), initialOpen: false }, |
| 263 |
el(TextControl, { label: __('Base price ($)', 'blockenberg'), type: 'number', value: String(a.basePrice), onChange: function (v) { setAttributes({ basePrice: parseFloat(v)||0 }); } }), |
| 264 |
el(TextControl, { label: __('Currency symbol', 'blockenberg'), value: a.currency, onChange: function (v) { setAttributes({ currency: v }); } }), |
| 265 |
el(SelectControl, { label: __('Symbol position', 'blockenberg'), value: a.currencyPos, options: CURRENCY_POS_OPTIONS, onChange: function (v) { setAttributes({ currencyPos: v }); } }), |
| 266 |
el(ToggleControl, { label: __('Show billing toggle (monthly/annual)', 'blockenberg'), checked: a.billingToggle, onChange: function (v) { setAttributes({ billingToggle: v }); }, __nextHasNoMarginBottom: true }), |
| 267 |
a.billingToggle && el(RangeControl, { label: __('Annual discount %', 'blockenberg'), value: a.annualDiscount, min: 5, max: 50, onChange: function (v) { setAttributes({ annualDiscount: v }); } }), |
| 268 |
el(TextControl, { label: __('Price note (monthly)', 'blockenberg'), value: a.priceNote, onChange: function (v) { setAttributes({ priceNote: v }); } }), |
| 269 |
a.billingToggle && el(TextControl, { label: __('Price note (annual)', 'blockenberg'), value: a.priceNoteAnnual, onChange: function (v) { setAttributes({ priceNoteAnnual: v }); } }) |
| 270 |
), |
| 271 |
el(PanelBody, { title: __('CTA Button', 'blockenberg'), initialOpen: false }, |
| 272 |
el(TextControl, { label: __('Button label', 'blockenberg'), value: a.ctaLabel, onChange: function (v) { setAttributes({ ctaLabel: v }); } }), |
| 273 |
el(TextControl, { label: __('Button URL', 'blockenberg'), value: a.ctaUrl, onChange: function (v) { setAttributes({ ctaUrl: v }); } }), |
| 274 |
el(ToggleControl, { label: __('Open in new tab', 'blockenberg'), checked: a.ctaNewTab, onChange: function (v) { setAttributes({ ctaNewTab: v }); }, __nextHasNoMarginBottom: true }) |
| 275 |
), |
| 276 |
el(PanelBody, { title: __('Layout', 'blockenberg'), initialOpen: false }, |
| 277 |
el(RangeControl, { label: __('Max width (px)', 'blockenberg'), value: a.maxWidth, min: 400, max: 900, onChange: function (v) { setAttributes({ maxWidth: v }); } }), |
| 278 |
el(RangeControl, { label: __('Card radius (px)', 'blockenberg'), value: a.cardRadius, min: 0, max: 32, onChange: function (v) { setAttributes({ cardRadius: v }); } }), |
| 279 |
el(RangeControl, { label: __('Card padding (px)', 'blockenberg'), value: a.cardPadding, min: 16, max: 64, onChange: function (v) { setAttributes({ cardPadding: v }); } }), |
| 280 |
el(RangeControl, { label: __('Button radius (px)','blockenberg'), value: a.btnRadius, min: 0, max: 99, onChange: function (v) { setAttributes({ btnRadius: v }); } }) |
| 281 |
), |
| 282 |
el(PanelBody, { title: __('Typography', 'blockenberg'), initialOpen: false }, |
| 283 |
(function () { |
| 284 |
var TC = getTypoControl(); |
| 285 |
if (!TC) return el('p', null, 'Loading…'); |
| 286 |
return el(Fragment, null, |
| 287 |
el(TC, { label: __('Title', 'blockenberg'), value: a.titleTypo, onChange: function (v) { setAttributes({ titleTypo: v }); } }), |
| 288 |
el(TC, { label: __('Subtitle', 'blockenberg'), value: a.subtitleTypo, onChange: function (v) { setAttributes({ subtitleTypo: v }); } }), |
| 289 |
el(TC, { label: __('Price', 'blockenberg'), value: a.priceTypo, onChange: function (v) { setAttributes({ priceTypo: v }); } }), |
| 290 |
el(TC, { label: __('Labels', 'blockenberg'), value: a.labelTypo, onChange: function (v) { setAttributes({ labelTypo: v }); } }) |
| 291 |
); |
| 292 |
})() |
| 293 |
), |
| 294 |
el(PanelBody, { title: __('Colors', 'blockenberg'), initialOpen: false }, |
| 295 |
cc('accentColor', __('Accent', 'blockenberg'), 'accentColor'), |
| 296 |
cc('titleColor', __('Title', 'blockenberg'), 'titleColor'), |
| 297 |
cc('subtitleColor', __('Subtitle', 'blockenberg'), 'subtitleColor'), |
| 298 |
cc('labelColor', __('Labels', 'blockenberg'), 'labelColor'), |
| 299 |
cc('priceColor', __('Price text', 'blockenberg'), 'priceColor'), |
| 300 |
cc('priceAccent', __('Price accent', 'blockenberg'), 'priceAccent'), |
| 301 |
cc('sliderTrack', __('Slider track', 'blockenberg'), 'sliderTrack'), |
| 302 |
cc('sliderFill', __('Slider fill', 'blockenberg'), 'sliderFill'), |
| 303 |
cc('cardBg', __('Card background', 'blockenberg'), 'cardBg'), |
| 304 |
cc('cardBorder', __('Card border', 'blockenberg'), 'cardBorder'), |
| 305 |
cc('priceBg', __('Price box bg', 'blockenberg'), 'priceBg'), |
| 306 |
cc('priceBorder', __('Price box border', 'blockenberg'), 'priceBorder'), |
| 307 |
cc('btnBg', __('Button background','blockenberg'), 'btnBg'), |
| 308 |
cc('btnColor', __('Button text', 'blockenberg'), 'btnColor'), |
| 309 |
cc('bgColor', __('Section bg', 'blockenberg'), 'bgColor') |
| 310 |
), |
| 311 |
el(PanelBody, { title: __('Spacing', 'blockenberg'), initialOpen: false }, |
| 312 |
el(RangeControl, { label: __('Padding top', 'blockenberg'), value: a.paddingTop, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingTop: v }); } }), |
| 313 |
el(RangeControl, { label: __('Padding bottom', 'blockenberg'), value: a.paddingBottom, min: 0, max: 200, onChange: function (v) { setAttributes({ paddingBottom: v }); } }) |
| 314 |
) |
| 315 |
), |
| 316 |
|
| 317 |
el('div', blockProps, |
| 318 |
el('div', { className: 'bkbg-pc-outer', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' } }, |
| 319 |
el('div', { className: 'bkbg-pc-card', style: { background: a.cardBg, border: '1px solid ' + a.cardBorder, borderRadius: a.cardRadius + 'px', padding: a.cardPadding + 'px', boxSizing: 'border-box' } }, |
| 320 |
/* Header */ |
| 321 |
el('div', { className: 'bkbg-pc-header', style: { marginBottom: '28px', textAlign: 'center' } }, |
| 322 |
el(RichText, { tagName: 'h2', className: 'bkbg-pc-title', value: a.title, onChange: function (v) { setAttributes({ title: v }); }, placeholder: __('Calculate Your Price', 'blockenberg'), style: { color: a.titleColor, margin: '0 0 8px' } }), |
| 323 |
el(RichText, { tagName: 'p', className: 'bkbg-pc-subtitle', value: a.subtitle, onChange: function (v) { setAttributes({ subtitle: v }); }, placeholder: __('Subtitle…', 'blockenberg'), style: { color: a.subtitleColor, margin: 0 } }) |
| 324 |
), |
| 325 |
/* Billing toggle */ |
| 326 |
a.billingToggle && el('div', { className: 'bkbg-pc-billing-row', style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '12px', marginBottom: '28px' } }, |
| 327 |
el('span', { className: 'bkbg-pc-billing-label', style: { color: isAnnual ? a.labelColor : a.accentColor } }, __('Monthly', 'blockenberg')), |
| 328 |
el('button', { type: 'button', className: 'bkbg-pc-toggle-btn', onClick: function () { setIsAnnual(!isAnnual); }, |
| 329 |
style: { width: '42px', height: '24px', borderRadius: '99px', border: 'none', background: isAnnual ? a.accentColor : '#d1d5db', cursor: 'pointer', position: 'relative', transition: 'background 0.2s', padding: 0 } }, |
| 330 |
el('span', { style: { position: 'absolute', top: '3px', left: isAnnual ? '21px' : '3px', width: '18px', height: '18px', borderRadius: '50%', background: '#fff', transition: 'left 0.2s', display: 'block' } }) |
| 331 |
), |
| 332 |
el('span', { className: 'bkbg-pc-billing-label', style: { color: isAnnual ? a.accentColor : a.labelColor } }, |
| 333 |
__('Annual', 'blockenberg'), |
| 334 |
a.annualDiscount > 0 && el('span', { style: { marginLeft: '6px', background: '#dcfce7', color: '#16a34a', fontSize: '11px', fontWeight: 700, padding: '2px 8px', borderRadius: '99px' } }, '-' + a.annualDiscount + '%') |
| 335 |
) |
| 336 |
), |
| 337 |
/* Sliders */ |
| 338 |
el('div', { className: 'bkbg-pc-sliders', style: { marginBottom: '24px' } }, |
| 339 |
a.sliders.map(function (sl) { |
| 340 |
return el(SliderRow, { key: sl.id, sl: sl, a: a, |
| 341 |
val: sliderVals[sl.id] !== undefined ? sliderVals[sl.id] : sl.value, |
| 342 |
onChangeVal: function (v) { var nv = {}; nv[sl.id] = v; setSliderVals(Object.assign({}, sliderVals, nv)); } |
| 343 |
}); |
| 344 |
}) |
| 345 |
), |
| 346 |
/* Add-ons */ |
| 347 |
a.addons.length > 0 && el('div', { className: 'bkbg-pc-addons', style: { marginBottom: '28px' } }, |
| 348 |
el('p', { className: 'bkbg-pc-addons-label', style: { color: a.labelColor, margin: '0 0 10px' } }, __('Add-ons', 'blockenberg')), |
| 349 |
a.addons.map(function (ad) { |
| 350 |
return el(AddonRow, { key: ad.id, ad: ad, a: a, |
| 351 |
checked: addonChecked[ad.id] !== undefined ? addonChecked[ad.id] : ad.checked, |
| 352 |
onToggle: function () { var nv = {}; nv[ad.id] = !addonChecked[ad.id]; setAddonChecked(Object.assign({}, addonChecked, nv)); } |
| 353 |
}); |
| 354 |
}) |
| 355 |
), |
| 356 |
/* Price display */ |
| 357 |
el('div', { className: 'bkbg-pc-price-box', style: { background: a.priceBg, border: '1px solid ' + a.priceBorder, borderRadius: '12px', padding: '24px', textAlign: 'center', marginBottom: '20px' } }, |
| 358 |
el('div', { className: 'bkbg-pc-price', style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'center', gap: '2px', lineHeight: 1 } }, |
| 359 |
a.currencyPos === 'before' && el('span', { style: { fontSize: '24px', fontWeight: 900, color: a.priceAccent, marginTop: '6px' } }, a.currency), |
| 360 |
el('span', { className: 'bkbg-pc-price-val', style: { color: a.priceColor } }, price.toFixed(2).replace(/\.00$/, '')), |
| 361 |
a.currencyPos === 'after' && el('span', { style: { fontSize: '24px', fontWeight: 900, color: a.priceAccent, marginTop: '6px' } }, a.currency) |
| 362 |
), |
| 363 |
el('p', { className: 'bkbg-pc-price-note', style: { fontSize: '13px', color: a.subtitleColor, margin: '6px 0 0' } }, priceNote) |
| 364 |
), |
| 365 |
/* CTA */ |
| 366 |
el('a', { href: a.ctaUrl, className: 'bkbg-pc-cta-btn', style: { display: 'block', padding: '16px 28px', borderRadius: a.btnRadius + 'px', border: 'none', background: a.btnBg, color: a.btnColor, fontFamily: 'inherit', fontSize: '16px', fontWeight: 800, cursor: 'pointer', textAlign: 'center', textDecoration: 'none', lineHeight: 1 } }, a.ctaLabel) |
| 367 |
) |
| 368 |
) |
| 369 |
) |
| 370 |
); |
| 371 |
}, |
| 372 |
|
| 373 |
deprecated: [{ |
| 374 |
attributes: {"title":{"type":"string","default":"Calculate Your Price"},"subtitle":{"type":"string","default":"Adjust the sliders to see your custom quote instantly."},"currency":{"type":"string","default":"$"},"currencyPos":{"type":"string","default":"before"},"billingToggle":{"type":"boolean","default":true},"annualDiscount":{"type":"number","default":20},"sliders":{"type":"array","default":[{"id":"sl1","label":"Team Members","unit":"users","min":1,"max":50,"step":1,"value":5,"pricePerUnit":12,"icon":"\ud83d\udc65"},{"id":"sl2","label":"Storage","unit":"GB","min":10,"max":1000,"step":10,"value":100,"pricePerUnit":0.05,"icon":"\ud83d\udcbe"},{"id":"sl3","label":"API Calls / month","unit":"k calls","min":10,"max":500,"step":10,"value":50,"pricePerUnit":0.01,"icon":"\u26a1"}]},"addons":{"type":"array","default":[{"id":"a1","label":"Priority Support","price":29,"checked":false,"icon":"\ud83c\udfa7"},{"id":"a2","label":"Advanced Analytics","price":19,"checked":false,"icon":"\ud83d\udcca"},{"id":"a3","label":"SSO / SAML","price":49,"checked":false,"icon":"\ud83d\udd10"}]},"basePrice":{"type":"number","default":0},"ctaLabel":{"type":"string","default":"Get Started"},"ctaUrl":{"type":"string","default":"#"},"ctaNewTab":{"type":"boolean","default":false},"priceNote":{"type":"string","default":"per month, billed monthly"},"priceNoteAnnual":{"type":"string","default":"per month, billed annually"},"maxWidth":{"type":"number","default":720},"cardRadius":{"type":"number","default":20},"cardPadding":{"type":"number","default":40},"sliderRadius":{"type":"number","default":99},"btnRadius":{"type":"number","default":10},"accentColor":{"type":"string","default":"#6c3fb5"},"sliderTrack":{"type":"string","default":"#e5e7eb"},"sliderFill":{"type":"string","default":"#6c3fb5"},"sliderThumb":{"type":"string","default":"#6c3fb5"},"cardBg":{"type":"string","default":"#ffffff"},"cardBorder":{"type":"string","default":"#e5e7eb"},"priceBg":{"type":"string","default":"#f9fafb"},"priceBorder":{"type":"string","default":"#e5e7eb"},"btnBg":{"type":"string","default":"#6c3fb5"},"btnColor":{"type":"string","default":"#ffffff"},"titleColor":{"type":"string","default":"#111827"},"subtitleColor":{"type":"string","default":"#6b7280"},"labelColor":{"type":"string","default":"#374151"},"priceColor":{"type":"string","default":"#111827"},"priceAccent":{"type":"string","default":"#6c3fb5"},"titleSize":{"type":"number","default":26},"subtitleSize":{"type":"number","default":15},"priceSize":{"type":"number","default":52},"labelSize":{"type":"number","default":14},"bgColor":{"type":"string","default":""},"paddingTop":{"type":"number","default":64},"paddingBottom":{"type":"number","default":64},"titleFontWeight":{"type":"string","default":"700"},"subtitleFontWeight":{"type":"string","default":"400"}}, |
| 375 |
save: function (props) { |
| 376 |
var a = props.attributes; |
| 377 |
function oldBuildWrapStyle(a) { |
| 378 |
return { |
| 379 |
'--bkbg-pc-accent': a.accentColor, |
| 380 |
'--bkbg-pc-slider-track': a.sliderTrack, |
| 381 |
'--bkbg-pc-slider-fill': a.sliderFill, |
| 382 |
'--bkbg-pc-slider-thumb': a.sliderThumb, |
| 383 |
'--bkbg-pc-card-bg': a.cardBg, |
| 384 |
'--bkbg-pc-card-border': a.cardBorder, |
| 385 |
'--bkbg-pc-price-bg': a.priceBg, |
| 386 |
'--bkbg-pc-price-border': a.priceBorder, |
| 387 |
'--bkbg-pc-btn-bg': a.btnBg, |
| 388 |
'--bkbg-pc-btn-color': a.btnColor, |
| 389 |
'--bkbg-pc-title-color': a.titleColor, |
| 390 |
'--bkbg-pc-sub-color': a.subtitleColor, |
| 391 |
'--bkbg-pc-label-color': a.labelColor, |
| 392 |
'--bkbg-pc-price-color': a.priceColor, |
| 393 |
'--bkbg-pc-price-accent': a.priceAccent, |
| 394 |
'--bkbg-pc-card-r': a.cardRadius + 'px', |
| 395 |
'--bkbg-pc-card-pad': a.cardPadding + 'px', |
| 396 |
'--bkbg-pc-btn-r': a.btnRadius + 'px', |
| 397 |
'--bkbg-pc-title-sz': a.titleSize + 'px', |
| 398 |
'--bkbg-pc-sub-sz': a.subtitleSize + 'px', |
| 399 |
'--bkbg-pc-price-sz': a.priceSize + 'px', |
| 400 |
'--bkbg-pc-label-sz': a.labelSize + 'px', |
| 401 |
paddingTop: a.paddingTop + 'px', |
| 402 |
paddingBottom: a.paddingBottom + 'px', |
| 403 |
backgroundColor: a.bgColor || undefined, |
| 404 |
}; |
| 405 |
} |
| 406 |
return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-pc-wrapper', style: oldBuildWrapStyle(a) }), |
| 407 |
el('div', { className: 'bkbg-pc-outer', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' } }, |
| 408 |
el('div', { className: 'bkbg-pc-card', |
| 409 |
'data-currency': a.currency, |
| 410 |
'data-currency-pos': a.currencyPos, |
| 411 |
'data-annual-discount': a.annualDiscount, |
| 412 |
'data-base-price': a.basePrice, |
| 413 |
style: { background: a.cardBg, border: '1px solid ' + a.cardBorder, borderRadius: a.cardRadius + 'px', padding: a.cardPadding + 'px', boxSizing: 'border-box' } }, |
| 414 |
el('div', { className: 'bkbg-pc-header' }, |
| 415 |
el(RichText.Content, { tagName: 'h2', className: 'bkbg-pc-title', value: a.title }), |
| 416 |
el(RichText.Content, { tagName: 'p', className: 'bkbg-pc-subtitle', value: a.subtitle }) |
| 417 |
), |
| 418 |
a.billingToggle && el('div', { className: 'bkbg-pc-billing-row' }, |
| 419 |
el('span', { className: 'bkbg-pc-billing-label is-monthly' }, __('Monthly', 'blockenberg')), |
| 420 |
el('button', { type: 'button', className: 'bkbg-pc-toggle-btn', 'aria-pressed': 'false', 'aria-label': __('Toggle billing period', 'blockenberg') }, |
| 421 |
el('span', { className: 'bkbg-pc-toggle-thumb' }) |
| 422 |
), |
| 423 |
el('span', { className: 'bkbg-pc-billing-label is-annual' }, |
| 424 |
__('Annual', 'blockenberg'), |
| 425 |
a.annualDiscount > 0 && el('span', { className: 'bkbg-pc-discount-badge' }, '-' + a.annualDiscount + '%') |
| 426 |
) |
| 427 |
), |
| 428 |
el('div', { className: 'bkbg-pc-sliders' }, |
| 429 |
a.sliders.map(function (sl) { |
| 430 |
return el('div', { key: sl.id, className: 'bkbg-pc-slider-row', 'data-slider-id': sl.id, 'data-price-per-unit': sl.pricePerUnit }, |
| 431 |
el('div', { className: 'bkbg-pc-slider-header' }, |
| 432 |
el('div', { className: 'bkbg-pc-slider-label-wrap' }, |
| 433 |
sl.icon && el('span', { className: 'bkbg-pc-slider-icon', 'aria-hidden': 'true' }, sl.icon), |
| 434 |
el('span', { className: 'bkbg-pc-slider-label' }, sl.label) |
| 435 |
), |
| 436 |
el('span', { className: 'bkbg-pc-slider-val' }, sl.value + ' ' + sl.unit) |
| 437 |
), |
| 438 |
el('div', { className: 'bkbg-pc-slider-track-wrap' }, |
| 439 |
el('div', { className: 'bkbg-pc-slider-fill' }), |
| 440 |
el('input', { type: 'range', min: sl.min, max: sl.max, step: sl.step, defaultValue: sl.value, 'data-unit': sl.unit, className: 'bkbg-pc-range', 'aria-label': sl.label }) |
| 441 |
) |
| 442 |
); |
| 443 |
}) |
| 444 |
), |
| 445 |
a.addons.length > 0 && el('div', { className: 'bkbg-pc-addons' }, |
| 446 |
el('p', { className: 'bkbg-pc-addons-label' }, __('Add-ons', 'blockenberg')), |
| 447 |
a.addons.map(function (ad) { |
| 448 |
return el('label', { key: ad.id, className: 'bkbg-pc-addon', 'data-addon-id': ad.id, 'data-price': ad.price }, |
| 449 |
el('div', { className: 'bkbg-pc-addon-left' }, |
| 450 |
el('input', { type: 'checkbox', defaultChecked: ad.checked, className: 'bkbg-pc-addon-cb', 'data-addon-id': ad.id }), |
| 451 |
ad.icon && el('span', { className: 'bkbg-pc-addon-icon', 'aria-hidden': 'true' }, ad.icon), |
| 452 |
el('span', { className: 'bkbg-pc-addon-label' }, ad.label) |
| 453 |
), |
| 454 |
el('span', { className: 'bkbg-pc-addon-price' }, '+' + a.currency + ad.price + '/mo') |
| 455 |
); |
| 456 |
}) |
| 457 |
), |
| 458 |
el('div', { className: 'bkbg-pc-price-box' }, |
| 459 |
el('div', { className: 'bkbg-pc-price' }, |
| 460 |
a.currencyPos === 'before' && el('span', { className: 'bkbg-pc-currency' }, a.currency), |
| 461 |
el('span', { className: 'bkbg-pc-price-val' }, '0'), |
| 462 |
a.currencyPos === 'after' && el('span', { className: 'bkbg-pc-currency' }, a.currency) |
| 463 |
), |
| 464 |
el('p', { className: 'bkbg-pc-price-note', 'data-monthly': a.priceNote, 'data-annual': a.priceNoteAnnual }, a.priceNote) |
| 465 |
), |
| 466 |
el('a', { href: a.ctaUrl, className: 'bkbg-pc-cta-btn', target: a.ctaNewTab ? '_blank' : undefined, rel: a.ctaNewTab ? 'noopener noreferrer' : undefined }, a.ctaLabel) |
| 467 |
) |
| 468 |
) |
| 469 |
); |
| 470 |
} |
| 471 |
}], |
| 472 |
|
| 473 |
save: function (props) { |
| 474 |
var a = props.attributes; |
| 475 |
var _tvFn = getTypoCssVars(); |
| 476 |
var saveStyle = buildWrapStyle(a); |
| 477 |
if (_tvFn) { |
| 478 |
Object.assign(saveStyle, _tvFn(a.titleTypo, '--bkbg-pc-tt-')); |
| 479 |
Object.assign(saveStyle, _tvFn(a.subtitleTypo, '--bkbg-pc-st-')); |
| 480 |
Object.assign(saveStyle, _tvFn(a.priceTypo, '--bkbg-pc-pr-')); |
| 481 |
Object.assign(saveStyle, _tvFn(a.labelTypo, '--bkbg-pc-lb-')); |
| 482 |
} |
| 483 |
return el('div', wp.blockEditor.useBlockProps.save({ className: 'bkbg-pc-wrapper', style: saveStyle }), |
| 484 |
el('div', { className: 'bkbg-pc-outer', style: { maxWidth: a.maxWidth + 'px', margin: '0 auto' } }, |
| 485 |
el('div', { className: 'bkbg-pc-card', |
| 486 |
'data-currency': a.currency, |
| 487 |
'data-currency-pos': a.currencyPos, |
| 488 |
'data-annual-discount': a.annualDiscount, |
| 489 |
'data-base-price': a.basePrice, |
| 490 |
style: { background: a.cardBg, border: '1px solid ' + a.cardBorder, borderRadius: a.cardRadius + 'px', padding: a.cardPadding + 'px', boxSizing: 'border-box' } }, |
| 491 |
el('div', { className: 'bkbg-pc-header' }, |
| 492 |
el(RichText.Content, { tagName: 'h2', className: 'bkbg-pc-title', value: a.title }), |
| 493 |
el(RichText.Content, { tagName: 'p', className: 'bkbg-pc-subtitle', value: a.subtitle }) |
| 494 |
), |
| 495 |
a.billingToggle && el('div', { className: 'bkbg-pc-billing-row' }, |
| 496 |
el('span', { className: 'bkbg-pc-billing-label is-monthly' }, __('Monthly', 'blockenberg')), |
| 497 |
el('button', { type: 'button', className: 'bkbg-pc-toggle-btn', 'aria-pressed': 'false', 'aria-label': __('Toggle billing period', 'blockenberg') }, |
| 498 |
el('span', { className: 'bkbg-pc-toggle-thumb' }) |
| 499 |
), |
| 500 |
el('span', { className: 'bkbg-pc-billing-label is-annual' }, |
| 501 |
__('Annual', 'blockenberg'), |
| 502 |
a.annualDiscount > 0 && el('span', { className: 'bkbg-pc-discount-badge' }, '-' + a.annualDiscount + '%') |
| 503 |
) |
| 504 |
), |
| 505 |
el('div', { className: 'bkbg-pc-sliders' }, |
| 506 |
a.sliders.map(function (sl) { |
| 507 |
return el('div', { key: sl.id, className: 'bkbg-pc-slider-row', 'data-slider-id': sl.id, 'data-price-per-unit': sl.pricePerUnit }, |
| 508 |
el('div', { className: 'bkbg-pc-slider-header' }, |
| 509 |
el('div', { className: 'bkbg-pc-slider-label-wrap' }, |
| 510 |
sl.icon && el('span', { className: 'bkbg-pc-slider-icon', 'aria-hidden': 'true' }, (sl.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(sl.iconType, sl.icon, sl.iconDashicon, sl.iconImageUrl, sl.iconDashiconColor) : sl.icon), |
| 511 |
el('span', { className: 'bkbg-pc-slider-label' }, sl.label) |
| 512 |
), |
| 513 |
el('span', { className: 'bkbg-pc-slider-val' }, sl.value + ' ' + sl.unit) |
| 514 |
), |
| 515 |
el('div', { className: 'bkbg-pc-slider-track-wrap' }, |
| 516 |
el('div', { className: 'bkbg-pc-slider-fill' }), |
| 517 |
el('input', { type: 'range', min: sl.min, max: sl.max, step: sl.step, defaultValue: sl.value, 'data-unit': sl.unit, className: 'bkbg-pc-range', 'aria-label': sl.label }) |
| 518 |
) |
| 519 |
); |
| 520 |
}) |
| 521 |
), |
| 522 |
a.addons.length > 0 && el('div', { className: 'bkbg-pc-addons' }, |
| 523 |
el('p', { className: 'bkbg-pc-addons-label' }, __('Add-ons', 'blockenberg')), |
| 524 |
a.addons.map(function (ad) { |
| 525 |
return el('label', { key: ad.id, className: 'bkbg-pc-addon', 'data-addon-id': ad.id, 'data-price': ad.price }, |
| 526 |
el('div', { className: 'bkbg-pc-addon-left' }, |
| 527 |
el('input', { type: 'checkbox', defaultChecked: ad.checked, className: 'bkbg-pc-addon-cb', 'data-addon-id': ad.id }), |
| 528 |
ad.icon && el('span', { className: 'bkbg-pc-addon-icon', 'aria-hidden': 'true' }, (ad.iconType || 'custom-char') !== 'custom-char' ? IP().buildSaveIcon(ad.iconType, ad.icon, ad.iconDashicon, ad.iconImageUrl, ad.iconDashiconColor) : ad.icon), |
| 529 |
el('span', { className: 'bkbg-pc-addon-label' }, ad.label) |
| 530 |
), |
| 531 |
el('span', { className: 'bkbg-pc-addon-price' }, '+' + a.currency + ad.price + '/mo') |
| 532 |
); |
| 533 |
}) |
| 534 |
), |
| 535 |
el('div', { className: 'bkbg-pc-price-box' }, |
| 536 |
el('div', { className: 'bkbg-pc-price' }, |
| 537 |
a.currencyPos === 'before' && el('span', { className: 'bkbg-pc-currency' }, a.currency), |
| 538 |
el('span', { className: 'bkbg-pc-price-val' }, '0'), |
| 539 |
a.currencyPos === 'after' && el('span', { className: 'bkbg-pc-currency' }, a.currency) |
| 540 |
), |
| 541 |
el('p', { className: 'bkbg-pc-price-note', 'data-monthly': a.priceNote, 'data-annual': a.priceNoteAnnual }, a.priceNote) |
| 542 |
), |
| 543 |
el('a', { href: a.ctaUrl, className: 'bkbg-pc-cta-btn', target: a.ctaNewTab ? '_blank' : undefined, rel: a.ctaNewTab ? 'noopener noreferrer' : undefined }, a.ctaLabel) |
| 544 |
) |
| 545 |
) |
| 546 |
); |
| 547 |
} |
| 548 |
}); |
| 549 |
}() ); |
| 550 |
|