salix/front/core/components/dialog/index.js

162 lines
4.7 KiB
JavaScript
Raw Normal View History

2019-10-26 23:30:01 +00:00
import ngModule from '../../module';
import Popup from '../popup';
import template from './index.html';
import './style.scss';
/**
* Dialog component that allows to register function handlers for responses. If
* any of the handlers returns false or a promise that resolves to false,
* the dialog closing is cancelled. Also, if promise is returned, the dialog
* will wait until it is resolved by locking itself and displaying a loading
* animation.
2019-10-26 23:30:01 +00:00
*
2019-10-30 15:57:14 +00:00
* @property {Function} onResponse Handler for dialog response
* @property {Function} onAccept Shortcut handler for accept response
* @slot body The dialog HTML body
* @slot buttons The dialog HTML buttons
2019-10-26 23:30:01 +00:00
*/
export default class Dialog extends Popup {
constructor($element, $, $transclude) {
super($element, $, $transclude);
this.fillDefaultSlot(template);
2019-10-26 23:30:01 +00:00
}
2020-03-30 15:30:03 +00:00
/**
* Fills the dialog slots, it is intended to be used by child classes.
*
* @param {String} template The HTML template string
*/
fillSlots(template) {
let $template = angular.element(template);
this.fillSlot('body', $template.find('tpl-body'));
this.fillSlot('buttons', $template.find('tpl-buttons'));
}
2019-10-26 23:30:01 +00:00
/**
2019-10-30 15:57:14 +00:00
* Shows the dialog and optionally registers a handler for the response.
*
* @param {*} data Optional user data to pass to response handler
* @param {Function} responseHandler An optional response handler
* @return {Promise} A promise that will be resolved with response when dialog is closed
*/
show(data, responseHandler) {
2019-11-10 10:08:44 +00:00
if (this.shown)
return this.$q.reject(new Error('Dialog already shown'));
super.show();
2019-10-30 15:57:14 +00:00
if (typeof data == 'function') {
responseHandler = data;
data = null;
}
this.data = data;
this.showHandler = responseHandler;
return this.$q(resolve => {
this.resolve = resolve;
});
}
/**
2019-11-10 10:08:44 +00:00
* Hides the dialog resolving the promise returned by show().
2019-10-30 15:57:14 +00:00
*
* @param {String} response The response
2019-10-26 23:30:01 +00:00
*/
2019-10-30 15:57:14 +00:00
hide(response) {
if (!this.shown) return;
2019-10-26 23:30:01 +00:00
super.hide();
2019-11-10 10:08:44 +00:00
this.showHandler = null;
2019-10-30 15:57:14 +00:00
if (this.resolve)
this.resolve(response);
2019-10-26 23:30:01 +00:00
}
/**
2019-11-10 10:08:44 +00:00
* Calls the response handlers.
2019-10-26 23:30:01 +00:00
*
* @param {String} response The response code
2019-10-30 15:57:14 +00:00
* @return {Boolean} The response handler return
2019-10-26 23:30:01 +00:00
*/
2019-10-30 15:57:14 +00:00
respond(response) {
if (!this.shown)
return this.$q.resolve();
2020-03-30 15:30:03 +00:00
return this.responseHandler(response);
}
2020-03-30 15:30:03 +00:00
/**
* The default response handler, it can be overriden by child classes to
* add custom logic.
*
* @param {String} response The response code
* @return {Boolean} The response handler return
*/
responseHandler(response) {
2019-10-30 15:57:14 +00:00
let handlerArgs = {
$response: response,
$data: this.data
};
let cancellers = [];
2019-10-26 23:30:01 +00:00
if (this.onResponse)
2019-10-30 15:57:14 +00:00
cancellers.push(this.onResponse(handlerArgs));
if (response == 'accept' && this.onAccept)
cancellers.push(this.onAccept(handlerArgs));
if (this.showHandler)
cancellers.push(this.showHandler(response, this.data));
let promises = [];
let resolvedCancellers = [];
for (let canceller of cancellers) {
if (canceller instanceof Object && canceller.then)
promises.push(canceller);
else
resolvedCancellers.push(canceller);
}
let close = () => {
if (resolvedCancellers.indexOf(false) == -1)
this.hide(response);
else
return false;
};
if (promises.length) {
this.loading = true;
return this.$q.all(promises)
.then(res => {
resolvedCancellers = resolvedCancellers.concat(res);
return close();
})
.finally(() => {
this.loading = false;
});
} else
return this.$q.resolve(close());
2019-10-26 23:30:01 +00:00
}
onButtonClick(event) {
let buttons = this.popup.querySelector('.buttons');
let tplButtons = buttons.querySelector('tpl-buttons');
let node = event.target;
while (node.parentNode != tplButtons) {
if (node == buttons) return;
node = node.parentNode;
}
2019-10-30 15:57:14 +00:00
this.respond(node.getAttribute('response'));
2019-10-26 23:30:01 +00:00
}
}
ngModule.vnComponent('vnDialog', {
controller: Dialog,
transclude: {
body: 'tplBody',
buttons: '?tplButtons'
},
bindings: {
2019-10-30 15:57:14 +00:00
onResponse: '&?',
onAccept: '&?'
2019-10-26 23:30:01 +00:00
}
});