feat: parseHTML for attributes should return the value instead of an object now, fix #1863

This commit is contained in:
Philipp Kühn 2021-09-08 23:53:44 +02:00
parent d3285e9308
commit 8a3b47a529
17 changed files with 38 additions and 92 deletions

View File

@ -16,11 +16,7 @@ const CustomTableCell = TableCell.extend({
// and add a new one
backgroundColor: {
default: null,
parseHTML: element => {
return {
backgroundColor: element.getAttribute('data-background-color'),
}
},
parseHTML: element => element.getAttribute('data-background-color'),
renderHTML: attributes => {
return {
'data-background-color': attributes.backgroundColor,

View File

@ -76,11 +76,7 @@ const CustomTableCell = TableCell.extend({
// and add a new one
backgroundColor: {
default: null,
parseHTML: element => {
return {
backgroundColor: element.getAttribute('data-background-color'),
}
},
parseHTML: element => element.getAttribute('data-background-color'),
renderHTML: attributes => {
return {
'data-background-color': attributes.backgroundColor,

View File

@ -42,11 +42,7 @@ export default Node.create({
},
allowfullscreen: {
default: this.options.allowFullscreen,
parseHTML: () => {
return {
allowfullscreen: this.options.allowFullscreen,
}
},
parseHTML: () => this.options.allowFullscreen,
},
}
},

View File

@ -57,29 +57,17 @@ export const Figure = Node.create<FigureOptions>({
return {
src: {
default: null,
parseHTML: element => {
return {
src: element.querySelector('img')?.getAttribute('src'),
}
},
parseHTML: element => element.querySelector('img')?.getAttribute('src'),
},
alt: {
default: null,
parseHTML: element => {
return {
alt: element.querySelector('img')?.getAttribute('alt'),
}
},
parseHTML: element => element.querySelector('img')?.getAttribute('alt'),
},
title: {
default: null,
parseHTML: element => {
return {
title: element.querySelector('img')?.getAttribute('title'),
}
},
parseHTML: element => element.querySelector('img')?.getAttribute('title'),
},
}
},

View File

@ -163,11 +163,7 @@ const CustomParagraph = Paragraph.extend({
color: {
default: null,
// Customize the HTML parsing (for example, to load the initial content)
parseHTML: element => {
return {
color: element.getAttribute('data-color'),
}
},
parseHTML: element => element.getAttribute('data-color'),
// … and customize the HTML rendering.
renderHTML: attributes => {
return {
@ -228,9 +224,7 @@ const TextAlign = Extension.create({
renderHTML: attributes => ({
style: `text-align: ${attributes.textAlign}`,
}),
parseHTML: element => ({
textAlign: element.style.textAlign || 'left',
}),
parseHTML: element => element.style.textAlign || 'left',
},
},
},

View File

@ -1,6 +1,7 @@
import { ParseRule } from 'prosemirror-model'
import { ExtensionAttribute } from '../types'
import fromString from '../utilities/fromString'
import isObject from '../utilities/isObject'
/**
* This function merges extension attributes into parserule attributes (`attrs` or `getAttrs`).
@ -27,18 +28,21 @@ export default function injectExtensionAttributesToParseRule(parseRule: ParseRul
const newAttributes = extensionAttributes
.filter(item => item.attribute.rendered)
.reduce((items, item) => {
const attributes = item.attribute.parseHTML
? item.attribute.parseHTML(node as HTMLElement) || {}
: {
[item.name]: fromString((node as HTMLElement).getAttribute(item.name)),
const value = item.attribute.parseHTML
? item.attribute.parseHTML(node as HTMLElement)
: fromString((node as HTMLElement).getAttribute(item.name))
if (isObject(value)) {
console.warn(`[tiptap warn]: BREAKING CHANGE: "parseHTML" for your attribute "${item.name}" returns an object but should return the value itself. If this is expected you can ignore this message. This warning will be removed in one of the next releases. Further information: https://github.com/ueberdosis/tiptap/issues/1863`)
}
const filteredAttributes = Object.fromEntries(Object.entries(attributes)
.filter(([, value]) => value !== undefined && value !== null))
if (value === null || value === undefined) {
return items
}
return {
...items,
...filteredAttributes,
[item.name]: value,
}
}, {})

View File

@ -98,7 +98,7 @@ export type Attribute = {
default: any,
rendered?: boolean,
renderHTML?: ((attributes: Record<string, any>) => Record<string, any> | null) | null,
parseHTML?: ((element: HTMLElement) => Record<string, any> | null) | null,
parseHTML?: ((element: HTMLElement) => any | null) | null,
keepOnSplit: boolean,
}

View File

@ -58,9 +58,7 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
return null
}
return {
language,
}
return language
},
renderHTML: attributes => {
if (!attributes.language) {

View File

@ -34,6 +34,7 @@ export const Color = Extension.create<ColorOptions>({
attributes: {
color: {
default: null,
parseHTML: element => element.style.color.replace(/['"]+/g, ''),
renderHTML: attributes => {
if (!attributes.color) {
return {}
@ -43,11 +44,6 @@ export const Color = Extension.create<ColorOptions>({
style: `color: ${attributes.color}`,
}
},
parseHTML: element => {
return {
color: element.style.color.replace(/['"]+/g, ''),
}
},
},
},
},

View File

@ -34,6 +34,7 @@ export const FontFamily = Extension.create<FontFamilyOptions>({
attributes: {
fontFamily: {
default: null,
parseHTML: element => element.style.fontFamily.replace(/['"]+/g, ''),
renderHTML: attributes => {
if (!attributes.fontFamily) {
return {}
@ -43,9 +44,6 @@ export const FontFamily = Extension.create<FontFamilyOptions>({
style: `font-family: ${attributes.fontFamily}`,
}
},
parseHTML: element => ({
fontFamily: element.style.fontFamily.replace(/['"]+/g, ''),
}),
},
},
},

View File

@ -48,11 +48,7 @@ export const Highlight = Mark.create<HighlightOptions>({
return {
color: {
default: null,
parseHTML: element => {
return {
color: element.getAttribute('data-color') || element.style.backgroundColor,
}
},
parseHTML: element => element.getAttribute('data-color') || element.style.backgroundColor,
renderHTML: attributes => {
if (!attributes.color) {
return {}

View File

@ -68,11 +68,7 @@ export const Mention = Node.create<MentionOptions>({
return {
id: {
default: null,
parseHTML: element => {
return {
id: element.getAttribute('data-id'),
}
},
parseHTML: element => element.getAttribute('data-id'),
renderHTML: attributes => {
if (!attributes.id) {
return {}
@ -86,11 +82,7 @@ export const Mention = Node.create<MentionOptions>({
label: {
default: null,
parseHTML: element => {
return {
label: element.getAttribute('data-label'),
}
},
parseHTML: element => element.getAttribute('data-label'),
renderHTML: attributes => {
if (!attributes.label) {
return {}

View File

@ -33,11 +33,11 @@ export const OrderedList = Node.create<OrderedListOptions>({
return {
start: {
default: 1,
parseHTML: element => ({
start: element.hasAttribute('start')
parseHTML: element => {
return element.hasAttribute('start')
? parseInt(element.getAttribute('start') || '', 10)
: 1,
}),
: 1
},
},
}
},

View File

@ -29,9 +29,7 @@ export const TableCell = Node.create<TableCellOptions>({
? [parseInt(colwidth, 10)]
: null
return {
colwidth: value,
}
return value
},
},
}

View File

@ -28,9 +28,7 @@ export const TableHeader = Node.create<TableHeaderOptions>({
? [parseInt(colwidth, 10)]
: null
return {
colwidth: value,
}
return value
},
},
}

View File

@ -26,13 +26,11 @@ export const TaskItem = Node.create<TaskItemOptions>({
return {
checked: {
default: false,
parseHTML: element => ({
checked: element.getAttribute('data-checked') === 'true',
}),
keepOnSplit: false,
parseHTML: element => element.getAttribute('data-checked') === 'true',
renderHTML: attributes => ({
'data-checked': attributes.checked,
}),
keepOnSplit: false,
},
}
},

View File

@ -37,9 +37,7 @@ export const TextAlign = Extension.create<TextAlignOptions>({
attributes: {
textAlign: {
default: this.options.defaultAlignment,
parseHTML: element => ({
textAlign: element.style.textAlign || this.options.defaultAlignment,
}),
parseHTML: element => element.style.textAlign || this.options.defaultAlignment,
renderHTML: attributes => {
if (attributes.textAlign === this.options.defaultAlignment) {
return {}