add data-attribute fallback to attribute parser

This commit is contained in:
Philipp Kühn 2020-10-24 23:53:56 +02:00
parent c85844ae11
commit 16d52d05a0
5 changed files with 51 additions and 53 deletions

View File

@ -6,12 +6,9 @@ export type Extensions = (Extension | NodeExtension | MarkExtension)[]
export type Attribute = {
default: any,
rendered?: false,
} | {
default: any,
rendered?: true,
renderHTML: (attributes: { [key: string]: any }) => any,
parseHTML: (node: HTMLElement) => { [key: string]: any },
rendered?: boolean,
renderHTML?: ((attributes: { [key: string]: any }) => any) | null,
parseHTML?: ((node: HTMLElement) => { [key: string]: any }) | null,
}
export type Attributes = {
@ -21,12 +18,7 @@ export type Attributes = {
export type ExtensionAttribute = {
type: string,
name: string,
attribute: {
default: any,
rendered: boolean,
renderHTML: (attributes: { [key: string]: any }) => any,
parseHTML: (node: HTMLElement) => { [key: string]: any },
},
attribute: Required<Attribute>,
}
export type GlobalAttributes = {

View File

@ -14,8 +14,8 @@ export default function getAttributesFromExtensions(extensions: Extensions) {
const defaultAttribute: Required<Attribute> = {
default: null,
rendered: true,
renderHTML: () => ({}),
parseHTML: () => ({}),
renderHTML: null,
parseHTML: null,
}
extensions.forEach(extension => {

View File

@ -1,21 +1,18 @@
import { Node, Mark } from 'prosemirror-model'
import { ExtensionAttribute } from '../types'
import mergeAttributes from './mergeAttributes'
import isEmptyObject from './isEmptyObject'
export default function getRenderedAttributes(nodeOrMark: Node | Mark, extensionAttributes: ExtensionAttribute[]): { [key: string]: any } {
return extensionAttributes
.filter(item => item.attribute.rendered)
.map(item => {
const renderedAttributes = item.attribute.renderHTML(nodeOrMark.attrs)
if (isEmptyObject(renderedAttributes)) {
if (!item.attribute.renderHTML) {
return {
[`data-${item.name}`]: nodeOrMark.attrs[item.name],
}
}
return renderedAttributes
return item.attribute.renderHTML(nodeOrMark.attrs)
})
.reduce((attributes, attribute) => {
return mergeAttributes(attributes, attribute)

View File

@ -1,11 +1,10 @@
import {
NodeSpec, MarkSpec, Schema, ParseRule,
} from 'prosemirror-model'
import { ExtensionAttribute, Extensions } from '../types'
import { NodeSpec, MarkSpec, Schema } from 'prosemirror-model'
import { Extensions } from '../types'
import splitExtensions from './splitExtensions'
import getAttributesFromExtensions from './getAttributesFromExtensions'
import getRenderedAttributes from './getRenderedAttributes'
import isEmptyObject from './isEmptyObject'
import injectExtensionAttributesToParseRule from './injectExtensionAttributesToParseRule'
function cleanUpSchemaItem<T>(data: T) {
return Object.fromEntries(Object.entries(data).filter(([key, value]) => {
@ -17,34 +16,6 @@ function cleanUpSchemaItem<T>(data: T) {
})) as T
}
function injectExtensionAttributes(parseRule: ParseRule, extensionAttributes: ExtensionAttribute[]): ParseRule {
if (parseRule.style) {
return parseRule
}
return {
...parseRule,
getAttrs: node => {
const oldAttributes = parseRule.getAttrs
? parseRule.getAttrs(node)
: parseRule.attrs
if (oldAttributes === false) {
return false
}
const newAttributes = extensionAttributes
.filter(item => item.attribute.rendered)
.reduce((items, item) => ({
...items,
...item.attribute.parseHTML(node as HTMLElement),
}), {})
return { ...oldAttributes, ...newAttributes }
},
}
}
export default function getSchema(extensions: Extensions): Schema {
const allAttributes = getAttributesFromExtensions(extensions)
const { nodeExtensions, markExtensions } = splitExtensions(extensions)
@ -72,7 +43,7 @@ export default function getSchema(extensions: Extensions): Schema {
if (extension.parseHTML) {
schema.parseDOM = extension.parseHTML
.bind(context)()
?.map(parseRule => injectExtensionAttributes(parseRule, extensionAttributes))
?.map(parseRule => injectExtensionAttributesToParseRule(parseRule, extensionAttributes))
}
if (extension.renderHTML) {
@ -101,7 +72,7 @@ export default function getSchema(extensions: Extensions): Schema {
if (extension.parseHTML) {
schema.parseDOM = extension.parseHTML
.bind(context)()
?.map(parseRule => injectExtensionAttributes(parseRule, extensionAttributes))
?.map(parseRule => injectExtensionAttributesToParseRule(parseRule, extensionAttributes))
}
if (extension.renderHTML) {

View File

@ -0,0 +1,38 @@
import { ParseRule } from 'prosemirror-model'
import { ExtensionAttribute } from '../types'
export default function injectExtensionAttributesToParseRule(parseRule: ParseRule, extensionAttributes: ExtensionAttribute[]): ParseRule {
if (parseRule.style) {
return parseRule
}
return {
...parseRule,
getAttrs: node => {
const oldAttributes = parseRule.getAttrs
? parseRule.getAttrs(node)
: parseRule.attrs
if (oldAttributes === false) {
return false
}
const newAttributes = extensionAttributes
.filter(item => item.attribute.rendered)
.reduce((items, item) => {
const attributes = item.attribute.parseHTML
? item.attribute.parseHTML(node as HTMLElement)
: {
[item.name]: (node as HTMLElement).dataset[item.name],
}
return {
...items,
...attributes,
}
}, {})
return { ...oldAttributes, ...newAttributes }
},
}
}