codemirror-graphql
Version:
GraphQL mode and helpers for CodeMirror.
135 lines • 4.75 kB
JavaScript
import CodeMirror from 'codemirror';
CodeMirror.defineOption('info', false, (cm, options, old) => {
if (old && old !== CodeMirror.Init) {
const oldOnMouseOver = cm.state.info.onMouseOver;
CodeMirror.off(cm.getWrapperElement(), 'mouseover', oldOnMouseOver);
clearTimeout(cm.state.info.hoverTimeout);
delete cm.state.info;
}
if (options) {
const state = (cm.state.info = createState(options));
state.onMouseOver = onMouseOver.bind(null, cm);
CodeMirror.on(cm.getWrapperElement(), 'mouseover', state.onMouseOver);
}
});
function createState(options) {
return {
options: options instanceof Function
? { render: options }
: options === true
? {}
: options,
};
}
function getHoverTime(cm) {
const { options } = cm.state.info;
return (options === null || options === void 0 ? void 0 : options.hoverTime) || 500;
}
function onMouseOver(cm, e) {
const state = cm.state.info;
const target = e.target || e.srcElement;
if (!(target instanceof HTMLElement)) {
return;
}
if (target.nodeName !== 'SPAN' || state.hoverTimeout !== undefined) {
return;
}
const box = target.getBoundingClientRect();
const onMouseMove = function () {
clearTimeout(state.hoverTimeout);
state.hoverTimeout = setTimeout(onHover, hoverTime);
};
const onMouseOut = function () {
CodeMirror.off(document, 'mousemove', onMouseMove);
CodeMirror.off(cm.getWrapperElement(), 'mouseout', onMouseOut);
clearTimeout(state.hoverTimeout);
state.hoverTimeout = undefined;
};
const onHover = function () {
CodeMirror.off(document, 'mousemove', onMouseMove);
CodeMirror.off(cm.getWrapperElement(), 'mouseout', onMouseOut);
state.hoverTimeout = undefined;
onMouseHover(cm, box);
};
const hoverTime = getHoverTime(cm);
state.hoverTimeout = setTimeout(onHover, hoverTime);
CodeMirror.on(document, 'mousemove', onMouseMove);
CodeMirror.on(cm.getWrapperElement(), 'mouseout', onMouseOut);
}
function onMouseHover(cm, box) {
const pos = cm.coordsChar({
left: (box.left + box.right) / 2,
top: (box.top + box.bottom) / 2,
}, 'window');
const state = cm.state.info;
const { options } = state;
const render = options.render || cm.getHelper(pos, 'info');
if (render) {
const token = cm.getTokenAt(pos, true);
if (token) {
const info = render(token, options, cm, pos);
if (info) {
showPopup(cm, box, info);
}
}
}
}
function showPopup(cm, box, info) {
const popup = document.createElement('div');
popup.className = 'CodeMirror-info';
popup.append(info);
document.body.append(popup);
const popupBox = popup.getBoundingClientRect();
const { marginLeft, marginRight, marginBottom, marginTop } = getComputedStyle(popup);
const popupWidth = popupBox.right -
popupBox.left +
parseFloat(marginLeft) +
parseFloat(marginRight);
const popupHeight = popupBox.bottom -
popupBox.top +
parseFloat(marginTop) +
parseFloat(marginBottom);
let topPos = box.bottom;
if (popupHeight > window.innerHeight - box.bottom - 15 &&
box.top > window.innerHeight - box.bottom) {
topPos = box.top - popupHeight;
}
if (topPos < 0) {
topPos = box.bottom;
}
let leftPos = Math.max(0, window.innerWidth - popupWidth - 15);
if (leftPos > box.left) {
leftPos = box.left;
}
popup.style.opacity = '1';
popup.style.top = topPos + 'px';
popup.style.left = leftPos + 'px';
let popupTimeout;
const onMouseOverPopup = function () {
clearTimeout(popupTimeout);
};
const onMouseOut = function () {
clearTimeout(popupTimeout);
popupTimeout = setTimeout(hidePopup, 200);
};
const hidePopup = function () {
CodeMirror.off(popup, 'mouseover', onMouseOverPopup);
CodeMirror.off(popup, 'mouseout', onMouseOut);
CodeMirror.off(cm.getWrapperElement(), 'mouseout', onMouseOut);
if (popup.style.opacity) {
popup.style.opacity = '0';
setTimeout(() => {
if (popup.parentNode) {
popup.remove();
}
}, 600);
}
else if (popup.parentNode) {
popup.remove();
}
};
CodeMirror.on(popup, 'mouseover', onMouseOverPopup);
CodeMirror.on(popup, 'mouseout', onMouseOut);
CodeMirror.on(cm.getWrapperElement(), 'mouseout', onMouseOut);
}
//# sourceMappingURL=info-addon.js.map