mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-11 23:02:56 +01:00
- Added MIME type mappings for .otf, .woff, and .woff2 font formats - Fixed missing break statement after .wav case (was falling through to .mp4) - Fonts now load correctly in editor preview without 404 errors - Resolves OTS parsing error messages in console The web server was already serving project directory files correctly, but browsers were rejecting font files due to missing/incorrect MIME types. Related to TASK-006
159 lines
4.7 KiB
JavaScript
159 lines
4.7 KiB
JavaScript
export default class Inspector {
|
|
constructor({ onInspect, onHighlight, onDisableHighlight }) {
|
|
this.onMouseMove = (e) => {
|
|
onDisableHighlight();
|
|
|
|
const noodlNode = this.findNoodlNode(e.target);
|
|
if (noodlNode) {
|
|
document.body.style.cursor = 'pointer';
|
|
onHighlight(noodlNode.id);
|
|
} else {
|
|
document.body.style.cursor = 'initial';
|
|
}
|
|
|
|
e.stopPropagation();
|
|
};
|
|
|
|
this.onClick = (e) => {
|
|
onDisableHighlight();
|
|
|
|
const noodlNode = this.findNoodlNode(e.target);
|
|
if (noodlNode) {
|
|
onInspect([noodlNode.id]);
|
|
}
|
|
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
//not sure how to stop React input elements from getting focus, so blurring the potential element tha got focus on click
|
|
if (document.activeElement) {
|
|
document.activeElement.blur();
|
|
}
|
|
};
|
|
|
|
this.onContextMenu = (e) => {
|
|
const nodeIds = document
|
|
.elementsFromPoint(e.clientX, e.clientY)
|
|
.map((dom) => this.findNoodlNode(dom))
|
|
.filter((node) => !!node)
|
|
.map((node) => node.id);
|
|
|
|
if (nodeIds.length) {
|
|
onInspect(nodeIds);
|
|
}
|
|
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
//not sure how to stop React input elements from getting focus, so blurring the potential element tha got focus on click
|
|
if (document.activeElement) {
|
|
document.activeElement.blur();
|
|
}
|
|
};
|
|
|
|
this.onMouseOut = (e) => {
|
|
onDisableHighlight();
|
|
};
|
|
|
|
this.blockEvent = (e) => {
|
|
e.stopPropagation();
|
|
};
|
|
|
|
this.onDisableHighlight = onDisableHighlight;
|
|
}
|
|
|
|
setComponent(component) {
|
|
this.component = component;
|
|
}
|
|
|
|
enable() {
|
|
//blur active element, if any
|
|
if (document.activeElement) {
|
|
document.activeElement.blur();
|
|
}
|
|
|
|
//get events from capture phase, before they tunnel down the tree
|
|
document.addEventListener('mouseenter', this.blockEvent, true);
|
|
document.addEventListener('mouseover', this.blockEvent, true);
|
|
document.addEventListener('mousedown', this.blockEvent, true);
|
|
document.addEventListener('mouseup', this.blockEvent, true);
|
|
document.addEventListener('mousemove', this.onMouseMove, true);
|
|
document.addEventListener('mouseout', this.onMouseOut, true);
|
|
document.addEventListener('click', this.onClick, true);
|
|
document.addEventListener('contextmenu', this.onContextMenu, true);
|
|
}
|
|
|
|
disable() {
|
|
document.body.style.cursor = 'initial';
|
|
|
|
document.removeEventListener('mouseenter', this.blockEvent, true);
|
|
document.removeEventListener('mouseover', this.blockEvent, true);
|
|
document.removeEventListener('mousedown', this.blockEvent, true);
|
|
document.removeEventListener('mouseup', this.blockEvent, true);
|
|
document.removeEventListener('mousemove', this.onMouseMove, true);
|
|
document.removeEventListener('mouseout', this.onMouseOut, true);
|
|
document.removeEventListener('click', this.onClick, true);
|
|
document.removeEventListener('contextmenu', this.onContextMenu, true);
|
|
|
|
this.onDisableHighlight();
|
|
}
|
|
|
|
findNoodlNode(dom) {
|
|
//walk the dom tree upwards until a dom element with react state is found
|
|
let domFiber;
|
|
while (!domFiber && dom) {
|
|
// React 18 changed from __reactInternalInstance$ to __reactFiber$
|
|
const key = Object.keys(dom).find((key) =>
|
|
key.startsWith('__reactFiber$') || key.startsWith('__reactInternalInstance$')
|
|
);
|
|
domFiber = dom[key];
|
|
if (!domFiber) dom = dom.parentElement;
|
|
}
|
|
|
|
//found none
|
|
if (!domFiber) {
|
|
return undefined;
|
|
}
|
|
|
|
const GetCompFiber = (fiber) => {
|
|
let parentFiber = fiber.return;
|
|
while (parentFiber && typeof parentFiber.type == 'string') {
|
|
parentFiber = parentFiber.return;
|
|
}
|
|
return parentFiber;
|
|
};
|
|
|
|
//found a react node, now walk the react tree until a noodl node is found
|
|
//(identified by having a noodlNode prop)
|
|
let compFiber = GetCompFiber(domFiber);
|
|
while (compFiber && (!compFiber.stateNode || !compFiber.stateNode.props || !compFiber.stateNode.props.noodlNode)) {
|
|
compFiber = GetCompFiber(compFiber);
|
|
}
|
|
|
|
const noodlNode = compFiber ? compFiber.stateNode.props.noodlNode : undefined;
|
|
if (!noodlNode) return;
|
|
|
|
if (this.component) {
|
|
let node = noodlNode;
|
|
|
|
while (node) {
|
|
if (node.parentNodeScope) {
|
|
if (node.parentNodeScope.componentOwner.name === this.component.name) {
|
|
return node;
|
|
}
|
|
node = node.parentNodeScope.componentOwner;
|
|
} else {
|
|
if (node.nodeScope.componentOwner.name === this.component.name) {
|
|
return node;
|
|
}
|
|
node = node.nodeScope.componentOwner;
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
return noodlNode;
|
|
}
|
|
}
|