|
|
@@ -38,6 +38,7 @@
|
|
|
const PREFIX = 'layer-';
|
|
|
const RING_TYPES = new Set(['success', 'error', 'warning', 'info', 'question']);
|
|
|
const RING_BG_PARTS_SELECTOR = `.${PREFIX}success-circular-line-left, .${PREFIX}success-circular-line-right, .${PREFIX}success-fix`;
|
|
|
+ const LOTTIE_PREFIX = 'svg:';
|
|
|
|
|
|
const normalizeOptions = (options, text, icon) => {
|
|
|
if (typeof options !== 'string') return options || {};
|
|
|
@@ -113,6 +114,93 @@
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ // Lottie (svg.js) lazy loader for "svg:*" icon type
|
|
|
+ let _lottieReady = null;
|
|
|
+ let _lottiePrefetchScheduled = false;
|
|
|
+ const isLottieIcon = (icon) => {
|
|
|
+ if (typeof icon !== 'string') return false;
|
|
|
+ const s = icon.trim();
|
|
|
+ return s.startsWith(LOTTIE_PREFIX);
|
|
|
+ };
|
|
|
+ const getLottieIconName = (icon) => {
|
|
|
+ if (!isLottieIcon(icon)) return '';
|
|
|
+ let name = String(icon || '').trim().slice(LOTTIE_PREFIX.length).trim();
|
|
|
+ if (name === 'loadding') name = 'loading';
|
|
|
+ return name;
|
|
|
+ };
|
|
|
+ const getLayerScriptBase = () => {
|
|
|
+ try {
|
|
|
+ if (typeof document === 'undefined') return '';
|
|
|
+ const scripts = Array.from(document.getElementsByTagName('script'));
|
|
|
+ const src = scripts
|
|
|
+ .map((s) => s && s.src)
|
|
|
+ .find((s) => /(^|\/)(xjs|layer)\.js(\?|#|$)/.test(String(s || '')));
|
|
|
+ if (!src) return '';
|
|
|
+ return String(src)
|
|
|
+ .replace(/[#?].*$/, '')
|
|
|
+ .replace(/\/[^\/]*$/, '/');
|
|
|
+ } catch {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const resolveLottieScriptUrl = () => {
|
|
|
+ const base = getLayerScriptBase();
|
|
|
+ return base ? (base + 'svg/svg.js') : 'svg/svg.js';
|
|
|
+ };
|
|
|
+ const resolveLottieJsonUrl = (name) => {
|
|
|
+ const raw = String(name || '').trim();
|
|
|
+ if (!raw) return '';
|
|
|
+ if (/^(https?:)?\/\//.test(raw)) return raw;
|
|
|
+ if (raw.startsWith('/') || raw.startsWith('./') || raw.startsWith('../')) return raw;
|
|
|
+ const base = getLayerScriptBase();
|
|
|
+ const file = raw.endsWith('.json') ? raw : (raw + '.json');
|
|
|
+ return (base ? base : '') + 'svg/' + file;
|
|
|
+ };
|
|
|
+ const ensureLottieLib = () => {
|
|
|
+ try {
|
|
|
+ if (typeof window === 'undefined') return Promise.resolve(null);
|
|
|
+ if (window.lottie) return Promise.resolve(window.lottie);
|
|
|
+ if (typeof document === 'undefined' || !document.head) return Promise.resolve(null);
|
|
|
+ if (_lottieReady) return _lottieReady;
|
|
|
+
|
|
|
+ const existing = document.getElementById('layer-lottie-lib');
|
|
|
+ _lottieReady = new Promise((resolve) => {
|
|
|
+ const finish = () => resolve(window.lottie || null);
|
|
|
+ if (existing) {
|
|
|
+ try { existing.addEventListener('load', finish, { once: true }); } catch {}
|
|
|
+ try { existing.addEventListener('error', finish, { once: true }); } catch {}
|
|
|
+ setTimeout(finish, 1200);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const script = document.createElement('script');
|
|
|
+ script.id = 'layer-lottie-lib';
|
|
|
+ script.async = true;
|
|
|
+ script.src = resolveLottieScriptUrl();
|
|
|
+ try { script.addEventListener('load', finish, { once: true }); } catch {}
|
|
|
+ try { script.addEventListener('error', finish, { once: true }); } catch {}
|
|
|
+ setTimeout(finish, 1800);
|
|
|
+ document.head.appendChild(script);
|
|
|
+ });
|
|
|
+ return _lottieReady;
|
|
|
+ } catch {
|
|
|
+ return Promise.resolve(null);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const scheduleLottiePrefetch = () => {
|
|
|
+ if (_lottiePrefetchScheduled) return;
|
|
|
+ _lottiePrefetchScheduled = true;
|
|
|
+ try {
|
|
|
+ if (typeof window === 'undefined') return;
|
|
|
+ const start = () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ try { ensureLottieLib(); } catch {}
|
|
|
+ }, 0);
|
|
|
+ };
|
|
|
+ if (document.readyState === 'complete') start();
|
|
|
+ else window.addEventListener('load', start, { once: true });
|
|
|
+ } catch {}
|
|
|
+ };
|
|
|
+
|
|
|
class Layer {
|
|
|
constructor() {
|
|
|
this._cssReady = ensureXjsCss();
|
|
|
@@ -223,15 +311,16 @@
|
|
|
text: '',
|
|
|
icon: null,
|
|
|
iconSize: null, // e.g. '6em' / '72px'
|
|
|
+ iconLoop: null, // lottie only: true/false/null (auto)
|
|
|
confirmButtonText: 'OK',
|
|
|
cancelButtonText: 'Cancel',
|
|
|
showCancelButton: false,
|
|
|
- confirmButtonColor: '#3085d6',
|
|
|
- cancelButtonColor: '#aaa',
|
|
|
closeOnClickOutside: true,
|
|
|
closeOnEsc: true,
|
|
|
iconAnimation: true,
|
|
|
popupAnimation: true,
|
|
|
+ nextIcon: null, // flow-only: icon for Next button
|
|
|
+ prevIcon: null, // flow-only: icon for Back button
|
|
|
// Content:
|
|
|
// - text: plain text
|
|
|
// - html: innerHTML
|
|
|
@@ -332,6 +421,7 @@
|
|
|
}
|
|
|
|
|
|
_render(meta = null) {
|
|
|
+ this._destroyLottieIcon();
|
|
|
// Remove existing if any (but first, try to restore any mounted DOM from the previous instance)
|
|
|
const existing = document.querySelector(`.${PREFIX}overlay`);
|
|
|
const wantReplace = !!(this.params && this.params.replace);
|
|
|
@@ -426,15 +516,15 @@
|
|
|
|
|
|
// Cancel Button
|
|
|
if (this.params.showCancelButton) {
|
|
|
- this.dom.cancelBtn = el('button', `${PREFIX}button ${PREFIX}cancel`, this.params.cancelButtonText);
|
|
|
- this.dom.cancelBtn.style.backgroundColor = this.params.cancelButtonColor;
|
|
|
+ this.dom.cancelBtn = el('button', `${PREFIX}button ${PREFIX}cancel`, '');
|
|
|
+ this._setButtonContent(this.dom.cancelBtn, this.params.cancelButtonText);
|
|
|
this.dom.cancelBtn.onclick = () => this._handleCancel();
|
|
|
this.dom.actions.appendChild(this.dom.cancelBtn);
|
|
|
}
|
|
|
|
|
|
// Confirm Button
|
|
|
- this.dom.confirmBtn = el('button', `${PREFIX}button ${PREFIX}confirm`, this.params.confirmButtonText);
|
|
|
- this.dom.confirmBtn.style.backgroundColor = this.params.confirmButtonColor;
|
|
|
+ this.dom.confirmBtn = el('button', `${PREFIX}button ${PREFIX}confirm`, '');
|
|
|
+ this._setButtonContent(this.dom.confirmBtn, this.params.confirmButtonText);
|
|
|
this.dom.confirmBtn.onclick = () => this._handleConfirm();
|
|
|
this.dom.actions.appendChild(this.dom.confirmBtn);
|
|
|
|
|
|
@@ -482,6 +572,7 @@
|
|
|
}
|
|
|
|
|
|
_renderFlowUI() {
|
|
|
+ this._destroyLottieIcon();
|
|
|
// Icon/title/content/actions are stable; steps are pre-mounted and toggled.
|
|
|
const popup = this.dom.popup;
|
|
|
if (!popup) return;
|
|
|
@@ -584,21 +675,27 @@
|
|
|
while (actions.firstChild) actions.removeChild(actions.firstChild);
|
|
|
|
|
|
this.dom.cancelBtn = null;
|
|
|
+ const total = (this._flowSteps && this._flowSteps.length) ? this._flowSteps.length : 0;
|
|
|
+ const isLast = total > 0 ? (this._flowIndex >= (total - 1)) : true;
|
|
|
+
|
|
|
if (this.params.showCancelButton) {
|
|
|
- this.dom.cancelBtn = el('button', `${PREFIX}button ${PREFIX}cancel`, this.params.cancelButtonText);
|
|
|
- this.dom.cancelBtn.style.backgroundColor = this.params.cancelButtonColor;
|
|
|
+ const prevIcon = (this._flowIndex > 0) ? this.params.prevIcon : null;
|
|
|
+ this.dom.cancelBtn = el('button', `${PREFIX}button ${PREFIX}cancel`, '');
|
|
|
+ this._setButtonContent(this.dom.cancelBtn, this.params.cancelButtonText, prevIcon, 'start');
|
|
|
this.dom.cancelBtn.onclick = () => this._handleCancel();
|
|
|
actions.appendChild(this.dom.cancelBtn);
|
|
|
}
|
|
|
|
|
|
- this.dom.confirmBtn = el('button', `${PREFIX}button ${PREFIX}confirm`, this.params.confirmButtonText);
|
|
|
- this.dom.confirmBtn.style.backgroundColor = this.params.confirmButtonColor;
|
|
|
+ const nextIcon = (!isLast) ? this.params.nextIcon : null;
|
|
|
+ this.dom.confirmBtn = el('button', `${PREFIX}button ${PREFIX}confirm`, '');
|
|
|
+ this._setButtonContent(this.dom.confirmBtn, this.params.confirmButtonText, nextIcon, 'end');
|
|
|
this.dom.confirmBtn.onclick = () => this._handleConfirm();
|
|
|
actions.appendChild(this.dom.confirmBtn);
|
|
|
}
|
|
|
|
|
|
_createIcon(type) {
|
|
|
- const icon = el('div', `${PREFIX}icon ${type}`);
|
|
|
+ const rawType = String(type || '').trim();
|
|
|
+ const icon = el('div', `${PREFIX}icon ${rawType}`);
|
|
|
const applyIconSize = (mode) => {
|
|
|
if (!(this.params && this.params.iconSize)) return;
|
|
|
try {
|
|
|
@@ -659,22 +756,35 @@
|
|
|
};
|
|
|
|
|
|
const appendBuiltInInnerMark = (svg) => {
|
|
|
- if (type === 'error') {
|
|
|
+ if (rawType === 'error') {
|
|
|
addMarkPath(svg, 'M28 28 L52 52', `${PREFIX}svg-error-left`);
|
|
|
addMarkPath(svg, 'M52 28 L28 52', `${PREFIX}svg-error-right`);
|
|
|
- } else if (type === 'warning') {
|
|
|
+ } else if (rawType === 'warning') {
|
|
|
addMarkPath(svg, 'M40 20 L40 46', `${PREFIX}svg-warning-line`);
|
|
|
addDot(svg, 40, 58);
|
|
|
- } else if (type === 'info') {
|
|
|
+ } else if (rawType === 'info') {
|
|
|
addMarkPath(svg, 'M40 34 L40 56', `${PREFIX}svg-info-line`);
|
|
|
addDot(svg, 40, 25);
|
|
|
- } else if (type === 'question') {
|
|
|
+ } else if (rawType === 'question') {
|
|
|
addMarkPath(svg, 'M30 30 C30 23 35 19 42 19 C49 19 54 23 54 30 C54 36 50 39 46 41 C43 42 42 44 42 48 L42 52', `${PREFIX}svg-question`);
|
|
|
addDot(svg, 42, 61);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- if (type === 'success') {
|
|
|
+ if (isLottieIcon(rawType)) {
|
|
|
+ // Lottie animation icon: svg:<name>
|
|
|
+ const name = getLottieIconName(rawType);
|
|
|
+ icon.className = `${PREFIX}icon ${PREFIX}icon-lottie`;
|
|
|
+ icon.dataset.lottie = name;
|
|
|
+ const container = el('div', `${PREFIX}lottie`);
|
|
|
+ icon.appendChild(container);
|
|
|
+ applyIconSize('box');
|
|
|
+ scheduleLottiePrefetch();
|
|
|
+ this._initLottieIcon(icon, name);
|
|
|
+ return icon;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rawType === 'success') {
|
|
|
// SweetAlert2-compatible DOM structure (circle + tick) for exact style parity
|
|
|
// <div class="...success-circular-line-left"></div>
|
|
|
// <div class="...success-mark"><span class="...success-line-tip"></span><span class="...success-line-long"></span></div>
|
|
|
@@ -694,7 +804,7 @@
|
|
|
return icon;
|
|
|
}
|
|
|
|
|
|
- if (type === 'error' || type === 'warning' || type === 'info' || type === 'question') {
|
|
|
+ if (rawType === 'error' || rawType === 'warning' || rawType === 'info' || rawType === 'question') {
|
|
|
// Use the same "success-like" ring parts for every icon
|
|
|
appendRingParts();
|
|
|
|
|
|
@@ -847,6 +957,7 @@
|
|
|
const icon = this.dom.icon;
|
|
|
if (!icon) return;
|
|
|
const type = (this.params && this.params.icon) || '';
|
|
|
+ if (isLottieIcon(type)) return;
|
|
|
|
|
|
// Ring animation (same as success) for all built-in icons
|
|
|
if (RING_TYPES.has(type)) this._adjustRingBackgroundColor();
|
|
|
@@ -902,6 +1013,7 @@
|
|
|
}
|
|
|
|
|
|
_forceDestroy(reason = 'replace') {
|
|
|
+ try { this._destroyLottieIcon(); } catch {}
|
|
|
// Restore mounted DOM (if any) and cleanup listeners; also resolve the promise so it doesn't hang.
|
|
|
try {
|
|
|
if (this._flowSteps && this._flowSteps.length) this._unmountFlowMounted();
|
|
|
@@ -921,6 +1033,7 @@
|
|
|
_close(isConfirmed, reason) {
|
|
|
if (this._isClosing) return;
|
|
|
this._isClosing = true;
|
|
|
+ try { this._destroyLottieIcon(); } catch {}
|
|
|
|
|
|
const shouldDelayUnmount = !!(
|
|
|
(this._mounted && this._mounted.kind === 'move') ||
|
|
|
@@ -1248,6 +1361,46 @@
|
|
|
} catch {}
|
|
|
}
|
|
|
|
|
|
+ _normalizeButtonIcon(icon) {
|
|
|
+ if (!icon) return null;
|
|
|
+ try {
|
|
|
+ if (icon && icon.nodeType) return icon.cloneNode(true);
|
|
|
+ } catch {}
|
|
|
+ if (typeof icon === 'string') {
|
|
|
+ const s = icon.trim();
|
|
|
+ if (!s) return null;
|
|
|
+ if (s.indexOf('<') !== -1 && s.indexOf('>') !== -1) {
|
|
|
+ const wrap = document.createElement('span');
|
|
|
+ wrap.innerHTML = s;
|
|
|
+ return wrap;
|
|
|
+ }
|
|
|
+ return document.createTextNode(s);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ _setButtonContent(btn, text, icon, iconPosition) {
|
|
|
+ if (!btn) return;
|
|
|
+ const labelText = (text === undefined || text === null) ? '' : String(text);
|
|
|
+ if (!icon) {
|
|
|
+ try { btn.textContent = labelText; } catch {}
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ while (btn.firstChild) btn.removeChild(btn.firstChild);
|
|
|
+ const iconNode = this._normalizeButtonIcon(icon);
|
|
|
+ const iconWrap = el('span', `${PREFIX}btn-icon`);
|
|
|
+ if (iconNode) iconWrap.appendChild(iconNode);
|
|
|
+ const label = el('span', `${PREFIX}btn-label`, labelText);
|
|
|
+ const atEnd = iconPosition === 'end';
|
|
|
+ if (atEnd) {
|
|
|
+ btn.appendChild(label);
|
|
|
+ btn.appendChild(iconWrap);
|
|
|
+ } else {
|
|
|
+ btn.appendChild(iconWrap);
|
|
|
+ btn.appendChild(label);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
async _handleConfirm() {
|
|
|
// Flow next / finalize
|
|
|
if (this._flowSteps && this._flowSteps.length) {
|
|
|
@@ -1430,12 +1583,16 @@
|
|
|
try {
|
|
|
const wantsIcon = !!this.params.icon;
|
|
|
if (!wantsIcon && this.dom.icon) {
|
|
|
+ this._destroyLottieIcon();
|
|
|
this.dom.icon.remove();
|
|
|
this.dom.icon = null;
|
|
|
} else if (wantsIcon) {
|
|
|
- const curType = this.dom.icon ? (Array.from(this.dom.icon.classList).find(c => c !== `${PREFIX}icon`) || '') : '';
|
|
|
- if (!this.dom.icon || !this.dom.icon.classList.contains(String(this.params.icon))) {
|
|
|
- if (this.dom.icon) this.dom.icon.remove();
|
|
|
+ const same = this._isSameIconType(this.dom.icon, this.params.icon);
|
|
|
+ if (!this.dom.icon || !same) {
|
|
|
+ if (this.dom.icon) {
|
|
|
+ this._destroyLottieIcon();
|
|
|
+ this.dom.icon.remove();
|
|
|
+ }
|
|
|
this.dom.icon = this._createIcon(this.params.icon);
|
|
|
// icon should be on top (before title)
|
|
|
popup.insertBefore(this.dom.icon, this.dom.title || popup.firstChild);
|
|
|
@@ -1534,7 +1691,113 @@
|
|
|
try { this._adjustRingBackgroundColor(); } catch {}
|
|
|
}
|
|
|
|
|
|
+ _isSameIconType(iconEl, type) {
|
|
|
+ if (!iconEl) return false;
|
|
|
+ const raw = String(type || '').trim();
|
|
|
+ if (isLottieIcon(raw)) {
|
|
|
+ const name = getLottieIconName(raw);
|
|
|
+ return iconEl.dataset && iconEl.dataset.lottie === name;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return iconEl.classList && iconEl.classList.contains(raw);
|
|
|
+ } catch {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _destroyLottieIcon() {
|
|
|
+ const icon = this.dom && this.dom.icon;
|
|
|
+ if (!icon) return;
|
|
|
+ const inst = icon._lottieInstance;
|
|
|
+ if (inst && typeof inst.destroy === 'function') {
|
|
|
+ try { inst.destroy(); } catch {}
|
|
|
+ }
|
|
|
+ try { icon._lottieInstance = null; } catch {}
|
|
|
+ }
|
|
|
+
|
|
|
+ _initLottieIcon(iconEl, name) {
|
|
|
+ if (!iconEl) return;
|
|
|
+ const container = iconEl.querySelector(`.${PREFIX}lottie`);
|
|
|
+ if (!container) return;
|
|
|
+ const cleanName = String(name || '').trim();
|
|
|
+ if (!cleanName) return;
|
|
|
+
|
|
|
+ const url = resolveLottieJsonUrl(cleanName);
|
|
|
+ if (!url) return;
|
|
|
+
|
|
|
+ const wantsLoop = (this.params && typeof this.params.iconLoop === 'boolean')
|
|
|
+ ? this.params.iconLoop
|
|
|
+ : true;
|
|
|
+ const wantsAutoplay = !(this.params && this.params.iconAnimation === false);
|
|
|
+
|
|
|
+ const showError = (msg) => {
|
|
|
+ try {
|
|
|
+ container.textContent = String(msg || '');
|
|
|
+ container.classList.add(`${PREFIX}lottie-error`);
|
|
|
+ } catch {}
|
|
|
+ };
|
|
|
+
|
|
|
+ const loadData = () => new Promise((resolve, reject) => {
|
|
|
+ try {
|
|
|
+ if (typeof fetch === 'function') {
|
|
|
+ fetch(url).then((res) => {
|
|
|
+ if (!res || !res.ok) throw new Error('fetch failed');
|
|
|
+ return res.json();
|
|
|
+ }).then(resolve).catch(reject);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const xhr = new XMLHttpRequest();
|
|
|
+ xhr.open('GET', url, true);
|
|
|
+ xhr.responseType = 'json';
|
|
|
+ xhr.onload = () => {
|
|
|
+ if (xhr.status >= 200 && xhr.status < 300) {
|
|
|
+ const data = xhr.response || (xhr.responseText ? JSON.parse(xhr.responseText) : null);
|
|
|
+ resolve(data);
|
|
|
+ } else {
|
|
|
+ reject(new Error('xhr failed'));
|
|
|
+ }
|
|
|
+ };
|
|
|
+ xhr.onerror = () => reject(new Error('xhr error'));
|
|
|
+ xhr.send();
|
|
|
+ } catch (e) {
|
|
|
+ reject(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ (async () => {
|
|
|
+ const lottie = await ensureLottieLib();
|
|
|
+ if (!lottie) {
|
|
|
+ showError('Lottie lib not loaded.');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!iconEl.isConnected) return;
|
|
|
+ let data = null;
|
|
|
+ try { data = await loadData(); } catch {}
|
|
|
+ if (!data) {
|
|
|
+ showError('Failed to load animation.');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!iconEl.isConnected) return;
|
|
|
+ try {
|
|
|
+ const anim = lottie.loadAnimation({
|
|
|
+ container,
|
|
|
+ renderer: 'svg',
|
|
|
+ loop: wantsLoop,
|
|
|
+ autoplay: wantsAutoplay,
|
|
|
+ animationData: data
|
|
|
+ });
|
|
|
+ iconEl._lottieInstance = anim;
|
|
|
+ if (!wantsAutoplay && anim && typeof anim.goToAndStop === 'function') {
|
|
|
+ anim.goToAndStop(0, true);
|
|
|
+ }
|
|
|
+ } catch {
|
|
|
+ showError('Failed to init animation.');
|
|
|
+ }
|
|
|
+ })();
|
|
|
+ }
|
|
|
+
|
|
|
_rerenderInside() {
|
|
|
+ this._destroyLottieIcon();
|
|
|
// Update popup content without recreating overlay (used in flow transitions)
|
|
|
const popup = this.dom && this.dom.popup;
|
|
|
if (!popup) return;
|
|
|
@@ -1571,14 +1834,14 @@
|
|
|
this.dom.actions = el('div', `${PREFIX}actions`);
|
|
|
this.dom.cancelBtn = null;
|
|
|
if (this.params.showCancelButton) {
|
|
|
- this.dom.cancelBtn = el('button', `${PREFIX}button ${PREFIX}cancel`, this.params.cancelButtonText);
|
|
|
- this.dom.cancelBtn.style.backgroundColor = this.params.cancelButtonColor;
|
|
|
+ this.dom.cancelBtn = el('button', `${PREFIX}button ${PREFIX}cancel`, '');
|
|
|
+ this._setButtonContent(this.dom.cancelBtn, this.params.cancelButtonText);
|
|
|
this.dom.cancelBtn.onclick = () => this._handleCancel();
|
|
|
this.dom.actions.appendChild(this.dom.cancelBtn);
|
|
|
}
|
|
|
|
|
|
- this.dom.confirmBtn = el('button', `${PREFIX}button ${PREFIX}confirm`, this.params.confirmButtonText);
|
|
|
- this.dom.confirmBtn.style.backgroundColor = this.params.confirmButtonColor;
|
|
|
+ this.dom.confirmBtn = el('button', `${PREFIX}button ${PREFIX}confirm`, '');
|
|
|
+ this._setButtonContent(this.dom.confirmBtn, this.params.confirmButtonText);
|
|
|
this.dom.confirmBtn.onclick = () => this._handleConfirm();
|
|
|
this.dom.actions.appendChild(this.dom.confirmBtn);
|
|
|
|