mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-01-18 06:03:22 +08:00
feat: parseHTML for attributes should return the value instead of an object now, fix #1863
This commit is contained in:
parent
d3285e9308
commit
8a3b47a529
@ -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,
|
||||
@ -36,7 +32,7 @@ export const tableHTML = `
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<th>Firstname</th>
|
||||
<th>Lastname</th>
|
||||
<th>Lastname</th>
|
||||
<th>Age</th>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -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,
|
||||
|
@ -42,11 +42,7 @@ export default Node.create({
|
||||
},
|
||||
allowfullscreen: {
|
||||
default: this.options.allowFullscreen,
|
||||
parseHTML: () => {
|
||||
return {
|
||||
allowfullscreen: this.options.allowFullscreen,
|
||||
}
|
||||
},
|
||||
parseHTML: () => this.options.allowFullscreen,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -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'),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -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 {
|
||||
@ -187,7 +183,7 @@ const CustomParagraph = Paragraph.extend({
|
||||
You can completly disable the rendering of attributes with `rendered: false`.
|
||||
|
||||
#### Extend existing attributes
|
||||
If you want to add an attribute to an extension and keep existing attributes, you can access them through `this.parent()`.
|
||||
If you want to add an attribute to an extension and keep existing attributes, you can access them through `this.parent()`.
|
||||
|
||||
In some cases, it is undefined, so make sure to check for that case, or use optional chaining `this.parent?.()`
|
||||
|
||||
@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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))
|
||||
|
||||
const filteredAttributes = Object.fromEntries(Object.entries(attributes)
|
||||
.filter(([, value]) => value !== undefined && value !== null))
|
||||
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`)
|
||||
}
|
||||
|
||||
if (value === null || value === undefined) {
|
||||
return items
|
||||
}
|
||||
|
||||
return {
|
||||
...items,
|
||||
...filteredAttributes,
|
||||
[item.name]: value,
|
||||
}
|
||||
}, {})
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -58,9 +58,7 @@ export const CodeBlock = Node.create<CodeBlockOptions>({
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
language,
|
||||
}
|
||||
return language
|
||||
},
|
||||
renderHTML: attributes => {
|
||||
if (!attributes.language) {
|
||||
|
@ -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, ''),
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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, ''),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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 {}
|
||||
|
@ -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 {}
|
||||
|
@ -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
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -29,9 +29,7 @@ export const TableCell = Node.create<TableCellOptions>({
|
||||
? [parseInt(colwidth, 10)]
|
||||
: null
|
||||
|
||||
return {
|
||||
colwidth: value,
|
||||
}
|
||||
return value
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -28,9 +28,7 @@ export const TableHeader = Node.create<TableHeaderOptions>({
|
||||
? [parseInt(colwidth, 10)]
|
||||
: null
|
||||
|
||||
return {
|
||||
colwidth: value,
|
||||
}
|
||||
return value
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -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 {}
|
||||
|
Loading…
Reference in New Issue
Block a user