Dinos in the document
Say you need to include exotic, site-specific elements in your
documents. These may be handles to other objects in our system
(documents, users, etc), domain-specific widgets, or, in the case of
this demo, dinosaurs.
ProseMirror allows you to define your own schemas, which includes
defining custom document elements. You can use whatever you put in the
schema as proper semantic element in your documents.
This is your dinosaur-enabled editor. The insert menu allows you
to insert dinosaurs.
This paragraph , for example,
is full of
dinosaurs.
Dinosaur nodes can be selected, copied, pasted, dragged, and so on.
In this example, we extend the
basic
schema with a single new node. First, we define a node
spec, which describes the node's behavior and its
DOM representation.
const dinos = ["brontosaurus", "stegosaurus", "triceratops",
"tyrannosaurus", "pterodactyl"]
const dinoNodeSpec = {
attrs: {type: {default: "brontosaurus"}},
inline: true,
group: "inline",
draggable: true,
toDOM: node => ["img", {"dino-type": node.attrs.type,
src: "/img/dino/" + node.attrs.type + ".png",
title: node.attrs.type,
class: "dinosaur"}],
parseDOM: [{
tag: "img[dino-type]",
getAttrs: dom => {
let type = dom.getAttribute("dino-type")
return dinos.indexOf(type) > -1 ? {type} : false
}
}]
}
Then, we create an actual schema that includes this node, and use that
to parse a piece of the HTML page into a ProseMirror document.
import {Schema, DOMParser} from "prosemirror-model"
import {schema} from "prosemirror-schema-basic"
const dinoSchema = new Schema({
nodes: schema.spec.nodes.addBefore("image", "dino", dinoNodeSpec),
marks: schema.spec.marks
})
let content = document.querySelector("#content")
let startDoc = DOMParser.fromSchema(dinoSchema).parse(content)
The demo is going to use the example
setup
module again, to provide the basic plumbing for the editor. But we
need new menu items in the insert menu. First, define a
command that handles dinosaur insertion.
let dinoType = dinoSchema.nodes.dino
function insertDino(type) {
return function(state, dispatch) {
let {$from} = state.selection, index = $from.index()
if (!$from.parent.canReplaceWith(index, index, dinoType))
return false
if (dispatch)
dispatch(state.tr.replaceSelectionWith(dinoType.create({type})))
return true
}
}
Next, create menu items that call our command.
import {MenuItem} from "prosemirror-menu"
import {buildMenuItems} from "prosemirror-example-setup"
let menu = buildMenuItems(dinoSchema)
dinos.forEach(name => menu.insertMenu.content.push(new MenuItem({
title: "Insert " + name,
label: name.charAt(0).toUpperCase() + name.slice(1),
enable(state) { return insertDino(name)(state) },
run: insertDino(name)
})))
Now all that's left to do is creating an editor state and view with
our custom schema and menu.
import {EditorState} from "prosemirror-state"
import {EditorView} from "prosemirror-view"
import {exampleSetup} from "prosemirror-example-setup"
window.view = new EditorView(document.querySelector("#editor"), {
state: EditorState.create({
doc: startDoc,
plugins: exampleSetup({schema: dinoSchema, menuContent: menu.fullMenu})
})
})