mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-11-10 09:03:02 +08:00
122 lines
3.3 KiB
JavaScript
122 lines
3.3 KiB
JavaScript
import LiveEditor from "./cell_editor/live_editor";
|
|
import Connection from "./cell_editor/live_editor/connection";
|
|
import { parseHookProps } from "../lib/attribute";
|
|
import { waitUntilInViewport } from "../lib/utils";
|
|
|
|
const CellEditor = {
|
|
mounted() {
|
|
this.props = this.getProps();
|
|
|
|
this.handleEvent(
|
|
`cell_editor_init:${this.props.cellId}:${this.props.tag}`,
|
|
({ source, revision, doctest_reports, code_markers }) => {
|
|
const editorContainer = this.el.querySelector(
|
|
`[data-el-editor-container]`
|
|
);
|
|
|
|
const editorEl = document.createElement("div");
|
|
editorContainer.appendChild(editorEl);
|
|
|
|
this.connection = new Connection(
|
|
this,
|
|
this.props.cellId,
|
|
this.props.tag
|
|
);
|
|
|
|
this.liveEditor = new LiveEditor(
|
|
editorEl,
|
|
this.connection,
|
|
source,
|
|
revision,
|
|
this.props.language,
|
|
this.props.intellisense,
|
|
this.props.readOnly
|
|
);
|
|
|
|
this.liveEditor.setCodeMarkers(code_markers);
|
|
this.liveEditor.updateDoctests(doctest_reports);
|
|
|
|
const skeletonEl = editorContainer.querySelector(`[data-el-skeleton]`);
|
|
|
|
// Replace the skeleton with initial source, so that the
|
|
// whole page is still searchable, before the editors are
|
|
// lazily mounted. This also ensures the scroll has an
|
|
// accurate length right away.
|
|
const sourceEl = document.createElement("div");
|
|
|
|
sourceEl.classList.add(
|
|
"whitespace-pre",
|
|
"text-editor",
|
|
"font-editor",
|
|
"px-12"
|
|
);
|
|
sourceEl.textContent = source;
|
|
skeletonEl.replaceChildren(sourceEl);
|
|
|
|
this.liveEditor.onMount(() => {
|
|
// Remove the content placeholder
|
|
skeletonEl.remove();
|
|
});
|
|
|
|
this.el.dispatchEvent(
|
|
new CustomEvent("lb:cell:editor_created", {
|
|
detail: { tag: this.props.tag, liveEditor: this.liveEditor },
|
|
bubbles: true,
|
|
})
|
|
);
|
|
|
|
this.visibility = waitUntilInViewport(this.el, {
|
|
root: document.querySelector("[data-el-notebook]"),
|
|
proximity: 2000,
|
|
});
|
|
|
|
// We mount the editor lazily once it enters the viewport
|
|
this.visibility.promise.then(() => {
|
|
if (!this.liveEditor.isMounted()) {
|
|
this.liveEditor.mount();
|
|
}
|
|
});
|
|
}
|
|
);
|
|
},
|
|
|
|
disconnected() {
|
|
// When disconnected, this client is no longer seen by the server
|
|
// and misses all collaborative changes. On reconnection we want
|
|
// to clean up and mount a fresh hook, which we force by ensuring
|
|
// the DOM id doesn't match
|
|
this.el.removeAttribute("id");
|
|
},
|
|
|
|
destroyed() {
|
|
if (this.connection) {
|
|
this.connection.destroy();
|
|
}
|
|
|
|
if (this.liveEditor) {
|
|
this.el.dispatchEvent(
|
|
new CustomEvent("lb:cell:editor_removed", {
|
|
detail: { tag: this.props.tag },
|
|
bubbles: true,
|
|
})
|
|
);
|
|
this.liveEditor.destroy();
|
|
}
|
|
|
|
if (this.visibility) {
|
|
this.visibility.cancel();
|
|
}
|
|
},
|
|
|
|
getProps() {
|
|
return parseHookProps(this.el, [
|
|
"cell-id",
|
|
"tag",
|
|
"language",
|
|
"intellisense",
|
|
"read-only",
|
|
]);
|
|
},
|
|
};
|
|
|
|
export default CellEditor;
|