diff --git a/public/js/components/Bootstrap/Alert.js b/public/js/components/Bootstrap/Alert.js new file mode 100644 index 000000000..b261eeaef --- /dev/null +++ b/public/js/components/Bootstrap/Alert.js @@ -0,0 +1,44 @@ +import BsModal from './Modal.js'; + +export default { + components: { + BsModal + }, + mixins: [ + BsModal + ], + props: { + dialogClass: { + type: [String,Array,Object], + default: 'modal-dialog-centered' + }, + /* + * NOTE(chris): + * Hack to expose in "emits" declared events to $props which we use + * in the v-bind directive to forward all events. + * @see: https://github.com/vuejs/core/issues/3432 + */ + onHideBsModal: Function, + onHiddenBsModal: Function, + onHidePreventedBsModal: Function, + onShowBsModal: Function, + onShownBsModal: Function + }, + data: () => ({ + result: true + }), + mounted() { + this.modal = this.$refs.modalContainer.modal; + }, + popup(msg, options) { + return BsModal.popup.bind(this)(msg, options); + }, + template: ` + + + ` +} diff --git a/public/js/components/Bootstrap/Confirm.js b/public/js/components/Bootstrap/Confirm.js new file mode 100644 index 000000000..1c609d457 --- /dev/null +++ b/public/js/components/Bootstrap/Confirm.js @@ -0,0 +1,22 @@ +import BsAlert from './Alert'; + +export default { + mixins: [ + BsAlert + ], + data: () => ({ + result: false + }), + popup(msg, options) { + return BsAlert.popup.bind(this)(msg, options); + }, + template: ` + + + ` +} diff --git a/public/js/components/Bootstrap/Modal.js b/public/js/components/Bootstrap/Modal.js new file mode 100644 index 000000000..c99aabb58 --- /dev/null +++ b/public/js/components/Bootstrap/Modal.js @@ -0,0 +1,103 @@ +export default { + data: () => ({ + modal: null + }), + props: { + backdrop: { + type: [Boolean,String], + default: true, + validator(value) { + return ['static', true, false].includes(value); + } + }, + focus: { + type: Boolean, + default: true + }, + keyboard: { + type: Boolean, + default: true + }, + noCloseBtn: Boolean, + dialogClass: [String,Array,Object] + }, + emits: [ + "hideBsModal", + "hiddenBsModal", + "hidePreventedBsModal", + "showBsModal", + "shownBsModal" + ], + methods: { + dispose() { + return this.modal.dispose(); + }, + handleUpdate() { + return this.modal.handleUpdate(); + }, + hide() { + return this.modal.hide(); + }, + show(relatedTarget) { + return this.modal.show(relatedTarget); + }, + toggle() { + return this.modal.toggle(); + } + }, + mounted() { + this.modal = new bootstrap.Modal(this.$refs.modal, { + backdrop: this.backdrop, + focus: this.focus, + keyboard: this.keyboard + }); + }, + popup(body, options, title, footer) { + const BsModal = this; + return new Promise((resolve,reject) => { + const instance = Vue.createApp({ + setup() { + return () => Vue.h(BsModal, {...{ + class: 'fade' + },...options, ...{ + ref: 'modal', + 'onHidden.bs.modal': instance.unmount + }}, { + title: () => title, + default: () => body, + footer: () => footer + }); + }, + mounted() { + this.$refs.modal.show(); + }, + beforeUnmount() { + if (this.$refs.modal) + this.$refs.modal.result !== false ? resolve(this.$refs.modal.result) : reject(); + }, + unmounted() { + wrapper.parentElement.removeChild(wrapper); + } + }); + const wrapper = document.createElement("div"); + instance.mount(wrapper); + document.body.appendChild(wrapper); + }); + }, + template: `` +} diff --git a/public/js/components/Bootstrap/Prompt.js b/public/js/components/Bootstrap/Prompt.js new file mode 100644 index 000000000..c056d4237 --- /dev/null +++ b/public/js/components/Bootstrap/Prompt.js @@ -0,0 +1,36 @@ +import BsAlert from './Alert'; + +export default { + mixins: [ + BsAlert + ], + props: { + placeholder: String, + default: String + }, + data: () => ({ + value: '', + result: false + }), + created() { + if (this.default) + this.value = this.default; + }, + popup(msg, options) { + if (typeof options === 'string') + options = { default: options }; + return BsAlert.popup.bind(this)(msg, options); + }, + template: ` + + + ` +}