Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/text.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/nodes/TaskItem.js')
-rw-r--r--src/nodes/TaskItem.js134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/nodes/TaskItem.js b/src/nodes/TaskItem.js
new file mode 100644
index 000000000..74db3e82a
--- /dev/null
+++ b/src/nodes/TaskItem.js
@@ -0,0 +1,134 @@
+/*
+ * @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>
+ *
+ * @author Julius Härtl <jus@bitgrid.net>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import TipTapTaskItem from '@tiptap/extension-task-item'
+import { wrappingInputRule, mergeAttributes } from '@tiptap/core'
+import { Plugin } from 'prosemirror-state'
+import { findParentNodeClosestToPos } from 'prosemirror-utils'
+
+const TaskItem = TipTapTaskItem.extend({
+
+ addOptions() {
+ return {
+ nested: true,
+ HTMLAttributes: {},
+ }
+ },
+
+ draggable: false,
+
+ content: 'paragraph block*',
+
+ addAttributes() {
+ const adjust = { ...this.parent() }
+ adjust.checked.parseHTML = el => {
+ return el.querySelector('input[type=checkbox]')?.checked
+ }
+ return adjust
+ },
+
+ parseHTML: [
+ {
+ priority: 101,
+ tag: 'li',
+ getAttrs: el => {
+ const checkbox = el.querySelector('input[type=checkbox]')
+ return checkbox
+ },
+ context: 'taskList/',
+ },
+ ],
+
+ renderHTML({ node, HTMLAttributes }) {
+ const listAttributes = { class: 'checkbox-item' }
+ const checkboxAttributes = { type: 'checkbox', class: '', contenteditable: false }
+ if (node.attrs.checked) {
+ checkboxAttributes.checked = true
+ listAttributes.class += ' checked'
+ }
+ return [
+ 'li',
+ mergeAttributes(HTMLAttributes, listAttributes),
+ [
+ 'input',
+ checkboxAttributes,
+ ],
+ [
+ 'label',
+ 0,
+ ],
+ ]
+ },
+
+ // overwrite the parent node view so renderHTML gets used
+ addNodeView: false,
+
+ toMarkdown: (state, node) => {
+ state.write(`[${node.attrs.checked ? 'x' : ' '}] `)
+ state.renderContent(node)
+ },
+
+ addInputRules() {
+ return [
+ ...this.parent(),
+ wrappingInputRule({
+ find: /^\s*([-+*])\s(\[(x|X| ?)\])\s$/,
+ type: this.type,
+ getAttributes: match => ({
+ checked: 'xX'.includes(match[match.length - 1]),
+ }),
+ }),
+ ]
+ },
+
+ addProseMirrorPlugins() {
+ return [
+ new Plugin({
+ props: {
+ handleClick: (view, pos, event) => {
+ const state = view.state
+ const schema = state.schema
+
+ const coordinates = view.posAtCoords({ left: event.clientX, top: event.clientY })
+ const position = state.doc.resolve(coordinates.pos)
+ const parentList = findParentNodeClosestToPos(position, function(node) {
+ return node.type === schema.nodes.taskItem
+ || node.type === schema.nodes.listItem
+ })
+ const isListClicked = event.target.tagName.toLowerCase() === 'li'
+ if (!isListClicked
+ || !parentList
+ || parentList.node.type !== schema.nodes.taskItem) {
+ return
+ }
+ const tr = state.tr
+ tr.setNodeMarkup(parentList.pos, schema.nodes.taskItem, { checked: !parentList.node.attrs.checked })
+ view.dispatch(tr)
+ },
+ },
+ }),
+ ]
+ },
+
+})
+
+export default TaskItem