@zohodesk/popups
Version:
popups popupover modal dialog alert notifications popup handling for whole app
330 lines (272 loc) • 10.8 kB
JavaScript
let viewPort = {
frameRelativeRects: (el, customFrame) => {
if (!el) {return;}
var rect = el.getBoundingClientRect(); //Target Element
let documentEle = document.documentElement; //Body&HTML
var customFrameRect = {
top : 0,
left : 0 ,
right : documentEle.clientWidth,
bottom : documentEle.clientHeight,
height : documentEle.clientHeight,
width : documentEle.clientWidth,
x : 0 ,
y : 0
}
if( customFrame ){
customFrameRect = customFrame.getBoundingClientRect();
}
let newReact = {
top: rect.top - customFrameRect.top,
left: rect.left - customFrameRect.left,
height: rect.height,
width: rect.width
};
newReact.bottom = newReact.top + newReact.height;
newReact.right = newReact.left + newReact.width;
newReact.x = newReact.left;
newReact.y = newReact.top;
let rectGap = {
top: newReact.top,
left: newReact.left,
bottom: customFrameRect.height - newReact.bottom,
right: customFrameRect.width - newReact.right
};
rectGap.center = {
top: rectGap.top + newReact.height / 2,
left: rectGap.left + newReact.width / 2,
bottom: rectGap.bottom + newReact.height / 2,
right: rectGap.right + newReact.width / 2
};
let adjustments = {};
if (newReact.top < 0) {
adjustments.top = Math.abs(newReact.top);
}
if (newReact.left < 0) {
adjustments.left = Math.abs(newReact.left);
}
if (newReact.bottom > customFrameRect.height) {
adjustments.bottom = newReact.bottom - customFrameRect.height;
}
if (newReact.right > customFrameRect.width) {
adjustments.right = newReact.right - customFrameRect.width;
}
return { frameRect: customFrameRect, rect: newReact, rectGap, adjustments };
},
isInViewPort: (el, customFrame) => {
if (!el) {return;}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let react = elRects.rect;
let frameReact = elRects.frameRect;
return rect.top >= 0 && rect.left >= 0 && rect.bottom <= frameReact.height && rect.right <= frameReact.width;
},
possibilities: (
el,
relativeBox,
customFrame,
) => {
if (!el) {return;}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let rect = elRects.rect;
let adjustments = elRects.adjustments;
let relativeBoxReacts = viewPort.frameRelativeRects(relativeBox, customFrame);
let relativeBoxRect = relativeBoxReacts.rect;
let relativeBoxGap = relativeBoxReacts.rectGap;
let relativeBoxDocumentRects = viewPort.frameRelativeRects(
relativeBox,
customFrame
);
let { rectGap: documentGap } = relativeBoxDocumentRects;
adjustments.left? adjustments.left=adjustments.left+(relativeBoxReacts.rect.width*2/3):null
adjustments.right?adjustments.right=adjustments.right+(relativeBoxReacts.rect.width*2/3):null
adjustments.top?adjustments.top=adjustments.top+(relativeBoxReacts.rect.width*2/3):null
adjustments.bottom?adjustments.bottom=adjustments.bottom+(relativeBoxReacts.rect.width*2/3):null
let views = {};
//bottomCenter
let bottomOverFlow = rect.height >= relativeBoxGap.bottom;
let bottomRightOverFlow = rect.width / 2 >= relativeBoxGap.center.right;
let bottomLeftOverFlow = rect.width / 2 >= relativeBoxGap.center.left;
//bottomRight
let bottomLeftOnlyOverFlow = rect.width >= relativeBoxGap.center.left;
views.bottomRight = !(bottomOverFlow || bottomLeftOnlyOverFlow);
//bottomLeft
let bottomRightOnlyOverFlow = rect.width >= relativeBoxGap.center.right;
views.bottomLeft = !(bottomOverFlow || bottomRightOnlyOverFlow);
views.bottomCenter = !(bottomOverFlow || bottomRightOverFlow || bottomLeftOverFlow );
//topCenter
let topOverFlow = rect.height >= relativeBoxGap.top;
let topRightOverFlow = rect.width / 2 >= relativeBoxGap.center.right;
let topLeftOverFlow = rect.width / 2 >= relativeBoxGap.center.left;
//topRight
let topLeftOnlyOverFlow = rect.width >= relativeBoxGap.center.left;
views.topRight = !(topOverFlow || topLeftOnlyOverFlow);
//topLeft
let topRightOnlyOverFlow = rect.width >= relativeBoxGap.center.right;
views.topLeft = !(topOverFlow || topRightOnlyOverFlow);
views.topCenter = !(topOverFlow || topRightOverFlow || topLeftOverFlow ); //|| topLeftOnlyOverFlow || topRightOnlyOverFlow);
//leftCenter
let leftOverFlow = rect.width >= relativeBoxGap.left;
let leftTopOverFlow = rect.height / 2 >= relativeBoxGap.center.top;
let leftBottomOverFlow = rect.height / 2 >= relativeBoxGap.center.bottom;
//leftTop
let leftTopOnlyOverFlow = rect.height >= relativeBoxGap.center.bottom;
views.leftTop = !(leftOverFlow || leftTopOnlyOverFlow);
//leftBottom
let leftBottomOnlyOverFlow = rect.height >= relativeBoxGap.center.top;
views.leftBottom = !(leftOverFlow || leftBottomOnlyOverFlow);
views.leftCenter = !(leftOverFlow || leftTopOverFlow || leftBottomOverFlow); // || leftTopOnlyOverFlow || leftBottomOnlyOverFlow);
//rightCenter
let rightOverFlow = rect.width >= relativeBoxGap.right;
let rightTopOverFlow = rect.height / 2 >= relativeBoxGap.center.top;
let rightBottomOverFlow = rect.height / 2 >= relativeBoxGap.center.bottom;
//rightTop
let rightTopOnlyOverFlow = rect.height >= relativeBoxGap.center.bottom;
views.rightTop = !(rightOverFlow || rightTopOnlyOverFlow);
//rightBottom
let rightBottomOnlyOverFlow = rect.height >= relativeBoxGap.center.top;
views.rightBottom = !(rightOverFlow || rightBottomOnlyOverFlow);
views.rightCenter = !(rightOverFlow || rightTopOverFlow || rightBottomOverFlow); // || rightTopOnlyOverFlow || rightBottomOnlyOverFlow);
let horizontalCenter = relativeBoxGap.left + relativeBoxRect.width / 2;
let horizontalLeft = relativeBoxGap.left;
let horizontalRight = relativeBoxGap.left + relativeBoxRect.width;
let verticalBottom = relativeBoxGap.top + relativeBoxRect.height;
let verticalTop = relativeBoxGap.top;
let verticalCenter = relativeBoxGap.top + relativeBoxRect.height / 2;
let horizontalTop = documentGap.bottom + relativeBoxRect.height;
let needArrow = false;
let paddingSpace = 5; // space between target and relative element
let arrowSize = needArrow ? 10 : 5;
rect.height = rect.height + (needArrow ? arrowSize : paddingSpace);
rect.width = rect.width + (needArrow ? arrowSize : paddingSpace);
let viewsOffset = { // Code Copy frm DOT ViewPort.js qa
bottomCenter: {
left: horizontalCenter - rect.width / 2,
top: verticalBottom + arrowSize
},
bottomRight:{
left: horizontalRight - rect.width,
top: verticalBottom + arrowSize
},
bottomLeft:{
left: horizontalLeft,
top: verticalBottom + arrowSize
},
topCenter: {
left: horizontalCenter - rect.width / 2,
bottom: horizontalTop + arrowSize
},
topRight: {
left: horizontalRight - rect.width,
bottom: horizontalTop + arrowSize
},
topLeft: {
left: horizontalLeft,
bottom: horizontalTop + arrowSize
},
rightCenter: {
left: horizontalRight + arrowSize,
top: verticalCenter - rect.height / 2
},
rightBottom: {
left: horizontalRight + arrowSize,
bottom: documentGap.bottom
},
rightTop: {
left: horizontalRight + arrowSize,
top: verticalTop
},
leftCenter: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalCenter - rect.height / 2
},
leftTop: {
left: horizontalLeft - (rect.width + arrowSize),
top: verticalTop
},
leftBottom: {
left: horizontalLeft - (rect.width + arrowSize),
bottom: documentGap.bottom
}
};
return { views, adjustments, positionOffset:viewsOffset };
},
getArrowAdjustments : (el, relativeBox, customFrame) => {
if (!el) {return;}
let elRects = viewPort.frameRelativeRects(el, customFrame);
let rect = elRects.rect;
let rectGap = elRects.rectGap;
let adjustments = elRects.adjustments;
let relativeBoxReacts = viewPort.frameRelativeRects(relativeBox, customFrame);
let relativeBoxReact = relativeBoxReacts.rect;
let relativeBoxGap = relativeBoxReacts.rectGap;
return {
left : (relativeBoxGap.center.left - rectGap.left) ,
right : (relativeBoxGap.center.right - rectGap.right),
top : (relativeBoxGap.center.top - rectGap.top),
bottom : (relativeBoxGap.center.bottom - rectGap.bottom)
};
},
betterView: (
popup,
relativeBox,
defaultView,
customFrame
) => {
let viewPortPossibilities = viewPort.possibilities(popup, relativeBox, customFrame);
if (!viewPortPossibilities) {
return;
}
let views = viewPortPossibilities.views;
let adjustments = viewPortPossibilities.adjustments;
let viewKeys = Object.keys(views);
let isViewFound = false;
let positionOffset=viewPortPossibilities.positionOffset;
for (let i = 0; i < viewKeys.length; i++) {
let viewKey = viewKeys[i];
if (views[viewKey]) {
isViewFound = true;
break;
}
}
if (!isViewFound) {
return { view: null, adjustments, fixedPosition:{} };
}
if (views[defaultView]) {
return { view: defaultView, adjustments, fixedPosition:positionOffset[defaultView] };
}
let defaultPosition = defaultView.replace(/Center|Bottom|Top|Left|Right$/, '');
let viewTypes = { top: ['Center', 'Right', 'Left'], left: ['Center', 'Top', 'Bottom'] };
viewTypes.bottom = viewTypes.top;
viewTypes.right = viewTypes.left;
let defaultPositions = viewTypes[defaultPosition];
for (let i = 0, len = defaultPositions.length; i < len; i++) {
let viewKey = defaultPosition + defaultPositions[i];
if (views[viewKey]) {
return { view: viewKey, adjustments, fixedPosition:positionOffset[viewKey] };
}
}
let oppositePositionsOrder = {
bottom: ['top', 'right', 'left'],
top: ['bottom', 'right', 'left'],
left: ['bottom', 'right', 'top'],
right: ['bottom', 'top', 'left']
};
let oppositeViews = oppositePositionsOrder[defaultPosition];
for (let i = 0, len = oppositeViews.length; i < len; i++) {
let oppositeView = oppositeViews[i];
let positions = viewTypes[oppositeView];
for (let j = 0, lenx = positions.length; j < lenx; j++) {
let viewKey = oppositeView + positions[j];
if (views[viewKey]) {
return { view: viewKey, adjustments, fixedPosition:positionOffset[viewKey] };
}
}
}
return { view: null, adjustments, fixedPosition:{} };
}
};
export default {
betterView : viewPort.betterView,
frameRelativeRects : viewPort.frameRelativeRects,
getArrowAdjustments : viewPort.getArrowAdjustments
};