@selenite/graph-editor
Version:
A graph editor for visual programming, based on rete and svelte.
110 lines (109 loc) • 4.81 kB
JavaScript
import { BaseComponent } from '../components';
import { XmlNode } from '../nodes';
import { buildXml, mergeParsedXml, parseXml } from '@selenite/commons';
import { addGraphToEditor, xmlToGraph } from './code-integration/utils.svelte';
let worker;
async function instantiateWorker() { }
if (typeof requestIdleCallback !== 'undefined')
requestIdleCallback(() => {
instantiateWorker();
});
export class CodeIntegration extends BaseComponent {
/**
* Pulls the selected nodes from the graph editor to the code editor
*/
async toCode({ text = '', schema }) {
const factory = this.owner;
const editor = factory.editor;
const selectedXmlNodes = factory.selector.entities.values()
.map((selected) => editor.getNode(selected.id))
.filter((node) => node instanceof XmlNode)
.reduce((acc, node) => acc.add(node), new Set());
let preppedText = text;
// if (cursorOffset !== null)
// preppedText = text.slice(0, cursorOffset) + `<${cursorTag}/>` + text.slice(cursorOffset);
const baseXml = parseXml(preppedText);
let res = baseXml;
const cursorTag = 'cursorPositioooon';
const { structures } = await import('rete-structures');
const xmlMergingPromises = factory.selector.entities.values()
.map((selected) => editor.getNode(selected.id))
.filter((node) => node instanceof XmlNode)
// Take only the selected nodes that are not predecessors
// of other selected nodes because they are redundant
.filter((node) => structures(editor).successors(node.id).nodes().values()
.filter((node) => node instanceof XmlNode)
.every((node) => !selectedXmlNodes.has(node)))
.map(async (node) => {
const xml = parseXml(await node.getXml());
res = mergeParsedXml({
baseXml: res,
newXml: xml,
cursorTag,
typesPaths: schema.typePaths
});
});
await Promise.all(xmlMergingPromises);
return buildXml({ parsedXml: res, cursorTag });
}
/**
* Pushes the selected text from the code editor to the graph editor
*/
async toGraph({ text: xml, schema }) {
const t0 = performance.now();
const factory = this.owner;
// if (typeof Worker === "undefined") return;
// instantiateWorker();
// if (!worker) throw new ErrorWNotif('Worker not instantiated');
if (!worker) {
await this.owner.bulkOperation(async () => {
const { nodes, connections } = xmlToGraph({ xml, schema, factory });
await addGraphToEditor({ factory, nodes, connections, t0 });
});
return;
}
const msg = { type: 'xmlToGraph', xml, schema: schema.toJSON() };
worker.postMessage(msg);
worker.onmessage = async (e) => {
const data = e.data;
if (data.type !== 'xmlToGraph')
return;
const { nodes, connections } = data;
console.log('nodes', nodes);
addGraphToEditor({ factory, nodes, connections, t0 });
};
return;
// await factory.bulkOperation(async () => {
// const area = factory.getArea();
// let leftBound = 0;
// if (area) {
// wu(area.nodeViews.values()).forEach((nodeView) => {
// leftBound = Math.min(leftBound, nodeView.position.x - nodeView.element.offsetWidth * 1.4);
// });
// }
// const tmp_area = factory.area;
// if (tmp_area) {
// for (const [i, node] of nodesToAdd.entries()) {
// const tmp_nodeView = tmp_area.nodeViews.get(node.id) as NodeView;
// const nodeView = factory.getArea()?.nodeViews.get(node.id);
// factory.select(node, { accumulate: i !== 0 });
// // if (nodeView)
// // await nodeView.translate(tmp_nodeView.position.x + leftBound, tmp_nodeView.position.y);
// await factory.getArea()?.update('node', node.id);
// }
// factory.selector.releasePicked();
// }
// factory.notifications.hide('code-integration-progress');
// if (nodesToAdd.length > 0)
// factory.notifications.show({
// title: 'Graph editor',
// message: `${nodesToAdd.length} added nodes have been selected. They can be dragged using CTRL + Left mouse button.`,
// autoClose: 7000
// });
// if (area) {
// const { AreaExtensions } = await import('rete-area-plugin');
// await AreaExtensions.zoomAt(area, editor.getNodes(), {});
// }
// });
}
}