var Modal = {}; class _modal { /** * Initialize parameters. * @param {object} parameters */ constructor(parameters) { parameters = parameters || {}; if (!parameters.onClose) { parameters.onClose = function () { }; } if (!parameters.onSuccess) { parameters.onSuccess = function () { }; } if (!parameters.onCancel) { parameters.onCancel = function () { }; } this.parameters = parameters; this.onHideCallbacks = []; this.onShowCallbacks = []; } /** * Initialize modal. * @param {string} selector * @param {string} html * @param {function()} onApprove * @param {function()} onDeny * @param {jQuery} $context * @param {function()} onClose * @param {function()} onShow * @return {boolean} */ create(selector, html, onApprove, onDeny, $context, onClose, onShow) { let me = this; this.selector = `.modal.${selector}`; if ($(this.selector).exists()) { return false; } $('body').append(html); this.$modal = $(this.selector); if (Page.Meta.platform == 'desktop') { this.$modal.addClass('desktop'); } else { this.$modal.addClass('mobile'); } let idx = null; if (!$context) { $context = this.parameters.$context || Page.getContext(); if ($context.hasClass('pusher')) { $context = null; } } if ($context) { if (Page.Meta.app == 'ohg_website') { // For some reason the ohg website wigs out if fading the page, // so only fade if $context is a modal. if ($context.hasClass('modal')) { idx = $context.fade('show'); } } else { idx = $context.fade('show'); } } this.bindOnHide(onClose); this.bindOnHide(this.parameters.onClose); this.bindOnShow(onShow); this.$modal.modal({ dimmerSettings: Page.dimmerDefaults || { closable: false, loaderVariation: 'blue elastic' }, transition: 'fade down', closable: false, allowMultiple: true, observeChanges: true, autofocus: false, restoreFocus: false, detachable: true, onApprove: ($button) => { if ($.isFunction(onApprove)) { return onApprove($button, this.form(null, 'get values')); } if ($.isFunction(this.parameters.onSuccess)) { return this.parameters.onSuccess($button, this.form(null, 'get values')); } }, onDeny: ($button) => { if ($.isFunction(onDeny)) { return onDeny($button); } if ($.isFunction(this.parameters.onCancel)) { return this.parameters.onCancel($button); } }, onHidden: function () { $(this).remove(); for (let i = 0; i < me.onHideCallbacks.length; i++) { let onHide = me.onHideCallbacks[i]; if ($.isFunction(onHide)) { onHide(); } } $('.ui.modal').modal('refresh'); if (Page.Meta.app != 'ohg_website') { $('body').css('margin-right', 0); } }, onHide: function () { if (idx) { $context.fade('hide', idx); } }, onShow: () => $('body').popup('hide all'), onVisible: function () { Core.UI.Bind.get( me.$modal, { instance: me } ); me.refresh(); me.bind(); for (let i = 0; i < me.onShowCallbacks.length; i++) { let onShow = me.onShowCallbacks[i]; if ($.isFunction(onShow)) { onShow(); } } // @todo disabled inputs are still focused on modal show. } }); this.$modal.modal('show'); return true; } /** * Run function when modal is closed and hidden. * @param {function()} callback * @param {boolean} allowMultiple */ bindOnHide(callback, allowMultiple) { if (!$.isFunction(callback)) { return; } if (!allowMultiple) { this.onHideCallbacks.filter( function (e) { return e != callback; } ); } this.onHideCallbacks.push(callback); } /** * Run function when modal is shown. * @param {function()} callback * @param {boolean} allowMultiple */ bindOnShow(callback, allowMultiple) { if (!$.isFunction(callback)) { return; } if (!allowMultiple) { this.onShowCallbacks.filter( function (e) { return e != callback; } ); } this.onShowCallbacks.push(callback); } /** * Close modal. * @param {function()} callback */ close(callback) { if (callback) { this.bindOnHide(callback); } if (typeof Mqtt !== typeof undefined) { Mqtt.unsubscribeContext(this.getURI()); } this.$modal.modal('hide'); } /** * Refresh positioning and whatnot of modal. */ refresh() { this.$modal.modal('refresh'); } /** * Apply action to form. * @param {string} formName * @param {string} action * @param {string} value1 * @param {string} value2 */ form(formName, action, value1, value2) { let forms = {}; this.$modal.find('form').each(function () { let $form = $(this); let classes = []; $form[0].classList.forEach(function (className) { classes.push(className); }); classes.splice(0, 2); forms[classes[0]] = $form; }); if (!formName) { formName = Object.keys(forms)[0]; } let $form = forms[formName]; if (action && $form && $form.exists()) { return $form.form(action, value1, value2); } return $form; } /** * Dim modal actions. */ disableButtons() { this.$modal.children('.actions').fade( 'show', { hideLoader: true } ); } /** * Enable modal actions. */ enableButtons() { this.$modal.children('.actions').fade('hide all'); } /** * Disable a specific button. * @param {string} buttonId */ disableButton(buttonId) { this.$modal.children('.actions').children(`.button.${buttonId}`).addClass('disabled'); } /** * Enable a specific button. * @param {string} buttonId */ enableButton(buttonId) { this.$modal.children('.actions').children(`.button.${buttonId}`).removeClass('disabled'); } /** * Get modal URI. * * @return {string} */ getURI() { if (!this.getClassName) { return ''; } let dir = ''; let parts = this.getClassName().split('.'); for (let i = 0; i < parts.length; i++) { dir = `${dir}/${_.kebabCase(parts[i])}`; } return `/api/${Page.Meta.api_version}/${dir}/index.php`; } /** * Trigger modal positive action. */ triggerPositive() { this.$modal.children('.actions').children('.positive.button').trigger('click'); } /** * Trigger modal negative action. */ triggerNegative() { this.$modal.children('.actions').children('.negative.button').trigger('click'); } /** * Subscribe to MQTT topic. * @param {string} topic * @param {function()} callback */ subscribeToMQTTTopic(topic, callback) { if (!this.getClassName) { console.error('No getClassName() method set.'); return; } Mqtt.subscribe( this.getURI(), topic, callback ); } /** * Default modal bind. */ bind() { } /** * Default tab bind. */ bindTab() { } /** * Default table bind. */ bindTable() { } /** * Default tab bind. */ bindRow() { } }