You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
494 lines
20 KiB
494 lines
20 KiB
// Copyright (c) MudBlazor 2021
|
|
// MudBlazor licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
window.mudpopoverHelper = {
|
|
|
|
calculatePopoverPosition: function (list, boundingRect, selfRect) {
|
|
let top = 0;
|
|
let left = 0;
|
|
if (list.indexOf('mud-popover-anchor-top-left') >= 0) {
|
|
left = boundingRect.left;
|
|
top = boundingRect.top;
|
|
} else if (list.indexOf('mud-popover-anchor-top-center') >= 0) {
|
|
left = boundingRect.left + boundingRect.width / 2;
|
|
top = boundingRect.top;
|
|
} else if (list.indexOf('mud-popover-anchor-top-right') >= 0) {
|
|
left = boundingRect.left + boundingRect.width;
|
|
top = boundingRect.top;
|
|
|
|
} else if (list.indexOf('mud-popover-anchor-center-left') >= 0) {
|
|
left = boundingRect.left;
|
|
top = boundingRect.top + boundingRect.height / 2;
|
|
} else if (list.indexOf('mud-popover-anchor-center-center') >= 0) {
|
|
left = boundingRect.left + boundingRect.width / 2;
|
|
top = boundingRect.top + boundingRect.height / 2;
|
|
} else if (list.indexOf('mud-popover-anchor-center-right') >= 0) {
|
|
left = boundingRect.left + boundingRect.width;
|
|
top = boundingRect.top + boundingRect.height / 2;
|
|
|
|
} else if (list.indexOf('mud-popover-anchor-bottom-left') >= 0) {
|
|
left = boundingRect.left;
|
|
top = boundingRect.top + boundingRect.height;
|
|
} else if (list.indexOf('mud-popover-anchor-bottom-center') >= 0) {
|
|
left = boundingRect.left + boundingRect.width / 2;
|
|
top = boundingRect.top + boundingRect.height;
|
|
} else if (list.indexOf('mud-popover-anchor-bottom-right') >= 0) {
|
|
left = boundingRect.left + boundingRect.width;
|
|
top = boundingRect.top + boundingRect.height;
|
|
}
|
|
|
|
let offsetX = 0;
|
|
let offsetY = 0;
|
|
|
|
if (list.indexOf('mud-popover-top-left') >= 0) {
|
|
offsetX = 0;
|
|
offsetY = 0;
|
|
} else if (list.indexOf('mud-popover-top-center') >= 0) {
|
|
offsetX = -selfRect.width / 2;
|
|
offsetY = 0;
|
|
} else if (list.indexOf('mud-popover-top-right') >= 0) {
|
|
offsetX = -selfRect.width;
|
|
offsetY = 0;
|
|
}
|
|
|
|
else if (list.indexOf('mud-popover-center-left') >= 0) {
|
|
offsetX = 0;
|
|
offsetY = -selfRect.height / 2;
|
|
} else if (list.indexOf('mud-popover-center-center') >= 0) {
|
|
offsetX = -selfRect.width / 2;
|
|
offsetY = -selfRect.height / 2;
|
|
} else if (list.indexOf('mud-popover-center-right') >= 0) {
|
|
offsetX = -selfRect.width;
|
|
offsetY = -selfRect.height / 2;
|
|
}
|
|
|
|
else if (list.indexOf('mud-popover-bottom-left') >= 0) {
|
|
offsetX = 0;
|
|
offsetY = -selfRect.height;
|
|
} else if (list.indexOf('mud-popover-bottom-center') >= 0) {
|
|
offsetX = -selfRect.width / 2;
|
|
offsetY = -selfRect.height;
|
|
} else if (list.indexOf('mud-popover-bottom-right') >= 0) {
|
|
offsetX = -selfRect.width;
|
|
offsetY = -selfRect.height;
|
|
}
|
|
|
|
return {
|
|
top: top, left: left, offsetX: offsetX, offsetY: offsetY
|
|
};
|
|
},
|
|
|
|
flipClassReplacements: {
|
|
'top': {
|
|
'mud-popover-top-left': 'mud-popover-bottom-left',
|
|
'mud-popover-top-center': 'mud-popover-bottom-center',
|
|
'mud-popover-anchor-bottom-center': 'mud-popover-anchor-top-center',
|
|
'mud-popover-top-right': 'mud-popover-bottom-right',
|
|
},
|
|
'left': {
|
|
'mud-popover-top-left': 'mud-popover-top-right',
|
|
'mud-popover-center-left': 'mud-popover-center-right',
|
|
'mud-popover-anchor-center-right': 'mud-popover-anchor-center-left',
|
|
'mud-popover-bottom-left': 'mud-popover-bottom-right',
|
|
},
|
|
'right': {
|
|
'mud-popover-top-right': 'mud-popover-top-left',
|
|
'mud-popover-center-right': 'mud-popover-center-left',
|
|
'mud-popover-anchor-center-left': 'mud-popover-anchor-center-right',
|
|
'mud-popover-bottom-right': 'mud-popover-bottom-left',
|
|
},
|
|
'bottom': {
|
|
'mud-popover-bottom-left': 'mud-popover-top-left',
|
|
'mud-popover-bottom-center': 'mud-popover-top-center',
|
|
'mud-popover-anchor-top-center': 'mud-popover-anchor-bottom-center',
|
|
'mud-popover-bottom-right': 'mud-popover-top-right',
|
|
},
|
|
'top-and-left': {
|
|
'mud-popover-top-left': 'mud-popover-bottom-right',
|
|
},
|
|
'top-and-right': {
|
|
'mud-popover-top-right': 'mud-popover-bottom-left',
|
|
},
|
|
'bottom-and-left': {
|
|
'mud-popover-bottom-left': 'mud-popover-top-right',
|
|
},
|
|
'bottom-and-right': {
|
|
'mud-popover-bottom-right': 'mud-popover-top-left',
|
|
},
|
|
|
|
},
|
|
|
|
flipMargin: 0,
|
|
|
|
getPositionForFlippedPopver: function (inputArray, selector, boundingRect, selfRect) {
|
|
const classList = [];
|
|
for (var i = 0; i < inputArray.length; i++) {
|
|
const item = inputArray[i];
|
|
const replacments = window.mudpopoverHelper.flipClassReplacements[selector][item];
|
|
if (replacments) {
|
|
classList.push(replacments);
|
|
}
|
|
else {
|
|
classList.push(item);
|
|
}
|
|
}
|
|
|
|
return window.mudpopoverHelper.calculatePopoverPosition(classList, boundingRect, selfRect);
|
|
},
|
|
|
|
placePopover: function (popoverNode, classSelector) {
|
|
|
|
if (popoverNode && popoverNode.parentNode) {
|
|
const id = popoverNode.id.substr(8);
|
|
const popoverContentNode = document.getElementById('popovercontent-' + id);
|
|
if (popoverContentNode.classList.contains('mud-popover-open') == false) {
|
|
return;
|
|
}
|
|
|
|
if (!popoverContentNode) {
|
|
return;
|
|
}
|
|
|
|
if (classSelector) {
|
|
if (popoverContentNode.classList.contains(classSelector) == false) {
|
|
return;
|
|
}
|
|
}
|
|
const boundingRect = popoverNode.parentNode.getBoundingClientRect();
|
|
|
|
if (popoverContentNode.classList.contains('mud-popover-relative-width')) {
|
|
popoverContentNode.style['max-width'] = (boundingRect.width) + 'px';
|
|
}
|
|
|
|
const selfRect = popoverContentNode.getBoundingClientRect();
|
|
const classList = popoverContentNode.classList;
|
|
const classListArray = Array.from(popoverContentNode.classList);
|
|
|
|
const postion = window.mudpopoverHelper.calculatePopoverPosition(classListArray, boundingRect, selfRect);
|
|
let left = postion.left;
|
|
let top = postion.top;
|
|
let offsetX = postion.offsetX;
|
|
let offsetY = postion.offsetY;
|
|
|
|
if (classList.contains('mud-popover-overflow-flip-onopen') || classList.contains('mud-popover-overflow-flip-always')) {
|
|
|
|
const appBarElements = document.getElementsByClassName("mud-appbar mud-appbar-fixed-top");
|
|
let appBarOffset = 0;
|
|
if (appBarElements.length > 0) {
|
|
appBarOffset = appBarElements[0].getBoundingClientRect().height;
|
|
}
|
|
|
|
const graceMargin = window.mudpopoverHelper.flipMargin;
|
|
const deltaToLeft = left + offsetX;
|
|
const deltaToRight = window.innerWidth - left - selfRect.width;
|
|
const deltaTop = top - selfRect.height - appBarOffset;
|
|
const spaceToTop = top - appBarOffset;
|
|
const deltaBottom = window.innerHeight - top - selfRect.height;
|
|
//console.log('self-width: ' + selfRect.width + ' | self-height: ' + selfRect.height);
|
|
//console.log('left: ' + deltaToLeft + ' | rigth:' + deltaToRight + ' | top: ' + deltaTop + ' | bottom: ' + deltaBottom + ' | spaceToTop: ' + spaceToTop);
|
|
|
|
let selector = popoverContentNode.mudPopoverFliped;
|
|
|
|
if (!selector) {
|
|
if (classList.contains('mud-popover-top-left')) {
|
|
if (deltaBottom < graceMargin && deltaToRight < graceMargin && spaceToTop >= selfRect.height && deltaToLeft >= selfRect.width) {
|
|
selector = 'top-and-left';
|
|
} else if (deltaBottom < graceMargin && spaceToTop >= selfRect.height) {
|
|
selector = 'top';
|
|
} else if (deltaToRight < graceMargin && deltaToLeft >= selfRect.width) {
|
|
selector = 'left';
|
|
}
|
|
} else if (classList.contains('mud-popover-top-center')) {
|
|
if (deltaBottom < graceMargin && spaceToTop >= selfRect.height) {
|
|
selector = 'top';
|
|
}
|
|
} else if (classList.contains('mud-popover-top-right')) {
|
|
if (deltaBottom < graceMargin && deltaToLeft < graceMargin && spaceToTop >= selfRect.height && deltaToRight >= selfRect.width) {
|
|
selector = 'top-and-right';
|
|
} else if (deltaBottom < graceMargin && spaceToTop >= selfRect.height) {
|
|
selector = 'top';
|
|
} else if (deltaToLeft < graceMargin && deltaToRight >= selfRect.width) {
|
|
selector = 'right';
|
|
}
|
|
}
|
|
|
|
else if (classList.contains('mud-popover-center-left')) {
|
|
if (deltaToRight < graceMargin && deltaToLeft >= selfRect.width) {
|
|
selector = 'left';
|
|
}
|
|
}
|
|
else if (classList.contains('mud-popover-center-right')) {
|
|
if (deltaToLeft < graceMargin && deltaToRight >= selfRect.width) {
|
|
selector = 'right';
|
|
}
|
|
}
|
|
else if (classList.contains('mud-popover-bottom-left')) {
|
|
if (deltaTop < graceMargin && deltaToRight < graceMargin && deltaBottom >= 0 && deltaToLeft >= selfRect.width) {
|
|
selector = 'bottom-and-left';
|
|
} else if (deltaTop < graceMargin && deltaBottom >= 0) {
|
|
selector = 'bottom';
|
|
} else if (deltaToRight < graceMargin && deltaToLeft >= selfRect.width) {
|
|
selector = 'left';
|
|
}
|
|
} else if (classList.contains('mud-popover-bottom-center')) {
|
|
if (deltaTop < graceMargin && deltaBottom >= 0) {
|
|
selector = 'bottom';
|
|
}
|
|
} else if (classList.contains('mud-popover-bottom-right')) {
|
|
if (deltaTop < graceMargin && deltaToLeft < graceMargin && deltaBottom >= 0 && deltaToRight >= selfRect.width) {
|
|
selector = 'bottom-and-right';
|
|
} else if (deltaTop < graceMargin && deltaBottom >= 0) {
|
|
selector = 'bottom';
|
|
} else if (deltaToLeft < graceMargin && deltaToRight >= selfRect.width) {
|
|
selector = 'right';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selector && selector != 'none') {
|
|
const newPosition = window.mudpopoverHelper.getPositionForFlippedPopver(classListArray, selector, boundingRect, selfRect);
|
|
left = newPosition.left;
|
|
top = newPosition.top;
|
|
offsetX = newPosition.offsetX;
|
|
offsetY = newPosition.offsetY;
|
|
|
|
popoverContentNode.setAttribute('data-mudpopover-flip', 'flipped');
|
|
}
|
|
else {
|
|
popoverContentNode.removeAttribute('data-mudpopover-flip');
|
|
}
|
|
|
|
if (classList.contains('mud-popover-overflow-flip-onopen')) {
|
|
if (!popoverContentNode.mudPopoverFliped) {
|
|
popoverContentNode.mudPopoverFliped = selector || 'none';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (popoverContentNode.classList.contains('mud-popover-fixed')) {
|
|
}
|
|
else if (window.getComputedStyle(popoverNode).position == 'fixed') {
|
|
popoverContentNode.style['position'] = 'fixed';
|
|
}
|
|
else {
|
|
offsetX += window.scrollX;
|
|
offsetY += window.scrollY
|
|
}
|
|
|
|
popoverContentNode.style['left'] = (left + offsetX) + 'px';
|
|
popoverContentNode.style['top'] = (top + offsetY) + 'px';
|
|
|
|
if (window.getComputedStyle(popoverNode).getPropertyValue('z-index') != 'auto') {
|
|
popoverContentNode.style['z-index'] = window.getComputedStyle(popoverNode).getPropertyValue('z-index');
|
|
popoverContentNode.skipZIndex = true;
|
|
}
|
|
}
|
|
},
|
|
|
|
placePopoverByClassSelector: function (classSelector = null) {
|
|
var items = window.mudPopover.getAllObservedContainers();
|
|
|
|
for (let i = 0; i < items.length; i++) {
|
|
const popoverNode = document.getElementById('popover-' + items[i]);
|
|
window.mudpopoverHelper.placePopover(popoverNode, classSelector);
|
|
}
|
|
},
|
|
|
|
placePopoverByNode: function (target) {
|
|
const id = target.id.substr(15);
|
|
const popoverNode = document.getElementById('popover-' + id);
|
|
window.mudpopoverHelper.placePopover(popoverNode);
|
|
},
|
|
|
|
countProviders: function () {
|
|
return document.querySelectorAll(".mud-popover-provider").length;
|
|
}
|
|
}
|
|
|
|
class MudPopover {
|
|
|
|
constructor() {
|
|
this.map = {};
|
|
this.contentObserver = null;
|
|
this.mainContainerClass = null;
|
|
}
|
|
|
|
callback(id, mutationsList, observer) {
|
|
for (const mutation of mutationsList) {
|
|
if (mutation.type === 'attributes') {
|
|
const target = mutation.target
|
|
if (mutation.attributeName == 'class') {
|
|
if (target.classList.contains('mud-popover-overflow-flip-onopen') &&
|
|
target.classList.contains('mud-popover-open') == false) {
|
|
target.mudPopoverFliped = null;
|
|
target.removeAttribute('data-mudpopover-flip');
|
|
}
|
|
|
|
window.mudpopoverHelper.placePopoverByNode(target);
|
|
}
|
|
else if (mutation.attributeName == 'data-ticks') {
|
|
const tickAttribute = target.getAttribute('data-ticks');
|
|
|
|
const parent = target.parentElement;
|
|
const tickValues = [];
|
|
let max = -1;
|
|
for (let i = 0; i < parent.children.length; i++) {
|
|
const childNode = parent.children[i];
|
|
const tickValue = parseInt(childNode.getAttribute('data-ticks'));
|
|
if (tickValue == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (tickValues.indexOf(tickValue) >= 0) {
|
|
continue;
|
|
}
|
|
|
|
tickValues.push(tickValue);
|
|
|
|
if (tickValue > max) {
|
|
max = tickValue;
|
|
}
|
|
}
|
|
|
|
if (tickValues.length == 0) {
|
|
continue;
|
|
}
|
|
|
|
const sortedTickValues = tickValues.sort((x, y) => x - y);
|
|
|
|
for (let i = 0; i < parent.children.length; i++) {
|
|
const childNode = parent.children[i];
|
|
const tickValue = parseInt(childNode.getAttribute('data-ticks'));
|
|
if (tickValue == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (childNode.skipZIndex == true) {
|
|
continue;
|
|
}
|
|
|
|
childNode.style['z-index'] = 'calc(var(--mud-zindex-popover) + ' + (sortedTickValues.indexOf(tickValue) + 3).toString() + ')';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
initialize(containerClass, flipMargin) {
|
|
const mainContent = document.getElementsByClassName(containerClass);
|
|
if (mainContent.length == 0) {
|
|
return;
|
|
}
|
|
|
|
if (flipMargin) {
|
|
window.mudpopoverHelper.flipMargin = flipMargin;
|
|
}
|
|
|
|
this.mainContainerClass = containerClass;
|
|
|
|
if (!mainContent[0].mudPopoverMark) {
|
|
mainContent[0].mudPopoverMark = "mudded";
|
|
if (this.contentObserver != null) {
|
|
this.contentObserver.disconnect();
|
|
this.contentObserver = null;
|
|
}
|
|
|
|
this.contentObserver = new ResizeObserver(entries => {
|
|
window.mudpopoverHelper.placePopoverByClassSelector();
|
|
});
|
|
|
|
this.contentObserver.observe(mainContent[0]);
|
|
}
|
|
}
|
|
|
|
connect(id) {
|
|
this.initialize(this.mainContainerClass);
|
|
|
|
const popoverNode = document.getElementById('popover-' + id);
|
|
const popoverContentNode = document.getElementById('popovercontent-' + id);
|
|
if (popoverNode && popoverNode.parentNode && popoverContentNode) {
|
|
|
|
window.mudpopoverHelper.placePopover(popoverNode);
|
|
|
|
const config = { attributeFilter: ['class', 'data-ticks'] };
|
|
|
|
const observer = new MutationObserver(this.callback.bind(this, id));
|
|
|
|
observer.observe(popoverContentNode, config);
|
|
|
|
const resizeObserver = new ResizeObserver(entries => {
|
|
for (let entry of entries) {
|
|
const target = entry.target;
|
|
|
|
for (var i = 0; i < target.childNodes.length; i++) {
|
|
const childNode = target.childNodes[i];
|
|
if (childNode.id && childNode.id.startsWith('popover-')) {
|
|
window.mudpopoverHelper.placePopover(childNode);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
resizeObserver.observe(popoverNode.parentNode);
|
|
|
|
const contentNodeObserver = new ResizeObserver(entries => {
|
|
for (let entry of entries) {
|
|
var target = entry.target;
|
|
window.mudpopoverHelper.placePopoverByNode(target);
|
|
|
|
|
|
}
|
|
});
|
|
|
|
contentNodeObserver.observe(popoverContentNode);
|
|
|
|
this.map[id] = {
|
|
mutationObserver: observer,
|
|
resizeObserver: resizeObserver,
|
|
contentNodeObserver: contentNodeObserver
|
|
};
|
|
}
|
|
}
|
|
|
|
disconnect(id) {
|
|
if (this.map[id]) {
|
|
|
|
const item = this.map[id]
|
|
item.mutationObserver.disconnect();
|
|
item.resizeObserver.disconnect();
|
|
item.contentNodeObserver.disconnect();
|
|
|
|
delete this.map[id];
|
|
}
|
|
}
|
|
|
|
dispose() {
|
|
for (var i in this.map) {
|
|
disconnect(i);
|
|
}
|
|
|
|
this.contentObserver.disconnect();
|
|
this.contentObserver = null;
|
|
}
|
|
|
|
getAllObservedContainers() {
|
|
const result = [];
|
|
for (var i in this.map) {
|
|
result.push(i);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
window.mudPopover = new MudPopover();
|
|
|
|
window.addEventListener('scroll', () => {
|
|
window.mudpopoverHelper.placePopoverByClassSelector('mud-popover-fixed');
|
|
window.mudpopoverHelper.placePopoverByClassSelector('mud-popover-overflow-flip-always');
|
|
});
|
|
|
|
window.addEventListener('resize', () => {
|
|
window.mudpopoverHelper.placePopoverByClassSelector();
|
|
}); |