add node view to task item

This commit is contained in:
Philipp Kühn 2020-10-30 14:55:48 +01:00
parent cf8956bca1
commit b28a322d8b
6 changed files with 75 additions and 15 deletions

View File

@ -39,8 +39,8 @@ export default {
],
content: `
<ul data-type="task_list">
<li>A list item</li>
<li>And another one</li>
<li data-type="task_item" data-checked="true">A list item</li>
<li data-type="task_item" data-checked="false">And another one</li>
</ul>
`,
})

View File

@ -8,6 +8,8 @@ import { Extensions, NodeViewRenderer } from './types'
import getSchema from './utils/getSchema'
import getSchemaTypeByName from './utils/getSchemaTypeByName'
import splitExtensions from './utils/splitExtensions'
import getAttributesFromExtensions from './utils/getAttributesFromExtensions'
import getRenderedAttributes from './utils/getRenderedAttributes'
export default class ExtensionManager {
@ -97,14 +99,17 @@ export default class ExtensionManager {
}
get nodeViews() {
const { editor } = this
const { nodeExtensions } = splitExtensions(this.extensions)
const allAttributes = getAttributesFromExtensions(this.extensions)
return Object.fromEntries(nodeExtensions
.filter(extension => !!extension.addNodeView)
.map(extension => {
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.name)
const context = {
options: extension.options,
editor: this.editor,
editor,
type: getSchemaTypeByName(extension.name, this.schema),
}
@ -115,12 +120,17 @@ export default class ExtensionManager {
view: EditorView,
getPos: (() => number) | boolean,
decorations: Decoration[],
) => renderer({
editor: this.editor,
node,
getPos,
decorations,
})
) => {
const attributes = getRenderedAttributes(node, extensionAttributes)
return renderer({
editor,
node,
getPos,
decorations,
attributes,
})
}
return [extension.name, nodeview]
}))

View File

@ -8,7 +8,7 @@ import getNodeType from '../utils/getNodeType'
function isList(node: Node, schema: Schema) {
return (node.type === schema.nodes.bullet_list
|| node.type === schema.nodes.ordered_list
|| node.type === schema.nodes.todo_list)
|| node.type === schema.nodes.task_list)
}
export const ToggleList = createExtension({

View File

@ -48,7 +48,8 @@ export type NodeViewRendererProps = {
editor: Editor,
node: Node,
getPos: (() => number) | boolean,
decorations: Decoration[]
decorations: Decoration[],
attributes: AnyObject,
}
export type NodeViewRenderer = (props: NodeViewRendererProps) => NodeView

View File

@ -1,8 +1,8 @@
import { Node, Mark } from 'prosemirror-model'
import { ExtensionAttribute } from '../types'
import { ExtensionAttribute, AnyObject } from '../types'
import mergeAttributes from './mergeAttributes'
export default function getRenderedAttributes(nodeOrMark: Node | Mark, extensionAttributes: ExtensionAttribute[]): { [key: string]: any } {
export default function getRenderedAttributes(nodeOrMark: Node | Mark, extensionAttributes: ExtensionAttribute[]): AnyObject {
return extensionAttributes
.filter(item => item.attribute.rendered)
.map(item => {

View File

@ -22,8 +22,14 @@ const TaskItem = createNode({
addAttributes() {
return {
done: {
checked: {
default: false,
parseHTML: element => ({
checked: element.getAttribute('data-checked') === 'true',
}),
renderHTML: attributes => ({
'data-checked': attributes.checked,
}),
},
}
},
@ -42,12 +48,55 @@ const TaskItem = createNode({
},
addKeyboardShortcuts() {
return {
const shortcuts = {
Enter: () => this.editor.splitListItem('task_item'),
}
if (!this.options.nested) {
return shortcuts
}
return {
...shortcuts,
Tab: () => this.editor.sinkListItem('task_item'),
'Shift-Tab': () => this.editor.liftListItem('task_item'),
}
},
addNodeView() {
return ({ attributes, getPos, editor }) => {
const { view } = editor
const listItem = document.createElement('li')
const checkbox = document.createElement('input')
const content = document.createElement('div')
checkbox.type = 'checkbox'
checkbox.addEventListener('change', event => {
const { checked } = event.target as any
if (typeof getPos === 'function') {
view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, {
checked,
}))
}
})
if (attributes['data-checked'] === true) {
checkbox.setAttribute('checked', 'checked')
}
listItem.append(checkbox, content)
Object.entries(attributes).forEach(([key, value]) => {
listItem.setAttribute(key, value)
})
return {
dom: listItem,
contentDOM: content,
}
}
},
})
export default TaskItem