This commit is contained in:
Philipp Kühn 2020-11-30 15:40:20 +01:00
commit dd840703d9
4 changed files with 61 additions and 52 deletions

View File

@ -18,30 +18,21 @@ export default {
data() { data() {
return { return {
documentName: 'tiptap-collaboration-extension',
ydoc: null,
provider: null,
type: null,
editor: null, editor: null,
} }
}, },
mounted() { mounted() {
this.ydoc = new Y.Doc() const ydoc = new Y.Doc()
this.provider = new WebrtcProvider(this.documentName, this.ydoc) const provider = new WebrtcProvider('tiptap-collaboration-extension', ydoc)
this.type = this.ydoc.getXmlFragment('prosemirror')
this.editor = new Editor({ this.editor = new Editor({
// TODO: This is added by every new user.
// content: `
// <p>Example Text</p>
// `,
extensions: [ extensions: [
Document, Document,
Paragraph, Paragraph,
Text, Text,
Collaboration.configure({ Collaboration.configure({
type: this.type, provider,
}), }),
], ],
}) })
@ -49,7 +40,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
this.provider.destroy()
}, },
} }
</script> </script>

View File

@ -19,35 +19,28 @@ export default {
data() { data() {
return { return {
documentName: 'tiptap-collaboration-cursor-extension',
ydoc: null,
provider: null,
type: null,
editor: null, editor: null,
} }
}, },
mounted() { mounted() {
this.ydoc = new Y.Doc() const ydoc = new Y.Doc()
this.provider = new WebrtcProvider(this.documentName, this.ydoc) const provider = new WebrtcProvider('tiptap-collaboration-cursor-extension', ydoc)
this.type = this.ydoc.getXmlFragment('prosemirror')
this.editor = new Editor({ this.editor = new Editor({
// TODO: This is added by every new user.
// content: `
// <p>Example Text</p>
// `,
extensions: [ extensions: [
Document, Document,
Paragraph, Paragraph,
Text, Text,
Collaboration.configure({ Collaboration.configure({
type: this.type, provider,
}), }),
CollaborationCursor.configure({ CollaborationCursor.configure({
provider: this.provider, provider,
name: 'Cyndi Lauper', user: {
color: '#f783ac', name: 'Cyndi Lauper',
color: '#f783ac',
},
}), }),
], ],
}) })
@ -55,7 +48,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
this.provider.destroy()
}, },
} }
</script> </script>

View File

