文档中的恐龙
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 允许你定义自己的 schema,其中包括定义自定义的文档元素。你在 schema 中放入的任何东西,都可以作为文档中合适的语义元素来使用。
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.
在本示例中,我们用一个新的节点来扩展基础 schema。首先,我们定义一个 node spec,它描述节点的行为及其 DOM 表示。
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.
// The supported types of dinosaurs.
const dinos = ["brontosaurus", "stegosaurus", "triceratops",
"tyrannosaurus", "pterodactyl"]
const dinoNodeSpec = {
// Dinosaurs have one attribute, their type, which must be one of
// the types defined above.
// Brontosaurs are still the default dino.
attrs: {type: {default: "brontosaurus"}},
inline: true,
group: "inline",
draggable: true,
// These nodes are rendered as images with a `dino-type` attribute.
// There are pictures for all dino types under /img/dino/.
toDOM: node => ["img", {"dino-type": node.attrs.type,
src: "/img/dino/" + node.attrs.type + ".png",
title: node.attrs.type,
class: "dinosaur"}],
// When parsing, such an image, if its type matches one of the known
// types, is converted to a dino node.
parseDOM: [{
tag: "img[dino-type]",
getAttrs: dom => {
let type = dom.getAttribute("dino-type")
return dinos.indexOf(type) > -1 ? {type} : false
}
}]
}
然后,我们创建一个真正包含这个节点的 schema,并用它把 HTML 页面中的一段内容解析成一个 ProseMirror 文档。
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)
这个演示再次使用 example setup 模块,来提供编辑器的基础设施。但我们还需要在插入菜单中添加新的菜单项。首先,定义一个处理恐龙插入的命令。
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"
// Ask example-setup to build its basic menu
let menu = buildMenuItems(dinoSchema)
// Add a dino-inserting item for each type of dino
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 和菜单来创建编辑器状态和视图。
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,
// Pass exampleSetup our schema and the menu we created
plugins: exampleSetup({schema: dinoSchema, menuContent: menu.fullMenu})
})
})