From 48cc408a971a941cf731aedc55f6a36504de8106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Tue, 23 Jul 2019 18:30:59 +0200 Subject: [PATCH] add TrailingNode extension --- examples/Components/Routes/Embeds/index.vue | 2 + .../src/extensions/TrailingNode.js | 61 +++++++++++++++++++ packages/tiptap-extensions/src/index.js | 1 + 3 files changed, 64 insertions(+) create mode 100644 packages/tiptap-extensions/src/extensions/TrailingNode.js diff --git a/examples/Components/Routes/Embeds/index.vue b/examples/Components/Routes/Embeds/index.vue index 907dbc9f6..d376e4807 100644 --- a/examples/Components/Routes/Embeds/index.vue +++ b/examples/Components/Routes/Embeds/index.vue @@ -12,6 +12,7 @@ import { Bold, Italic, History, + TrailingNode, } from 'tiptap-extensions' import Iframe from './Iframe.js' @@ -28,6 +29,7 @@ export default { new Bold(), new Italic(), new History(), + new TrailingNode(), // custom extension new Iframe(), ], diff --git a/packages/tiptap-extensions/src/extensions/TrailingNode.js b/packages/tiptap-extensions/src/extensions/TrailingNode.js new file mode 100644 index 000000000..1beb40f21 --- /dev/null +++ b/packages/tiptap-extensions/src/extensions/TrailingNode.js @@ -0,0 +1,61 @@ +import { Extension, Plugin, PluginKey } from 'tiptap' +import { nodeEqualsType } from 'tiptap-utils' + +export default class TrailingNode extends Extension { + + get name() { + return 'trailing_node' + } + + get defaultOptions() { + return { + node: 'paragraph', + notAfter: [ + 'paragraph', + 'heading', + ], + } + } + + get plugins() { + const plugin = new PluginKey(this.name) + const disabledNodes = Object.entries(this.editor.schema.nodes) + .map(([, value]) => value) + .filter(node => this.options.notAfter.includes(node.name)) + + return [ + new Plugin({ + key: plugin, + view: () => ({ + update: view => { + const { state } = view + const { doc } = state + const insertNodeAtEnd = plugin.getState(state) + + if (!insertNodeAtEnd) { + return + } + + const type = state.schema.nodes[this.options.node] + view.dispatch(view.state.tr.insert(doc.content.size, type.create())) + }, + }), + state: { + init: (_, state) => { + const lastNode = state.tr.doc.lastChild + return !nodeEqualsType({ node: lastNode, types: disabledNodes }) + }, + apply: (tr, oldState) => { + if (!tr.docChanged) { + return oldState + } + + const lastNode = tr.doc.lastChild + return !nodeEqualsType({ node: lastNode, types: disabledNodes }) + }, + }, + }), + ] + } + +} diff --git a/packages/tiptap-extensions/src/index.js b/packages/tiptap-extensions/src/index.js index b38176962..3165bccb1 100644 --- a/packages/tiptap-extensions/src/index.js +++ b/packages/tiptap-extensions/src/index.js @@ -27,6 +27,7 @@ export { default as Collaboration } from './extensions/Collaboration' export { default as History } from './extensions/History' export { default as Placeholder } from './extensions/Placeholder' export { default as Search } from './extensions/Search' +export { default as TrailingNode } from './extensions/TrailingNode' export { default as Suggestions } from './plugins/Suggestions' export { default as Highlight } from './plugins/Highlight'