mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-06-07 09:25:29 +08:00
fix: do not modify createNodeFromContent
This commit is contained in:
parent
3f8efb9e64
commit
42f719468b
@ -84,14 +84,28 @@ export const insertContentAt: RawCommands['insertContentAt'] = (position, value,
|
||||
})
|
||||
}
|
||||
|
||||
const parseOptions: ParseOptions = {
|
||||
preserveWhitespace: 'full',
|
||||
...options.parseOptions,
|
||||
}
|
||||
|
||||
// If `emitContentError` is enabled, we want to check the content for errors
|
||||
// but ignore them (do not remove the invalid content from the document)
|
||||
if (!options.errorOnInvalidContent && editor.options.enableContentCheck && editor.options.emitContentError) {
|
||||
try {
|
||||
createNodeFromContent(value, editor.schema, {
|
||||
parseOptions,
|
||||
errorOnInvalidContent: true,
|
||||
})
|
||||
} catch (e) {
|
||||
emitContentError(e as Error)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
content = createNodeFromContent(value, editor.schema, {
|
||||
parseOptions: {
|
||||
preserveWhitespace: 'full',
|
||||
...options.parseOptions,
|
||||
},
|
||||
parseOptions,
|
||||
errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck,
|
||||
onIgnoredError: editor.options.emitContentError ? emitContentError : undefined,
|
||||
})
|
||||
} catch (e) {
|
||||
emitContentError(e as Error)
|
||||
|
@ -13,13 +13,6 @@ export type CreateNodeFromContentOptions = {
|
||||
slice?: boolean
|
||||
parseOptions?: ParseOptions
|
||||
errorOnInvalidContent?: boolean
|
||||
/**
|
||||
* Runs if a content is invalid and an error would have been thrown, but
|
||||
* `errorOnInvalidContent` is `false` so the invalid content is ignored.
|
||||
*
|
||||
* @param error The error that was not thrown
|
||||
*/
|
||||
onIgnoredError?: (error: Error) => void
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,17 +56,12 @@ export function createNodeFromContent(
|
||||
|
||||
return node
|
||||
} catch (error) {
|
||||
const thrownError = new Error('[tiptap error]: Invalid JSON content', { cause: error as Error })
|
||||
|
||||
if (options.errorOnInvalidContent) {
|
||||
throw thrownError
|
||||
}
|
||||
if (options.onIgnoredError) {
|
||||
options.onIgnoredError(thrownError)
|
||||
} else {
|
||||
console.warn('[tiptap warn]: Invalid content.', 'Passed value:', content, 'Error:', error)
|
||||
throw new Error('[tiptap error]: Invalid JSON content', { cause: error as Error })
|
||||
}
|
||||
|
||||
console.warn('[tiptap warn]: Invalid content.', 'Passed value:', content, 'Error:', error)
|
||||
|
||||
return createNodeFromContent('', schema, options)
|
||||
}
|
||||
}
|
||||
@ -117,15 +105,8 @@ export function createNodeFromContent(
|
||||
DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions)
|
||||
}
|
||||
|
||||
if (hasInvalidContent) {
|
||||
const thrownError = new Error('[tiptap error]: Invalid HTML content', { cause: new Error(`Invalid element found: ${invalidContent}`) })
|
||||
|
||||
if (options.errorOnInvalidContent) {
|
||||
throw thrownError
|
||||
} else if (options.onIgnoredError) {
|
||||
options.onIgnoredError(thrownError)
|
||||
}
|
||||
|
||||
if (options.errorOnInvalidContent && hasInvalidContent) {
|
||||
throw new Error('[tiptap error]: Invalid HTML content', { cause: new Error(`Invalid element found: ${invalidContent}`) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ export interface EditorOptions {
|
||||
*/
|
||||
enableContentCheck: boolean;
|
||||
/**
|
||||
* If `true`, the editor will emit the `contentError` event invalid content is
|
||||
* If `true`, the editor will emit the `contentError` event if invalid content is
|
||||
* encountered but `enableContentCheck` is `false`. This lets you preserve the
|
||||
* invalid editor content while still showing a warning or error message to
|
||||
* the user.
|
||||
|
@ -263,121 +263,4 @@ describe('createNodeFromContent', () => {
|
||||
]), { errorOnInvalidContent: true })
|
||||
}).to.throw('[tiptap error]: Invalid JSON content')
|
||||
})
|
||||
|
||||
it('calls onIgnoredError when a schema does not have matching node types for JSON content', () => {
|
||||
const content = {
|
||||
type: 'non-existing-node-type',
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: 'Example Text',
|
||||
}],
|
||||
}
|
||||
|
||||
let errorCalled = false
|
||||
let errorMessage = ''
|
||||
|
||||
const fragment = createNodeFromContent(content, getSchemaByResolvedExtensions([
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
]), {
|
||||
errorOnInvalidContent: false,
|
||||
onIgnoredError: error => {
|
||||
errorCalled = true
|
||||
errorMessage = error.message
|
||||
},
|
||||
})
|
||||
|
||||
expect(errorCalled).to.eq(true)
|
||||
expect(errorMessage).to.eq('[tiptap error]: Invalid JSON content')
|
||||
expect(fragment.toJSON()).to.deep.eq(null)
|
||||
})
|
||||
|
||||
it('calls onIgnoredError when a schema does not have matching node types for HTML content', () => {
|
||||
const content = '<non-existing-node-type>Example Text</non-existing-node-type>'
|
||||
|
||||
let errorCalled = false
|
||||
let errorMessage = ''
|
||||
|
||||
const fragment = createNodeFromContent(content, getSchemaByResolvedExtensions([
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
]), {
|
||||
errorOnInvalidContent: false,
|
||||
onIgnoredError: error => {
|
||||
errorCalled = true
|
||||
errorMessage = error.message
|
||||
},
|
||||
})
|
||||
|
||||
expect(errorCalled).to.eq(true)
|
||||
expect(errorMessage).to.eq('[tiptap error]: Invalid HTML content')
|
||||
expect(fragment.toJSON()).to.deep.eq([{ type: 'text', text: 'Example Text' }])
|
||||
})
|
||||
|
||||
it('calls onIgnoredError when a schema does not have matching mark types for JSON content', () => {
|
||||
const content = {
|
||||
type: 'paragraph',
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: 'Example Text',
|
||||
marks: [{
|
||||
type: 'non-existing-mark-type',
|
||||
}],
|
||||
}],
|
||||
}
|
||||
|
||||
let errorCalled = false
|
||||
let errorMessage = ''
|
||||
|
||||
const fragment = createNodeFromContent(content, getSchemaByResolvedExtensions([
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
]), {
|
||||
errorOnInvalidContent: false,
|
||||
onIgnoredError: error => {
|
||||
errorCalled = true
|
||||
errorMessage = error.message
|
||||
},
|
||||
})
|
||||
|
||||
expect(errorCalled).to.eq(true)
|
||||
expect(errorMessage).to.eq('[tiptap error]: Invalid JSON content')
|
||||
expect(fragment.toJSON()).to.deep.eq(null)
|
||||
})
|
||||
|
||||
it('calls onIgnoredError when the JSON content does not follow the nesting rules of the schema', () => {
|
||||
const content = {
|
||||
type: 'paragraph',
|
||||
content: [{
|
||||
type: 'paragraph',
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: 'Example Text',
|
||||
}],
|
||||
}],
|
||||
}
|
||||
|
||||
let errorCalled = false
|
||||
let errorMessage = ''
|
||||
|
||||
const fragment = createNodeFromContent(content, getSchemaByResolvedExtensions([
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
]), {
|
||||
errorOnInvalidContent: false,
|
||||
onIgnoredError: error => {
|
||||
errorCalled = true
|
||||
errorMessage = error.message
|
||||
},
|
||||
})
|
||||
|
||||
expect(errorCalled).to.eq(true)
|
||||
expect(errorMessage).to.eq('[tiptap error]: Invalid JSON content')
|
||||
expect(fragment.toJSON()).to.deep.eq(null)
|
||||
})
|
||||
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user