UNPKG

waibu-bootstrap

Version:

Bootstrap suport for Waibu Framework

212 lines (197 loc) 8.27 kB
/* global wmpa, _ */ class Wbs { constructor () { this.engine = window.mdb ?? window.bootstrap window.addEventListener('load', evt => { const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]') const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new this.engine.Popover(popoverTriggerEl)) // eslint-disable-line no-unused-vars const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]') const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new this.engine.Tooltip(tooltipTriggerEl)) // eslint-disable-line no-unused-vars const toastElList = document.querySelectorAll('.toast') const toastList = [...toastElList].map(toastEl => new this.engine.Toast(toastEl)) toastList.forEach(toast => toast.show()) }) } getInstance (type, id) { if (type === 'Drawer') type = 'Offcanvas' const el = typeof id === 'string' ? document.getElementById(id) : id return this.engine[type].getOrCreateInstance(el) } notifyHtml (id, html) { wmpa.addComponentHtml(html, { selector: '.toast-container' }) const el = document.getElementById(id) if (!el) return el.addEventListener('hidden.bs.toast', () => { el.remove() }) const instance = this.getInstance('Toast', id) instance.show() } async notify (msg, { title, caption, type = 'info', transValue = [] } = {}) { const id = wmpa.randomId() if (_.isString(transValue)) transValue = [transValue] transValue = transValue.join('|') let body = `<c:toast id="${id}" background="color:${type}" ` if (title) body += `title="${title}" ` if (caption) body += `caption="${caption}" ` body += `><c:t value="${transValue}">${msg}</c:t></c:toast>` await wmpa.addComponent(body, { selector: '.toast-container' }) const el = document.getElementById(id) if (!el) return el.addEventListener('hidden.bs.toast', () => { el.remove() }) const instance = this.getInstance('Toast', id) instance.show() } invalidateForm (evt) { const items = document.querySelectorAll('form .is-invalid') items.forEach(item => { item.classList.remove('is-invalid') }) const feedback = document.querySelectorAll('form .invalid-feedback') feedback.forEach(item => { item.remove() }) evt.target.remove() } async copyToClipboard (selector, isSelector) { await wmpa.copyToClipboard(selector, isSelector) await this.notify('Copied!') } async confirmation (msg, handler, opts = {}) { if (_.isPlainObject(handler)) { opts = handler handler = undefined } opts.icon = 'signQuestion' opts.buttons = [ { label: 'cancel', color: 'secondary', dismiss: true }, { label: 'ok', color: 'primary', dismiss: !opts.ok, alertType: 'confirmation', handler: opts.ok, handlerOpts: opts.opts ?? '', close: opts.close ?? '' } ] return await this.alert(msg, opts.title ?? 'confirmation', opts) } async prompt (msg, value, opts = {}) { if (_.isPlainObject(value)) { opts = value value = undefined } opts.content = [ `<c:form-input x-data="{ submit (evt) { this.$el.closest('.modal-body').querySelector('button[type=submit]').click() } }" @keyup.enter="submit" value="` + (value ?? opts.value) + '"/>', msg ? ('<c:div margin="top-3"><c:t>' + msg + '</c:t></c:div>') : '' ].join('\n') opts.close = opts.close ?? '' opts.buttons = [ { label: 'cancel', color: 'secondary', dismiss: true }, { label: 'ok', type: 'submit', color: 'primary', dismiss: !opts.ok, alertType: 'prompt', handler: opts.ok, handlerOpts: opts.opts ?? '', close: opts.close ?? '' } ] return await this.alert(msg, opts.title ?? 'Prompt', opts) } async appLauncher (params, menu, opts = {}) { document.body.click() const id = wmpa.randomId() const toolbar = params ? `toolbar="${params}"` : '' const menuId = menu ? `menu="${menu}"` : '' const body = [`<c:app-launcher id="${id}" ${toolbar} ${menuId} />`] await wmpa.addComponent(body.join('\n'), { selector: 'body', ...opts }) const item = new this.engine.Offcanvas(`#${id}`) const itemEl = document.getElementById(id) itemEl.addEventListener('hidden.bs.offcanvas', evt => { itemEl.remove() }) item.show() return id } async alert (msg, title, opts = {}) { const id = wmpa.randomId() if (_.isPlainObject(title)) { opts = title title = undefined } let { type = 'info', icon, centered = true, buttons, transValue = [] } = opts if (_.isString(transValue)) transValue = [transValue] transValue = transValue.join('|') buttons = buttons ?? [{ label: 'OK', color: 'primary', dismiss: true }] icon = icon ?? 'sign' + (type.charAt(0).toUpperCase() + type.slice(1)) switch (type) { case 'danger': title = title ?? 'error'; break case 'warning': title = title ?? 'warning'; break default: title = title ?? 'information' } buttons = buttons.map(b => { b.handlerOpts = wmpa.toBase64(JSON.stringify(b.handlerOpts)) let btn = `<c:btn type="${b.type ?? 'button'}" margin="start-2" ${b.id ? `id="${b.id}"` : ''} color="${b.color}" t:content="${b.label}" ` if (b.dismiss) btn += 'dismiss />' else if (b.handler) btn += `x-data @click="wbs.handleAlert('${b.handler}', '${id}', '${b.handlerOpts ?? ''}', '${b.close ?? ''}', '${b.alertType ?? 'alert'}')" />` else btn += '/>' return btn }) const body = [`<c:modal id="${id}" ${centered ? 'centered' : ''} t:title="${title}">`] if (opts.content) body.push(opts.content) else { body.push('<c:div flex="justify-content:between align-items:start">') body.push(`<c:div margin="end-3"><c:icon font="size:1" name="${icon}" /></c:div>`) body.push(`<c:div dim="width:100"><c:t value="${transValue}">${msg}</c:t></c:div>`) body.push('</c:div>') } body.push('<c:div flex="justify-content:end" margin="top-3">') body.push(...buttons) body.push('</c:div></c:modal>') const options = _.pick(opts, ['theme', 'iconset']) await wmpa.addComponent(body.join('\n'), { selector: 'body', ...options }) const modal = new this.engine.Modal(`#${id}`) const modalEl = document.getElementById(id) modalEl.addEventListener('hidden.bs.modal', evt => { modalEl.remove() }) modalEl.addEventListener('shown.bs.modal', evt => { const input = modalEl.querySelector('input') if (input) input.focus() }) modal.show() return id } closeModal (id) { this.getInstance('Modal', id).hide() } handleAlert (name, modalId, opts, close, alertType) { const callFn = (fn) => { let value if (alertType === 'prompt') { value = document.querySelector('#' + modalId + ' input.form-control').value } if (wmpa.isAsync(fn)) fn(modalId, opts, value).then() else fn(modalId, opts, value) } if (close !== '') this.closeModal(modalId) if (name.includes(':')) { const [ns, ...method] = name.split(':') const fn = wmpa.alpineScopeMethod(method.join(':'), '#' + ns) if (fn) callFn(fn) else console.error(`Component method not found: ${name}`) return } const fn = _.get(window, name) if (fn) callFn(fn) else console.error(`Function not found '${name}'`) } async openModal (id, body, opts = {}) { let { type = 'modal' } = opts if (_.isArray(body)) body = body.join('\n') if (!['modal', 'offcanvas'].includes(type)) type = 'modal' const options = _.pick(opts, ['theme', 'iconset']) await wmpa.addComponent(body, { ...options }) const item = new this.engine[_.upperFirst(type)](`#${id}`) const itemEl = document.getElementById(id) itemEl.addEventListener(`hidden.bs.${type}`, evt => { itemEl.remove() }) item.show() return id } } const wbs = new Wbs() // eslint-disable-line no-unused-vars