2021-03-29 15:47:22 +00:00
|
|
|
import { debounce } from "lodash";
|
|
|
|
|
import ReactDOM from "react-dom";
|
|
|
|
|
import ResizeObserver from "resize-observer-polyfill";
|
2021-09-06 09:29:35 +00:00
|
|
|
import getFeatureFlags from "utils/featureFlags";
|
2021-03-29 15:47:22 +00:00
|
|
|
|
|
|
|
|
export const draggableElement = (
|
|
|
|
|
id: string,
|
|
|
|
|
element: any,
|
|
|
|
|
onPositionChange: any,
|
|
|
|
|
initPostion?: any,
|
2021-07-20 05:18:58 +00:00
|
|
|
renderDragBlockPositions?: {
|
|
|
|
|
left?: string;
|
|
|
|
|
top?: string;
|
|
|
|
|
zIndex?: string;
|
|
|
|
|
position?: string;
|
|
|
|
|
},
|
2021-03-29 15:47:22 +00:00
|
|
|
dragHandle?: () => JSX.Element,
|
|
|
|
|
) => {
|
|
|
|
|
let newXPos = 0,
|
|
|
|
|
newYPos = 0,
|
|
|
|
|
oldXPos = 0,
|
|
|
|
|
oldYPos = 0;
|
|
|
|
|
let dragHandler = element;
|
|
|
|
|
let isDragged = !!initPostion;
|
|
|
|
|
|
|
|
|
|
const setElementPosition = () => {
|
|
|
|
|
element.style.top = initPostion.top + "px";
|
|
|
|
|
element.style.left = initPostion.left + "px";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const dragMouseDown = (e: MouseEvent) => {
|
|
|
|
|
e = e || window.event;
|
|
|
|
|
oldXPos = e.clientX;
|
|
|
|
|
oldYPos = e.clientY;
|
|
|
|
|
document.onmouseup = closeDragElement;
|
|
|
|
|
document.onmousemove = elementDrag;
|
|
|
|
|
};
|
|
|
|
|
const calculateBoundaryConfinedPosition = (
|
|
|
|
|
calculatedLeft: number,
|
|
|
|
|
calculatedTop: number,
|
|
|
|
|
) => {
|
2021-09-06 09:29:35 +00:00
|
|
|
const bottomBarOffset = getFeatureFlags().GIT ? 34 : 0;
|
|
|
|
|
|
2021-03-29 15:47:22 +00:00
|
|
|
if (calculatedLeft <= 0) {
|
|
|
|
|
calculatedLeft = 0;
|
|
|
|
|
}
|
|
|
|
|
if (calculatedTop <= 30) {
|
|
|
|
|
calculatedTop = 30;
|
|
|
|
|
}
|
|
|
|
|
if (calculatedLeft >= window.innerWidth - element.clientWidth) {
|
|
|
|
|
calculatedLeft = window.innerWidth - element.clientWidth;
|
|
|
|
|
}
|
2021-09-06 09:29:35 +00:00
|
|
|
if (
|
|
|
|
|
calculatedTop >=
|
|
|
|
|
window.innerHeight - (element.clientHeight + bottomBarOffset)
|
|
|
|
|
) {
|
|
|
|
|
calculatedTop =
|
|
|
|
|
window.innerHeight - element.clientHeight - bottomBarOffset;
|
2021-03-29 15:47:22 +00:00
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
left: calculatedLeft,
|
|
|
|
|
top: calculatedTop,
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const elementDrag = (e: MouseEvent) => {
|
|
|
|
|
e = e || window.event;
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
newXPos = oldXPos - e.clientX;
|
|
|
|
|
newYPos = oldYPos - e.clientY;
|
|
|
|
|
oldXPos = e.clientX;
|
|
|
|
|
oldYPos = e.clientY;
|
|
|
|
|
const calculatedTop = element.offsetTop - newYPos;
|
|
|
|
|
const calculatedLeft = element.offsetLeft - newXPos;
|
|
|
|
|
element.style.top = calculatedTop + "px";
|
|
|
|
|
element.style.left = calculatedLeft + "px";
|
|
|
|
|
const validFirstDrag = !isDragged && newXPos !== 0 && newYPos !== 0;
|
|
|
|
|
if (validFirstDrag) {
|
|
|
|
|
resizeObserver.observe(element);
|
|
|
|
|
isDragged = true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const calculateNewPosition = () => {
|
2021-05-13 08:35:39 +00:00
|
|
|
const { height, left, top, width } = element.getBoundingClientRect();
|
2021-03-29 15:47:22 +00:00
|
|
|
const isElementOpen = height && width;
|
|
|
|
|
const {
|
|
|
|
|
left: calculatedLeft,
|
|
|
|
|
top: calculatedTop,
|
|
|
|
|
} = calculateBoundaryConfinedPosition(left, top);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
updatePosition: isDragged && isElementOpen,
|
|
|
|
|
left: calculatedLeft,
|
|
|
|
|
top: calculatedTop,
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const updateElementPosition = () => {
|
|
|
|
|
const calculatedPositionData = calculateNewPosition();
|
|
|
|
|
if (calculatedPositionData.updatePosition) {
|
|
|
|
|
const { left, top } = calculatedPositionData;
|
|
|
|
|
onPositionChange({
|
|
|
|
|
left: left,
|
|
|
|
|
top: top,
|
|
|
|
|
});
|
|
|
|
|
element.style.top = top + "px";
|
|
|
|
|
element.style.left = left + "px";
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const closeDragElement = () => {
|
|
|
|
|
updateElementPosition();
|
|
|
|
|
document.onmouseup = null;
|
|
|
|
|
document.onmousemove = null;
|
|
|
|
|
};
|
|
|
|
|
const debouncedUpdatePosition = debounce(updateElementPosition, 50);
|
|
|
|
|
|
|
|
|
|
const resizeObserver = new ResizeObserver(function() {
|
|
|
|
|
debouncedUpdatePosition();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (isDragged) {
|
|
|
|
|
resizeObserver.observe(element);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const OnInit = () => {
|
|
|
|
|
if (dragHandle) {
|
2021-07-20 05:18:58 +00:00
|
|
|
dragHandler = createDragHandler(
|
|
|
|
|
id,
|
|
|
|
|
element,
|
|
|
|
|
dragHandle,
|
|
|
|
|
renderDragBlockPositions,
|
|
|
|
|
);
|
2021-03-29 15:47:22 +00:00
|
|
|
}
|
|
|
|
|
if (initPostion) {
|
|
|
|
|
setElementPosition();
|
|
|
|
|
}
|
|
|
|
|
dragHandler.addEventListener("mousedown", dragMouseDown);
|
|
|
|
|
// stop clicks from propogating to widget editor.
|
|
|
|
|
dragHandler.addEventListener("click", (e: any) => e.stopPropagation());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
OnInit();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const createDragHandler = (
|
|
|
|
|
id: string,
|
|
|
|
|
el: any,
|
|
|
|
|
dragHandle: () => JSX.Element,
|
2021-07-20 05:18:58 +00:00
|
|
|
renderDragBlockPositions?: {
|
|
|
|
|
left?: string;
|
|
|
|
|
top?: string;
|
|
|
|
|
zIndex?: string;
|
|
|
|
|
position?: string;
|
|
|
|
|
},
|
2021-03-29 15:47:22 +00:00
|
|
|
) => {
|
|
|
|
|
const oldDragHandler = document.getElementById(`${id}-draghandler`);
|
|
|
|
|
const dragElement = document.createElement("div");
|
|
|
|
|
dragElement.setAttribute("id", `${id}-draghandler`);
|
2021-07-20 05:18:58 +00:00
|
|
|
dragElement.style.position = renderDragBlockPositions?.position ?? "absolute";
|
|
|
|
|
dragElement.style.left = renderDragBlockPositions?.left ?? "135px";
|
|
|
|
|
dragElement.style.top = renderDragBlockPositions?.top ?? "0px";
|
|
|
|
|
dragElement.style.zIndex = renderDragBlockPositions?.zIndex ?? "3";
|
2021-03-29 15:47:22 +00:00
|
|
|
oldDragHandler
|
|
|
|
|
? el.replaceChild(dragElement, oldDragHandler)
|
|
|
|
|
: el.appendChild(dragElement);
|
|
|
|
|
ReactDOM.render(dragHandle(), dragElement);
|
|
|
|
|
return dragElement;
|
|
|
|
|
};
|