From a24fdac9f75765aa555ef0ebe1535799daafdbf2 Mon Sep 17 00:00:00 2001 From: Chrissi2812 Date: Fri, 17 May 2019 15:50:59 +0200 Subject: [PATCH 1/7] toggle between unordered_list and ordered_list --- .../src/commands/toggleList.js | 66 +++++++------------ 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/packages/tiptap-commands/src/commands/toggleList.js b/packages/tiptap-commands/src/commands/toggleList.js index 7fd1703e..ad7fde5c 100644 --- a/packages/tiptap-commands/src/commands/toggleList.js +++ b/packages/tiptap-commands/src/commands/toggleList.js @@ -1,49 +1,31 @@ -import { nodeIsActive } from 'tiptap-utils' import { wrapInList, liftListItem } from 'prosemirror-schema-list' -export default function toggleList(type, itemType) { - return (state, dispatch, view) => { - const isActive = nodeIsActive(state, type) - - if (isActive) { - return liftListItem(itemType)(state, dispatch, view) - } - - return wrapInList(type)(state, dispatch, view) - } +function isList(node, schema) { + return (node.type === schema.nodes.bullet_list || node.type === schema.nodes.ordered_list) } -// https://discuss.prosemirror.net/t/list-type-toggle/948 +export default function toggleList(listType) { + return (state, dispatch) => { + const { schema } = state + const lift = liftListItem(schema.nodes.list_item) + const wrap = wrapInList(listType) + const { $from, $to } = state.selection + const range = $from.blockRange($to) + if (!range) { + return false + } -// import { wrapInList, liftListItem } from 'prosemirror-schema-list' + if (range.depth >= 1 && $from.node(range.depth).type === listType) { + return lift(state, dispatch) + } -// function isList(node, schema) { -// return (node.type === schema.nodes.bullet_list || node.type === schema.nodes.ordered_list) -// } + if (range.depth >= 1 && isList($from.node(range.depth), schema)) { + const { tr } = state + tr.setNodeMarkup(range.start - 1, listType) + if (dispatch) dispatch(tr) + return false + } -// export default function toggleList(listType, schema) { -// const lift = liftListItem(schema.nodes.list_item) -// const wrap = wrapInList(listType) - -// return (state, dispatch) => { -// const { $from, $to } = state.selection -// const range = $from.blockRange($to) -// if (!range) { -// return false -// } - -// if (range.depth >= 2 && $from.node(range.depth - 1).type === listType) { -// return lift(state, dispatch) -// } else if (range.depth >= 2 && isList($from.node(range.depth - 1), schema)) { -// const tr = state.tr -// const node = $from.before(range.depth - 1) -// console.log({node}) -// // TODO: how do I pass the node above to `setNodeType`? -// // tr.setNodeType(range.start, listType); -// if (dispatch) dispatch(tr) -// return false -// } else { -// return wrap(state, dispatch) -// } -// } -// } + return wrap(state, dispatch) + } +} From ac89ca404a310ef97430b9b59a56cb5030684c30 Mon Sep 17 00:00:00 2001 From: Chrissi2812 Date: Mon, 20 May 2019 12:05:11 +0200 Subject: [PATCH 2/7] fixed offset problems with toggleList --- packages/tiptap-commands/src/commands/toggleList.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/tiptap-commands/src/commands/toggleList.js b/packages/tiptap-commands/src/commands/toggleList.js index ad7fde5c..0a7a22d7 100644 --- a/packages/tiptap-commands/src/commands/toggleList.js +++ b/packages/tiptap-commands/src/commands/toggleList.js @@ -11,17 +11,19 @@ export default function toggleList(listType) { const wrap = wrapInList(listType) const { $from, $to } = state.selection const range = $from.blockRange($to) + const depthOffset = range.depth > 1 ? ((range.depth + 1) % 2) : 0 if (!range) { return false } - if (range.depth >= 1 && $from.node(range.depth).type === listType) { + if (range.depth >= 1 && $from.node(range.depth - depthOffset).type === listType) { return lift(state, dispatch) } - if (range.depth >= 1 && isList($from.node(range.depth), schema)) { + if (range.depth >= 1 && isList($from.node(range.depth - depthOffset), schema)) { const { tr } = state - tr.setNodeMarkup(range.start - 1, listType) + const $insert = state.doc.resolve(range.start - depthOffset) + tr.setNodeMarkup(range.start - (1 + depthOffset) - $insert.parentOffset, listType) if (dispatch) dispatch(tr) return false } From 6cb1c0436b0115e094e3738807b690555a992579 Mon Sep 17 00:00:00 2001 From: Chrissi2812 Date: Mon, 20 May 2019 14:30:40 +0200 Subject: [PATCH 3/7] use findParentNode to find parent list instead of arbitary offsets --- packages/tiptap-commands/package.json | 1 + .../src/commands/toggleList.js | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/tiptap-commands/package.json b/packages/tiptap-commands/package.json index 9b1fa756..0a882b86 100644 --- a/packages/tiptap-commands/package.json +++ b/packages/tiptap-commands/package.json @@ -25,6 +25,7 @@ "prosemirror-model": "^1.7.0", "prosemirror-schema-list": "^1.0.3", "prosemirror-state": "^1.2.3", + "prosemirror-utils": "^0.8.1", "tiptap-utils": "^1.5.2" } } diff --git a/packages/tiptap-commands/src/commands/toggleList.js b/packages/tiptap-commands/src/commands/toggleList.js index 0a7a22d7..23529fdf 100644 --- a/packages/tiptap-commands/src/commands/toggleList.js +++ b/packages/tiptap-commands/src/commands/toggleList.js @@ -1,4 +1,5 @@ import { wrapInList, liftListItem } from 'prosemirror-schema-list' +import { findParentNode } from 'prosemirror-utils' function isList(node, schema) { return (node.type === schema.nodes.bullet_list || node.type === schema.nodes.ordered_list) @@ -6,26 +7,28 @@ function isList(node, schema) { export default function toggleList(listType) { return (state, dispatch) => { - const { schema } = state + const { schema, selection } = state const lift = liftListItem(schema.nodes.list_item) const wrap = wrapInList(listType) - const { $from, $to } = state.selection + const { $from, $to } = selection const range = $from.blockRange($to) - const depthOffset = range.depth > 1 ? ((range.depth + 1) % 2) : 0 if (!range) { return false } - if (range.depth >= 1 && $from.node(range.depth - depthOffset).type === listType) { - return lift(state, dispatch) - } + const parentList = findParentNode(node => isList(node, schema))(selection) - if (range.depth >= 1 && isList($from.node(range.depth - depthOffset), schema)) { - const { tr } = state - const $insert = state.doc.resolve(range.start - depthOffset) - tr.setNodeMarkup(range.start - (1 + depthOffset) - $insert.parentOffset, listType) - if (dispatch) dispatch(tr) - return false + if (range.depth >= 1 && parentList) { + if (parentList.node.type === listType) { + return lift(state, dispatch) + } + + if (isList(parentList.node, schema)) { + const { tr } = state + tr.setNodeMarkup(parentList.pos, listType) + if (dispatch) dispatch(tr) + return false + } } return wrap(state, dispatch) From a6baa66e89954fa6f4cf1a71b4c98c8de6ed611d Mon Sep 17 00:00:00 2001 From: Chrissi2812 Date: Mon, 20 May 2019 14:54:25 +0200 Subject: [PATCH 4/7] fixed todo_lists in toggleList method --- .../tiptap-commands/src/commands/toggleList.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/tiptap-commands/src/commands/toggleList.js b/packages/tiptap-commands/src/commands/toggleList.js index 23529fdf..587644c9 100644 --- a/packages/tiptap-commands/src/commands/toggleList.js +++ b/packages/tiptap-commands/src/commands/toggleList.js @@ -2,13 +2,15 @@ import { wrapInList, liftListItem } from 'prosemirror-schema-list' import { findParentNode } from 'prosemirror-utils' function isList(node, schema) { - return (node.type === schema.nodes.bullet_list || node.type === schema.nodes.ordered_list) + return (node.type === schema.nodes.bullet_list + || node.type === schema.nodes.ordered_list + || node.type === schema.nodes.todo_list) } -export default function toggleList(listType) { - return (state, dispatch) => { +export default function toggleList(listType, itemType) { + return (state, dispatch, view) => { const { schema, selection } = state - const lift = liftListItem(schema.nodes.list_item) + const lift = liftListItem(itemType) const wrap = wrapInList(listType) const { $from, $to } = selection const range = $from.blockRange($to) @@ -20,7 +22,7 @@ export default function toggleList(listType) { if (range.depth >= 1 && parentList) { if (parentList.node.type === listType) { - return lift(state, dispatch) + return lift(state, dispatch, view) } if (isList(parentList.node, schema)) { @@ -31,6 +33,6 @@ export default function toggleList(listType) { } } - return wrap(state, dispatch) + return wrap(state, dispatch, view) } } From 670936a1603f4a8ee46eac1cba44e4c9ea92524a Mon Sep 17 00:00:00 2001 From: Chrissi2812 Date: Mon, 20 May 2019 15:00:19 +0200 Subject: [PATCH 5/7] moved liftListItem and wrapInList methods in conditional block this makes more sense because both functions are only called once and can't be chained as I initially thought. --- packages/tiptap-commands/src/commands/toggleList.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/tiptap-commands/src/commands/toggleList.js b/packages/tiptap-commands/src/commands/toggleList.js index 587644c9..df8bc1c2 100644 --- a/packages/tiptap-commands/src/commands/toggleList.js +++ b/packages/tiptap-commands/src/commands/toggleList.js @@ -10,8 +10,6 @@ function isList(node, schema) { export default function toggleList(listType, itemType) { return (state, dispatch, view) => { const { schema, selection } = state - const lift = liftListItem(itemType) - const wrap = wrapInList(listType) const { $from, $to } = selection const range = $from.blockRange($to) if (!range) { @@ -22,7 +20,7 @@ export default function toggleList(listType, itemType) { if (range.depth >= 1 && parentList) { if (parentList.node.type === listType) { - return lift(state, dispatch, view) + return liftListItem(itemType)(state, dispatch, view) } if (isList(parentList.node, schema)) { @@ -33,6 +31,6 @@ export default function toggleList(listType, itemType) { } } - return wrap(state, dispatch, view) + return wrapInList(listType)(state, dispatch, view) } } From a0dae562c27776333f934621ae79591c04bbda12 Mon Sep 17 00:00:00 2001 From: Chrissi2812 Date: Mon, 20 May 2019 15:40:31 +0200 Subject: [PATCH 6/7] prevents invalid content in toggleList This will skip the replace step for invalid content and instead inserts a new list of selected type --- packages/tiptap-commands/src/commands/toggleList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tiptap-commands/src/commands/toggleList.js b/packages/tiptap-commands/src/commands/toggleList.js index df8bc1c2..8d71b73f 100644 --- a/packages/tiptap-commands/src/commands/toggleList.js +++ b/packages/tiptap-commands/src/commands/toggleList.js @@ -23,7 +23,7 @@ export default function toggleList(listType, itemType) { return liftListItem(itemType)(state, dispatch, view) } - if (isList(parentList.node, schema)) { + if (isList(parentList.node, schema) && listType.validContent(parentList.node.content)) { const { tr } = state tr.setNodeMarkup(parentList.pos, listType) if (dispatch) dispatch(tr) From 2291c699ad2d35cbb29061fd57a02ec09b0061a1 Mon Sep 17 00:00:00 2001 From: Chrissi2812 Date: Mon, 20 May 2019 15:44:11 +0200 Subject: [PATCH 7/7] only lift list_item if we are currently in a list this allows to use lists in blockquotes that are in another list. --- packages/tiptap-commands/src/commands/toggleList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tiptap-commands/src/commands/toggleList.js b/packages/tiptap-commands/src/commands/toggleList.js index 8d71b73f..6e7adab3 100644 --- a/packages/tiptap-commands/src/commands/toggleList.js +++ b/packages/tiptap-commands/src/commands/toggleList.js @@ -18,7 +18,7 @@ export default function toggleList(listType, itemType) { const parentList = findParentNode(node => isList(node, schema))(selection) - if (range.depth >= 1 && parentList) { + if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) { if (parentList.node.type === listType) { return liftListItem(itemType)(state, dispatch, view) }