import {module} from '../module'; import './style.css'; directive.$inject = ['vnPopover']; export function directive(vnPopover) { return { restrict: 'A', link: function($scope, $element, $attrs) { $element.on('click', function(event) { vnPopover.showComponent($attrs.vnDialog, $scope, $element); event.preventDefault(); }); } }; } module.directive('vnPopover', directive); export class Popover { constructor($document, $compile, $transitions) { this.document = $document[0]; this.$compile = $compile; this.$transitions = $transitions; this.removeScope = false; this.popOpens = 0; } _init() { this.docMouseDownHandler = e => this.onDocMouseDown(e); this.document.addEventListener('mousedown', this.docMouseDownHandler); this.docKeyDownHandler = e => this.onDocKeyDown(e); this.document.addEventListener('keydown', this.docKeyDownHandler); this.deregisterCallback = this.$transitions.onStart({}, () => this.hideAll()); } _destroy() { this.document.removeEventListener('mousedown', this.docMouseDownHandler); this.document.removeEventListener('keydown', this.docKeyDownHandler); this.docMouseDownHandler = null; this.docKeyDownHandler = null; this.deregisterCallback(); } show(childElement, parent, popoverId) { this.childElement = childElement; let popover = this.document.createElement('div'); this.popOpens++; if (!popoverId) { popoverId = 'popover-' + this.popOpens; popover.id = popoverId; } popover.className = 'vn-popover'; popover.addEventListener('mousedown', e => this.onPopoverMouseDown(e)); popover.appendChild(childElement); this.popover = popover; let style = popover.style; let spacing = 0; let screenMargin = 20; let dblMargin = screenMargin * 2; let width = popover.offsetWidth; let height = popover.offsetHeight; let innerWidth = window.innerWidth; let innerHeight = window.innerHeight; if (width + dblMargin > innerWidth) { width = innerWidth - dblMargin; style.width = width + 'px'; } if (height + dblMargin > innerHeight) { height = innerHeight - dblMargin; style.height = height + 'px'; } if (parent) { let parentNode = parent; let rect = parentNode.getBoundingClientRect(); let left = rect.left; let top = rect.top + spacing + parentNode.offsetHeight; if (left + width > innerWidth) left -= (left + width) - innerWidth + margin; if (top + height > innerHeight) top -= height + parentNode.offsetHeight + spacing * 2; if (left < 0) left = screenMargin; if (top < 0) top = screenMargin; style.top = (top) + 'px'; style.left = (left) + 'px'; style.minWidth = (rect.width) + 'px'; } this.document.body.appendChild(popover); if (this.popOpens === 1) { this._init(); } return popoverId; } showComponent(childComponent, $scope, parent) { let childElement = this.document.createElement(childComponent); let id = 'popover-' + this.popOpens; childElement.id = id; this.removeScope = true; this.$compile(childElement)($scope.$new()); this.show(childElement, parent, id); return childElement; } _checkOpens() { this.popOpens = this.document.querySelectorAll('*[id^="popover-"]').length; if (this.popOpens === 0) { this._destroy(); } } _removeElement(val) { if (!val) return; let element = angular.element(val); let parent = val.parentNode; if (element.scope() && element.scope().$id > 1) { element.scope().$destroy(); } element.remove(); if (parent.className.indexOf('vn-popover') !== -1) this._removeElement(parent); } hide(id) { let popover = this.document.querySelector(`#${id}`); if (popover) { this._removeElement(popover); } this._checkOpens(); } hideChilds(id) { let popovers = this.document.querySelectorAll('*[id^="popover-"]'); let idNumber = parseInt(id.split('-')[1], 10); popovers.forEach( val => { let valId = angular.element(val).attr('id'); if (parseInt(valId.split('-')[1], 10) > idNumber) this._removeElement(val); } ); this._checkOpens(); } hideAll() { let popovers = this.document.querySelectorAll('*[id^="popover-"]'); popovers.forEach( val => { this._removeElement(val); } ); this._checkOpens(); } _findParent(node) { while (node != null) { if ((node.className && node.className.indexOf('vn-popover') !== -1) || (node.id && node.id.indexOf('popover-') !== -1)) { return angular.element(node).attr('id'); } node = node.parentNode; } return null; } onDocMouseDown(event) { let targetId = this._findParent(event.target); if (targetId) { this.hideChilds(targetId); } else { this.hideAll(); } } onDocKeyDown(event) { if (event.keyCode === 27) { let targetId = this._findParent(this.latTarget); if (targetId) { this.hideChilds(targetId); } else { this.hideAll(); } this.latTarget = null; } } onPopoverMouseDown(event) { this.latTarget = event.target; } } Popover.$inject = ['$document', '$compile', '$transitions']; module.service('vnPopover', Popover);