文档中的恐龙
产品给了你一个需求:你需要在你的文档中包含一些独家的文档元素。
用户可以操作这些元素或者开发者自己可以生成这些元素。下面的例子就展示给你这样一个「独家」的恐龙元素。
ProseMirror 允许你定义你自己的 schemas,它包含了自定义的文档元素。你可以在文档中使用任何你放到 schema 中的元素,当然如果 schema 中没有的元素你是不能够用的。
这就是你的支持插入「恐龙元素」的编辑器。
例如 ,这个段落
都是 恐龙。
恐龙节点可以被选中,复制,粘贴,拖拽等。
在这个示例中,我们扩展了 basic schema,将一个单独的新的节点加入其中。
首先,我们定义一个 node spec,它描述了节点的行为和它的 DOM 表现形式。
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
}
}]
}
之后,我们创建了一个真实的 schema 来包含这个节点,然后使用它去格式化 HTML 到 ProseMirror 文档:
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)
这个示例再次使用了 example setup 模块,以提供一些基本的编辑行为。
不过我们在菜单栏需要一个新的菜单项,来插入该节点。所以首先,定义一个 command 来处理恐龙的插入:
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
}
}
然后,新建一个菜单项来调用我们的命令:
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)
})))
现在,就只剩下用我们自定义的 schema 和 menu 来创建一个编辑器 state 和 view:
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})
})
})