-
-
Save sefgit/4ec5656c13251678cca7e1e3f9d79385 to your computer and use it in GitHub Desktop.
ContentEditable Demo (CodeMirror 6)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>ContentEditable Demo</title> | |
<script src="index.js"></script> | |
</head> | |
<body> | |
<div id="editor"></div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { EditorState } from "@codemirror/state" | |
import { Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate, WidgetType } from "@codemirror/view" | |
import { syntaxTree } from '@codemirror/language' | |
import { markdown, markdownLanguage } from "@codemirror/lang-markdown" | |
// Basic Widget class that only creates demo content | |
class ImageWidget extends WidgetType { | |
constructor () { super() } | |
eq (other: ImageWidget) { return false } | |
toDOM (view: EditorView): HTMLElement { | |
const wrapper = document.createElement('div') | |
wrapper.style.display = 'inline-block' | |
wrapper.innerText = `>>>This is a contenteditable Div<<<` | |
// The following two lines don't really work. The editor always sets the contenteditable attr to false. One can programmatically overwrite it and edit the div without any problems, however. | |
// wrapper.contentEditable = 'true' | |
wrapper.setAttribute('contenteditable', 'true') | |
const input = document.createElement('input') | |
input.value = 'An input elem -- edit me!' | |
wrapper.appendChild(input) | |
return wrapper | |
} | |
ignoreEvent (event: Event): boolean { return true } | |
} | |
// Small render function that uses the syntaxTree to find syntax nodes to replace | |
function renderWidgets (state: EditorState, visibleRanges: readonly {from: number, to: number}[]): DecorationSet { | |
const widgets: any[] = [] | |
const selections = state.selection.ranges.map(range => [range.from, range.to]) | |
for (const { from, to } of visibleRanges) { | |
syntaxTree(state).iterate({ | |
from, to, | |
enter: (node) => { | |
// Only render widgets with no selection overlaps | |
const overlaps = selections.filter(([from, to]) => !(to <= node.from || from >= node.to)).length | |
if (overlaps > 0) { return } | |
// In this example, we only render images. | |
if (node.type.name !== 'Image') { return } | |
const widget = Decoration.replace({ widget: new ImageWidget(), inclusive: false }) | |
widgets.push(widget.range(node.from, node.to)) | |
} | |
}) | |
} | |
return Decoration.set(widgets) | |
} | |
// This ViewPlugin is basically the decoration example. | |
const plugin = ViewPlugin.fromClass(class { | |
decorations: DecorationSet | |
constructor (view: EditorView) { | |
this.decorations = renderWidgets(view.state, view.visibleRanges) | |
} | |
update (update: ViewUpdate) { | |
if (update.docChanged || update.viewportChanged || update.selectionSet) { | |
this.decorations = renderWidgets(update.view.state, update.view.visibleRanges) | |
} | |
} | |
}, { decorations: view => view.decorations } | |
) | |
document.addEventListener('DOMContentLoaded', () => { | |
// Create a basic state that only has the Markdown parser (to retrieve the | |
// Image syntax nodes) and our demo plugin | |
const state = EditorState.create({ | |
doc: '# Test document\n\n\n\n> A blockquote', | |
extensions: [ | |
markdown({ base: markdownLanguage }), | |
plugin | |
] | |
}) | |
const view = new EditorView({ state, parent: document.getElementById('editor') ?? undefined }) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment