salix/client/core/src/components/popover/popover.js

206 lines
5.9 KiB
JavaScript
Raw Normal View History

2018-02-10 15:18:01 +00:00
import ngModule from '../../module';
2017-02-07 13:34:26 +00:00
import './style.css';
directive.$inject = ['vnPopover'];
2017-06-03 11:01:47 +00:00
export function directive(vnPopover) {
return {
restrict: 'A',
2017-05-16 10:37:48 +00:00
link: function($scope, $element, $attrs) {
$element.on('click', function(event) {
2017-06-03 11:01:47 +00:00
vnPopover.showComponent($attrs.vnDialog, $scope, $element);
event.preventDefault();
});
}
2017-05-16 10:37:48 +00:00
};
}
2018-02-10 15:18:01 +00:00
ngModule.directive('vnPopover', directive);
2017-02-01 09:05:15 +00:00
export class Popover {
constructor($document, $compile, $transitions) {
2017-02-01 09:05:15 +00:00
this.document = $document[0];
this.$compile = $compile;
this.$transitions = $transitions;
this.removeScope = false;
2017-07-05 07:47:24 +00:00
this.popOpens = 0;
2017-02-01 09:05:15 +00:00
}
_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();
}
2017-07-05 07:47:24 +00:00
show(childElement, parent, popoverId) {
this.childElement = childElement;
2017-02-01 09:05:15 +00:00
let popover = this.document.createElement('div');
2017-07-05 07:47:24 +00:00
this.popOpens++;
if (!popoverId) {
popoverId = 'popover-' + this.popOpens;
popover.id = popoverId;
}
2017-02-01 09:05:15 +00:00
popover.className = 'vn-popover';
popover.addEventListener('mousedown',
2017-06-03 11:01:47 +00:00
e => this.onPopoverMouseDown(e));
2017-02-01 09:05:15 +00:00
popover.appendChild(childElement);
this.popover = popover;
2017-02-01 09:05:15 +00:00
let style = popover.style;
2017-02-01 09:05:15 +00:00
let spacing = 0;
let screenMargin = 20;
let dblMargin = screenMargin * 2;
2017-02-01 09:05:15 +00:00
let width = popover.offsetWidth;
let height = popover.offsetHeight;
let innerWidth = window.innerWidth;
let innerHeight = window.innerHeight;
2017-05-16 10:37:48 +00:00
if (width + dblMargin > innerWidth) {
2017-02-01 09:05:15 +00:00
width = innerWidth - dblMargin;
2017-05-16 10:37:48 +00:00
style.width = width + 'px';
2017-02-01 09:05:15 +00:00
}
2017-10-04 14:02:53 +00:00
2017-05-16 10:37:48 +00:00
if (height + dblMargin > innerHeight) {
2017-02-01 09:05:15 +00:00
height = innerHeight - dblMargin;
2017-05-16 10:37:48 +00:00
style.height = height + 'px';
2017-02-01 09:05:15 +00:00
}
2017-05-16 10:37:48 +00:00
if (parent) {
2017-02-01 09:05:15 +00:00
let parentNode = parent;
let rect = parentNode.getBoundingClientRect();
let left = rect.left;
let top = rect.top + spacing + parentNode.offsetHeight;
2017-05-16 10:37:48 +00:00
if (left + width > innerWidth)
2017-02-01 09:05:15 +00:00
left -= (left + width) - innerWidth + margin;
2017-10-04 14:02:53 +00:00
2017-05-16 10:37:48 +00:00
if (top + height > innerHeight)
2017-02-01 09:05:15 +00:00
top -= height + parentNode.offsetHeight + spacing * 2;
2017-05-16 10:37:48 +00:00
if (left < 0)
2017-02-01 09:05:15 +00:00
left = screenMargin;
2017-10-04 14:02:53 +00:00
2017-05-16 10:37:48 +00:00
if (top < 0)
2017-02-01 09:05:15 +00:00
top = screenMargin;
2017-05-16 10:37:48 +00:00
style.top = (top) + 'px';
style.left = (left) + 'px';
style.minWidth = (rect.width) + 'px';
}
2017-02-01 09:05:15 +00:00
this.document.body.appendChild(popover);
2017-06-03 11:01:47 +00:00
2017-07-05 07:47:24 +00:00
if (this.popOpens === 1) {
this._init();
2017-07-05 07:47:24 +00:00
}
return popoverId;
2017-02-01 09:05:15 +00:00
}
2017-10-04 14:02:53 +00:00
2017-02-01 09:05:15 +00:00
showComponent(childComponent, $scope, parent) {
let childElement = this.document.createElement(childComponent);
2017-07-05 07:47:24 +00:00
let id = 'popover-' + this.popOpens;
childElement.id = id;
this.removeScope = true;
this.$compile(childElement)($scope.$new());
2017-07-05 07:47:24 +00:00
this.show(childElement, parent, id);
return childElement;
2017-02-01 09:05:15 +00:00
}
2017-10-04 14:02:53 +00:00
2017-07-05 07:47:24 +00:00
_checkOpens() {
this.popOpens = this.document.querySelectorAll('*[id^="popover-"]').length;
if (this.popOpens === 0) {
this._destroy();
}
2017-02-01 09:05:15 +00:00
}
2017-10-04 14:02:53 +00:00
2017-07-05 07:47:24 +00:00
_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();
}
2017-10-04 14:02:53 +00:00
2017-07-05 12:01:03 +00:00
hideChilds(id) {
2017-07-05 07:47:24 +00:00
let popovers = this.document.querySelectorAll('*[id^="popover-"]');
2017-07-05 12:01:03 +00:00
let idNumber = parseInt(id.split('-')[1], 10);
2017-07-05 07:47:24 +00:00
popovers.forEach(
val => {
2017-07-05 12:41:10 +00:00
if (parseInt(val.id.split('-')[1], 10) > idNumber)
2017-07-05 07:47:24 +00:00
this._removeElement(val);
}
);
this._checkOpens();
}
2017-10-04 14:02:53 +00:00
2017-07-05 07:47:24 +00:00
hideAll() {
let popovers = this.document.querySelectorAll('*[id^="popover-"]');
popovers.forEach(
val => {
this._removeElement(val);
}
);
this._checkOpens();
}
2017-10-04 14:02:53 +00:00
2017-07-05 12:41:10 +00:00
_findPopOver(node) {
2017-07-05 07:47:24 +00:00
while (node != null) {
2017-07-06 07:02:27 +00:00
if (node.id && node.id.startsWith('popover-')) {
2017-07-05 12:41:10 +00:00
return node.id;
2017-07-05 07:47:24 +00:00
}
node = node.parentNode;
}
return null;
}
2017-10-04 14:02:53 +00:00
2017-02-01 09:05:15 +00:00
onDocMouseDown(event) {
2017-07-05 12:41:10 +00:00
let targetId = this._findPopOver(event.target);
2017-07-05 07:47:24 +00:00
if (targetId) {
2017-07-05 12:01:03 +00:00
this.hideChilds(targetId);
2017-07-05 07:47:24 +00:00
} else {
this.hideAll();
}
2017-02-01 09:05:15 +00:00
}
2017-10-04 14:02:53 +00:00
2017-06-03 11:01:47 +00:00
onDocKeyDown(event) {
2017-07-05 07:47:24 +00:00
if (event.keyCode === 27) {
2017-07-05 12:59:40 +00:00
let targetId = this._findPopOver(this.lastTarget);
2017-07-05 07:47:24 +00:00
if (targetId) {
2017-07-05 12:01:03 +00:00
this.hideChilds(targetId);
2017-07-05 07:47:24 +00:00
} else {
this.hideAll();
}
2017-07-05 12:59:40 +00:00
this.lastTarget = null;
2017-07-05 07:47:24 +00:00
}
2017-06-03 11:01:47 +00:00
}
2017-10-04 14:02:53 +00:00
2017-02-01 09:05:15 +00:00
onPopoverMouseDown(event) {
2017-07-05 12:59:40 +00:00
this.lastTarget = event.target;
2017-02-01 09:05:15 +00:00
}
}
Popover.$inject = ['$document', '$compile', '$transitions'];
2017-10-04 14:02:53 +00:00
2018-02-10 15:18:01 +00:00
ngModule.service('vnPopover', Popover);