import ngModule from '../../module'; import Component from '../../lib/component'; import './style.scss'; /** * Dialog component. * * @property {HTMLElement} body The dialog HTML body * @property {HTMLElement} buttons The dialog HTML buttons */ export default class Dialog extends Component { constructor($element, $scope, $transclude) { super($element, $scope); this.shown = false; this.$element.addClass('vn-dialog'); this.element.addEventListener('mousedown', e => this.onBackgroundMouseDown(e)); if ($transclude) { $transclude($scope.$parent, tClone => { this.body = tClone[0]; }, null, 'body'); $transclude($scope.$parent, tClone => { this.buttons = tClone[0]; }, null, 'buttons'); } } set body(value) { this.element.querySelector('.body').appendChild(value); } set buttons(value) { this.element.querySelector('.buttons').appendChild(value); } /** * Displays the dialog to the user. */ show() { if (this.shown) return; this.shown = true; this.keyDownHandler = e => this.onkeyDown(e); this.document.addEventListener('keydown', this.keyDownHandler); this.element.style.display = 'flex'; this.transitionTimeout = setTimeout(() => this.$element.addClass('shown'), 30); if (this.onOpen) this.onOpen(); let firstFocusable = this.element.querySelector('input, textarea'); if (firstFocusable) firstFocusable.focus(); } /** * Hides the dialog calling the response handler. */ hide() { this.fireResponse(); this.realHide(); } /** * Calls the response handler. * * @param {String} response The response code * @return {Boolean} %true if response was canceled, %false otherwise */ fireResponse(response) { let cancel = false; if (this.onResponse) cancel = this.onResponse({response: response}); return cancel; } realHide() { if (!this.shown) return; this.element.style.display = 'none'; this.document.removeEventListener('keydown', this.keyDownHandler); this.lastEvent = null; this.shown = false; this.transitionTimeout = setTimeout(() => this.$element.removeClass('shown'), 30); } onButtonClick(event) { let buttons = this.element.querySelector('.buttons'); let tplButtons = buttons.querySelector('tpl-buttons'); let node = event.target; while (node.parentNode != tplButtons) { if (node == buttons) return; node = node.parentNode; } let response = node.getAttribute('response'); let cancel = this.fireResponse(response); if (cancel !== false) this.realHide(); } onDialogMouseDown(event) { this.lastEvent = event; } onBackgroundMouseDown(event) { if (event != this.lastEvent) this.hide(); } onkeyDown(event) { if (event.keyCode == 27) // Esc this.hide(); } $onDestroy() { clearTimeout(this.transitionTimeout); } } Dialog.$inject = ['$element', '$scope', '$transclude']; ngModule.component('vnDialog', { template: require('./dialog.html'), transclude: { body: 'tplBody', buttons: '?tplButtons' }, bindings: { onOpen: '&?', onResponse: '&?' }, controller: Dialog });