@ -3,9 +3,9 @@
## toc ## toc
## Introduction ## Introduction
The editor fires a few different events that you can hook into. There are two ways to register event listeners: The editor fires a few different events that you can hook into. There are three ways to register event listeners:
## Option 1: Right-away ## Option 1: Configuration
You can define your event listeners on a new editor instance right-away: You can define your event listeners on a new editor instance right-away:
```js ```js
@ -29,12 +29,12 @@ const editor = new Editor({
// The editor isnt focused anymore. // The editor isnt focused anymore.
}, },
onDestroy() { onDestroy() {
// The editor is destroyed. // The editor is being destroyed.
}, },
}) })
``` ```
## Option 2: Later ## Option 2: Binding
Or you can register your event listeners on a running editor instance: Or you can register your event listeners on a running editor instance:
### Bind event listeners ### Bind event listeners
@ -64,7 +64,7 @@ editor.on('blur', ({ event }) => {
} }
editor.on('destroy', () => { editor.on('destroy', () => {
// The editor is destroyed. // The editor is being destroyed.
} }
``` ```
@ -82,3 +82,34 @@ editor.on('update', onUpdate)
// … and unbind. // … and unbind.
editor.off('update', onUpdate) editor.off('update', onUpdate)
``` ```
## Option 3: Extensions
Moving your event listeners to custom extensions (or nodes, or marks) is also possible. Heres how that would look like:
```js
import { Extension } from '@tiptap/core'
const CustomExtension = Extension.create({
onCreate() {
// The editor is ready.
},
onUpdate() {
// The content has changed.
},
onSelection() {
// The selection has changed.
},
onTransaction({ transaction }) {
// The editor state has changed.
},
onFocus({ event }) {
// The editor is focused.
},
onBlur({ event }) {
// The editor isnt focused anymore.
},
onDestroy() {
// The editor is being destroyed.
},
})
```

View File

@ -4,6 +4,12 @@
Using collaborative editing in production? Do the right thing and [sponsor our work](/sponsor)! Using collaborative editing in production? Do the right thing and [sponsor our work](/sponsor)!
::: :::
<!--
TODO:
- Pass auth token to the provider
-
-->
## toc ## toc
## Introduction ## Introduction
@ -27,7 +33,7 @@ npm install @tiptap/extension-collaboration yjs y-webrtc
yarn add @tiptap/extension-collaboration yjs y-webrtc yarn add @tiptap/extension-collaboration yjs y-webrtc
``` ```
And create a new Y document, and register it with tiptap: Now, create a new Y document, and register it with tiptap:
```js ```js
import { Editor } from '@tiptap/core' import { Editor } from '@tiptap/core'
@ -39,15 +45,13 @@ import { WebrtcProvider } from 'y-webrtc'
const ydoc = new Y.Doc() const ydoc = new Y.Doc()
// Registered with a WebRTC provider // Registered with a WebRTC provider
const provider = new WebrtcProvider('example-document', ydoc) const provider = new WebrtcProvider('example-document', ydoc)
// Point to the ProseMirror schema
const type = ydoc.getXmlFragment('prosemirror')
const editor = new Editor({ const editor = new Editor({
extensions: [ extensions: [
// … // …
// Register the document with tiptap // Register the document with tiptap
Collaboration.configure({ Collaboration.configure({
type: type, provider
}), }),
], ],
}) })
@ -86,15 +90,13 @@ import { WebsocketProvider } from 'y-websocket'
const ydoc = new Y.Doc() const ydoc = new Y.Doc()
// Registered with a WebSocket provider // Registered with a WebSocket provider
const provider = new WebsocketProvider('ws://127.0.0.1:1234', 'example-document', ydoc) const provider = new WebsocketProvider('ws://127.0.0.1:1234', 'example-document', ydoc)
// Point to the ProseMirror schema
const type = ydoc.getXmlFragment('prosemirror')
const editor = new Editor({ const editor = new Editor({
extensions: [ extensions: [
// … // …
// Register the document with tiptap // Register the document with tiptap
Collaboration.configure({ Collaboration.configure({
type: type, provider
}), }),
], ],
}) })
@ -144,13 +146,12 @@ import { WebsocketProvider } from 'y-websocket'
const ydoc = new Y.Doc() const ydoc = new Y.Doc()
const provider = new WebsocketProvider('ws://127.0.0.1:1234', 'example-document', ydoc) const provider = new WebsocketProvider('ws://127.0.0.1:1234', 'example-document', ydoc)
const type = ydoc.getXmlFragment('prosemirror')
const editor = new Editor({ const editor = new Editor({
extensions: [ extensions: [
// … // …
Collaboration.configure({ Collaboration.configure({
type: type, provider
}), }),
// Register the collaboration cursor extension // Register the collaboration cursor extension
CollaborationCursor.configure({ CollaborationCursor.configure({
@ -162,7 +163,7 @@ const editor = new Editor({
}) })
``` ```
As you can see, you can pass a name and color for every user. Look at the [collaborative editing example](/exmplaes/collaborative-editing), to see a more advanced example. As you can see, you can pass a name and color for every user. Look at the [collaborative editing example](/examples/collaborative-editing), to see a more advanced example.
### Offline support ### Offline support
Adding offline support to your collaborative editor is basically a one-liner, thanks to the fantastic [Y IndexedDB adapter](https://github.com/yjs/y-indexeddb). Install it: Adding offline support to your collaborative editor is basically a one-liner, thanks to the fantastic [Y IndexedDB adapter](https://github.com/yjs/y-indexeddb). Install it:
@ -184,7 +185,6 @@ import * as Y from 'yjs'
import { IndexeddbPersistence } from 'y-indexeddb' import { IndexeddbPersistence } from 'y-indexeddb'
const ydoc = new Y.Doc() const ydoc = new Y.Doc()
const type = ydoc.getXmlFragment('prosemirror')
// Store the Y document in the browser // Store the Y document in the browser
const indexdb = new IndexeddbPersistence('example-document', ydoc) const indexdb = new IndexeddbPersistence('example-document', ydoc)
@ -192,7 +192,7 @@ const editor = new Editor({
extensions: [ extensions: [
// … // …
Collaboration.configure({ Collaboration.configure({
type: type, provider
}), }),
], ],
}) })
@ -213,9 +213,7 @@ import { Server } from '@hocuspocus/server'
const server = Server.configure({ const server = Server.configure({
onJoinDocument(data, resolve, reject) { onJoinDocument(data, resolve, reject) {
const { const { documentName, clientID, requestHeaders, clientsCount, document } = data
documentName, clientID, requestHeaders, clientsCount, document,
} = data
// Your code here, for example a request to an API // Your code here, for example a request to an API
// If the user is authorized … // If the user is authorized …
@ -260,9 +258,7 @@ const server = Server.configure({
// executed when the document is changed // executed when the document is changed
onChange(data) { onChange(data) {
const { const { documentName, clientID, requestHeaders, clientsCount, document } = data
documentName, clientID, requestHeaders, clientsCount, document,
} = data
}, },
}) })