Merge branch 'main' of github.com:ueberdosis/tiptap-next into main

This commit is contained in:
Hans Pagel
2020-12-02 15:35:52 +01:00
4 changed files with 72 additions and 30 deletions

View File

@@ -47,10 +47,10 @@ export default {
isActive: () => this.editor.isActive('code'), isActive: () => this.editor.isActive('code'),
}, },
{ {
icon: 'paragraph', icon: 'mark-pen-line',
title: 'Paragraph', title: 'Highlight',
action: () => this.editor.chain().focus().setParagraph().run(), action: () => this.editor.chain().focus().toggleHighlight().run(),
isActive: () => this.editor.isActive('paragraph'), isActive: () => this.editor.isActive('highlight'),
}, },
{ {
icon: 'h-1', icon: 'h-1',
@@ -65,28 +65,10 @@ export default {
isActive: () => this.editor.isActive('heading', { level: 2 }), isActive: () => this.editor.isActive('heading', { level: 2 }),
}, },
{ {
icon: 'h-3', icon: 'paragraph',
title: 'Heading 3', title: 'Paragraph',
action: () => this.editor.chain().focus().toggleHeading({ level: 3 }).run(), action: () => this.editor.chain().focus().setParagraph().run(),
isActive: () => this.editor.isActive('heading', { level: 3 }), isActive: () => this.editor.isActive('paragraph'),
},
{
icon: 'h-4',
title: 'Heading 4',
action: () => this.editor.chain().focus().toggleHeading({ level: 4 }).run(),
isActive: () => this.editor.isActive('heading', { level: 4 }),
},
{
icon: 'h-5',
title: 'Heading 5',
action: () => this.editor.chain().focus().toggleHeading({ level: 5 }).run(),
isActive: () => this.editor.isActive('heading', { level: 5 }),
},
{
icon: 'h-6',
title: 'Heading 6',
action: () => this.editor.chain().focus().toggleHeading({ level: 6 }).run(),
isActive: () => this.editor.isActive('heading', { level: 6 }),
}, },
{ {
icon: 'list-unordered', icon: 'list-unordered',
@@ -100,6 +82,12 @@ export default {
action: () => this.editor.chain().focus().toggleOrderedList().run(), action: () => this.editor.chain().focus().toggleOrderedList().run(),
isActive: () => this.editor.isActive('orderedList'), isActive: () => this.editor.isActive('orderedList'),
}, },
{
icon: 'list-check-2',
title: 'Task List',
action: () => this.editor.chain().focus().toggleTaskList().run(),
isActive: () => this.editor.isActive('taskList'),
},
{ {
icon: 'code-box-line', icon: 'code-box-line',
title: 'Code Block', title: 'Code Block',

View File

@@ -41,6 +41,9 @@
import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit' import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit'
import Collaboration from '@tiptap/extension-collaboration' import Collaboration from '@tiptap/extension-collaboration'
import CollaborationCursor from '@tiptap/extension-collaboration-cursor' import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
import TaskList from '@tiptap/extension-task-list'
import TaskItem from '@tiptap/extension-task-item'
import Highlight from '@tiptap/extension-highlight'
import * as Y from 'yjs' import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket' import { WebsocketProvider } from 'y-websocket'
import { IndexeddbPersistence } from 'y-indexeddb' import { IndexeddbPersistence } from 'y-indexeddb'
@@ -81,6 +84,9 @@ export default {
this.editor = new Editor({ this.editor = new Editor({
extensions: [ extensions: [
...defaultExtensions().filter(extension => extension.config.name !== 'history'), ...defaultExtensions().filter(extension => extension.config.name !== 'history'),
Highlight,
TaskList,
TaskItem,
Collaboration.configure({ Collaboration.configure({
provider, provider,
}), }),

View File

@@ -205,17 +205,55 @@ Yes, its magic. As already mentioned, that is all based on the fantastic Y.js
## Store the content ## Store the content
Our collaborative editing backend is ready to handle advanced use cases, like authorization, persistence and scaling. Lets go through a few common use cases here! Our collaborative editing backend is ready to handle advanced use cases, like authorization, persistence and scaling. Lets go through a few common use cases here!
### Authentication
With the `onConnect` hook you can write a custom Promise to check if a client is authenticated. That can be a request to an API, to a microservice, a database query, or whatever is needed, as long as its executing `resolve()` at some point. You can also pass contextual data to the `resolve()` method which will be accessible in other hooks.
```js
import { Server } from '@hocuspocus/server'
const server = Server.configure({
onConnect(data, resolve, reject) {
const { requestHeaders } = data
// Your code here, for example a request to an API
// If the user is not authorized …
if (requestHeaders.access_token !== 'super-secret-token') {
return reject()
}
// Set contextual data
const context = {
user_id: 1234,
}
// If the user is authorized …
resolve(context)
},
})
server.listen()
```
### Authorization ### Authorization
With the `onJoinDocument` hook you can write a custom Promise to check if a client is authorized. That can be a request to an API, to a microservice, a database query, or whatever is needed, as long as its executing `resolve()` at some point. With the `onJoinDocument` hook you can check if a user is authorized to edit the current document. This works in the same way the [Authentication](#authentication) works.
```js ```js
import { Server } from '@hocuspocus/server' import { Server } from '@hocuspocus/server'
const server = Server.configure({ const server = Server.configure({
onJoinDocument(data, resolve, reject) { onJoinDocument(data, resolve, reject) {
const { documentName, clientID, requestHeaders, clientsCount, document } = data const {
clientsCount,
context,
document,
documentName,
requestHeaders,
} = data
// Your code here, for example a request to an API // Your code here, for example a request to an API
// Access the contextual data from the onConnect hook, in this example this will print { user_id: 1234 }
console.log(context)
// If the user is authorized … // If the user is authorized …
resolve() resolve()
@@ -258,8 +296,14 @@ const server = Server.configure({
// executed when the document is changed // executed when the document is changed
onChange(data) { onChange(data) {
const { documentName, clientID, requestHeaders, clientsCount, document } = data const {
clientsCount,
document,
documentName,
requestHeaders,
} = data
// Your code here, for example a request to an API
}, },
}) })

View File

@@ -36,7 +36,7 @@ export default function isMarkActive(
let markRanges: MarkRange[] = [] let markRanges: MarkRange[] = []
state.doc.nodesBetween(from, to, (node, pos) => { state.doc.nodesBetween(from, to, (node, pos) => {
if (node.isInline) { if (node.isText) {
const relativeFrom = Math.max(from, pos) const relativeFrom = Math.max(from, pos)
const relativeTo = Math.min(to, pos + node.nodeSize) const relativeTo = Math.min(to, pos + node.nodeSize)
const range = relativeTo - relativeFrom const range = relativeTo - relativeFrom
@@ -51,6 +51,10 @@ export default function isMarkActive(
} }
}) })
if (selectionRange === 0) {
return false
}
const range = markRanges const range = markRanges
.filter(markRange => { .filter(markRange => {
if (!type) { if (!type) {