mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-28 14:03:55 +03:00
EZQMS-398: Update CollaborationDiffViewer (#4075)
* EZQMS-398: Update CollaborationDiffViewer Signed-off-by: Anna No <anna.no@xored.com> * EZQMS-398: Update CollaborationDiffViewer Signed-off-by: Anna No <anna.no@xored.com> * EZQMS-398: Update CollaborationDiffViewer Signed-off-by: Anna No <anna.no@xored.com> * EZQMS-398: Update CollaborationDiffViewer Signed-off-by: Anna No <anna.no@xored.com> --------- Signed-off-by: Anna No <anna.no@xored.com>
This commit is contained in:
parent
7e1ad06c4d
commit
99a56ba60b
@ -16,9 +16,8 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onDestroy, setContext } from 'svelte'
|
||||
import * as Y from 'yjs'
|
||||
|
||||
import { TiptapCollabProvider } from '../provider'
|
||||
import { TiptapCollabProvider, createTiptapCollaborationData } from '../provider'
|
||||
import { CollaborationIds } from '../types'
|
||||
|
||||
export let documentId: string
|
||||
@ -36,18 +35,16 @@
|
||||
if (provider !== undefined) {
|
||||
provider.disconnect()
|
||||
}
|
||||
const ydoc: Y.Doc = new Y.Doc()
|
||||
provider = new TiptapCollabProvider({
|
||||
url: collaboratorURL,
|
||||
name: documentId,
|
||||
document: ydoc,
|
||||
token,
|
||||
parameters: {
|
||||
initialContentId: initialContentId ?? ''
|
||||
}
|
||||
const data = createTiptapCollaborationData({
|
||||
collaboratorURL,
|
||||
documentId,
|
||||
initialContentId,
|
||||
token
|
||||
})
|
||||
setContext(CollaborationIds.Doc, ydoc)
|
||||
provider = data.provider
|
||||
setContext(CollaborationIds.Doc, data.ydoc)
|
||||
setContext(CollaborationIds.Provider, provider)
|
||||
|
||||
provider.on('status', (event: any) => {
|
||||
console.log('Collaboration:', documentId, event.status) // logs "connected" or "disconnected"
|
||||
})
|
||||
|
@ -15,25 +15,24 @@
|
||||
//
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
import { Doc as Ydoc } from 'yjs'
|
||||
|
||||
import { Editor, Extension, mergeAttributes } from '@tiptap/core'
|
||||
import Collaboration from '@tiptap/extension-collaboration'
|
||||
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
||||
import { DecorationSet } from '@tiptap/pm/view'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
import { Markup } from '@hcengineering/core'
|
||||
import { IconObjects, IconSize } from '@hcengineering/ui'
|
||||
|
||||
import textEditorPlugin from '../plugin'
|
||||
|
||||
import { calculateDecorations } from './diff/decorations'
|
||||
import { calculateDecorations, createYdocDocument } from './diff/decorations'
|
||||
import { defaultEditorAttributes } from './editor/editorProps'
|
||||
import { defaultExtensions } from './extensions'
|
||||
import StyleButton from './StyleButton.svelte'
|
||||
|
||||
export let content: Markup
|
||||
export let buttonSize: IconSize = 'small'
|
||||
export let comparedVersion: Markup | undefined = undefined
|
||||
export let noButton: boolean = false
|
||||
export let readonly = false
|
||||
export let ydoc: Ydoc
|
||||
export let field: string | undefined = undefined
|
||||
export let comparedYdoc: Ydoc | undefined = undefined
|
||||
export let comparedField: string | undefined = undefined
|
||||
|
||||
// export let mode: 'unified' = 'unified'
|
||||
|
||||
let element: HTMLElement
|
||||
let editor: Editor
|
||||
@ -41,8 +40,8 @@
|
||||
let _decoration = DecorationSet.empty
|
||||
let oldContent = ''
|
||||
|
||||
function updateEditor (editor?: Editor, comparedVersion?: Markup | ArrayBuffer): void {
|
||||
const r = calculateDecorations(editor, oldContent, undefined, comparedVersion)
|
||||
function updateEditor (editor: Editor, ydoc: Ydoc, field?: string): void {
|
||||
const r = calculateDecorations(editor, oldContent, createYdocDocument(editor.schema, ydoc, field))
|
||||
if (r !== undefined) {
|
||||
oldContent = r.oldContent
|
||||
_decoration = r.decorations
|
||||
@ -50,8 +49,8 @@
|
||||
}
|
||||
|
||||
const updateDecorations = () => {
|
||||
if (editor?.schema) {
|
||||
updateEditor(editor, comparedVersion)
|
||||
if (editor?.schema && comparedYdoc) {
|
||||
updateEditor(editor, comparedYdoc, comparedField)
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,12 +60,9 @@
|
||||
new Plugin({
|
||||
key: new PluginKey('diffs'),
|
||||
props: {
|
||||
decorations (state) {
|
||||
decorations () {
|
||||
updateDecorations()
|
||||
if (showDiff) {
|
||||
return _decoration
|
||||
}
|
||||
return undefined
|
||||
return _decoration
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -74,21 +70,17 @@
|
||||
}
|
||||
})
|
||||
|
||||
$: updateEditor(editor, comparedVersion)
|
||||
$: if (editor && comparedYdoc) {
|
||||
updateEditor(editor, comparedYdoc, comparedField)
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
editor = new Editor({
|
||||
editorProps: { attributes: mergeAttributes(defaultEditorAttributes, { class: 'flex-grow' }) },
|
||||
element,
|
||||
content,
|
||||
editable: true,
|
||||
extensions: [...defaultExtensions, DecorationExtension],
|
||||
onTransaction: () => {
|
||||
// force re-render so `editor.isActive` works as expected
|
||||
editor = editor
|
||||
}
|
||||
editable: false,
|
||||
extensions: [...defaultExtensions, DecorationExtension, Collaboration.configure({ document: ydoc, field })]
|
||||
})
|
||||
editor.setEditable(!readonly)
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
@ -96,27 +88,9 @@
|
||||
editor.destroy()
|
||||
}
|
||||
})
|
||||
let showDiff = true
|
||||
</script>
|
||||
|
||||
<div class="ref-container">
|
||||
{#if comparedVersion !== undefined && !noButton}
|
||||
<div class="flex">
|
||||
<div class="flex-grow" />
|
||||
<div class="formatPanel buttons-group xsmall-gap mb-4">
|
||||
<StyleButton
|
||||
icon={IconObjects}
|
||||
size={buttonSize}
|
||||
selected={showDiff}
|
||||
showTooltip={{ label: textEditorPlugin.string.EnableDiffMode }}
|
||||
on:click={() => {
|
||||
showDiff = !showDiff
|
||||
editor.chain().focus()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="textInput">
|
||||
<div class="select-text" style="width: 100%;" bind:this={element} />
|
||||
</div>
|
||||
|
@ -15,15 +15,14 @@
|
||||
//
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Markup, getCurrentAccount } from '@hcengineering/core'
|
||||
import { getCurrentAccount } from '@hcengineering/core'
|
||||
import { IntlString, translate } from '@hcengineering/platform'
|
||||
import { IconObjects, IconSize, Loading, getPlatformColorForText, registerFocus, themeStore } from '@hcengineering/ui'
|
||||
import { AnyExtension, Editor, Extension, FocusPosition, getMarkRange, mergeAttributes } from '@tiptap/core'
|
||||
import { IconSize, Loading, getPlatformColorForText, registerFocus, themeStore } from '@hcengineering/ui'
|
||||
import { AnyExtension, Editor, FocusPosition, getMarkRange, mergeAttributes } from '@tiptap/core'
|
||||
import Collaboration, { isChangeOrigin } from '@tiptap/extension-collaboration'
|
||||
import CollaborationCursor from '@tiptap/extension-collaboration-cursor'
|
||||
import Placeholder from '@tiptap/extension-placeholder'
|
||||
import { Plugin, PluginKey, TextSelection } from '@tiptap/pm/state'
|
||||
import { DecorationSet } from '@tiptap/pm/view'
|
||||
import { TextSelection } from '@tiptap/pm/state'
|
||||
import { createEventDispatcher, getContext, onDestroy, onMount } from 'svelte'
|
||||
import * as Y from 'yjs'
|
||||
|
||||
@ -35,9 +34,7 @@
|
||||
import { copyDocumentContent, copyDocumentField } from '../utils'
|
||||
|
||||
import ImageStyleToolbar from './ImageStyleToolbar.svelte'
|
||||
import StyleButton from './StyleButton.svelte'
|
||||
import TextEditorStyleToolbar from './TextEditorStyleToolbar.svelte'
|
||||
import { calculateDecorations } from './diff/decorations'
|
||||
import { noSelectionRender } from './editor/collaboration'
|
||||
import { defaultEditorAttributes } from './editor/editorProps'
|
||||
import { FileAttachFunction, ImageExtension } from './extension/imageExt'
|
||||
@ -50,14 +47,13 @@
|
||||
export let readonly = false
|
||||
export let visible = true
|
||||
|
||||
export let token: string
|
||||
export let collaboratorURL: string
|
||||
export let token: string = ''
|
||||
export let collaboratorURL: string = ''
|
||||
|
||||
export let buttonSize: IconSize = 'small'
|
||||
export let focusable: boolean = false
|
||||
export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder
|
||||
export let initialContentId: string | undefined = undefined
|
||||
export let comparedVersion: Markup | ArrayBuffer | undefined = undefined
|
||||
|
||||
export let field: string | undefined = undefined
|
||||
|
||||
@ -188,22 +184,6 @@
|
||||
copyDocumentField(documentId, srcFieldId, dstFieldId, { provider }, initialContentId)
|
||||
}
|
||||
|
||||
export function unregisterPlugin (nameOrPluginKey: string | PluginKey) {
|
||||
if (!editor) {
|
||||
return
|
||||
}
|
||||
|
||||
editor.unregisterPlugin(nameOrPluginKey)
|
||||
}
|
||||
|
||||
export function registerPlugin (plugin: Plugin) {
|
||||
if (!editor) {
|
||||
return
|
||||
}
|
||||
|
||||
editor.registerPlugin(plugin)
|
||||
}
|
||||
|
||||
let needFocus = false
|
||||
let focused = false
|
||||
let posFocus: FocusPosition | undefined = undefined
|
||||
@ -225,44 +205,6 @@
|
||||
editor.setEditable(!readonly)
|
||||
}
|
||||
|
||||
let _decoration = DecorationSet.empty
|
||||
let oldContent = ''
|
||||
|
||||
function updateEditor (editor?: Editor, field?: string, comparedVersion?: Markup | ArrayBuffer): void {
|
||||
const r = calculateDecorations(editor, oldContent, field, comparedVersion)
|
||||
if (r !== undefined) {
|
||||
oldContent = r.oldContent
|
||||
_decoration = r.decorations
|
||||
}
|
||||
}
|
||||
|
||||
const updateDecorations = () => {
|
||||
if (editor?.schema) {
|
||||
updateEditor(editor, field, comparedVersion)
|
||||
}
|
||||
}
|
||||
|
||||
const DecorationExtension = Extension.create({
|
||||
addProseMirrorPlugins () {
|
||||
return [
|
||||
new Plugin({
|
||||
key: new PluginKey('diffs'),
|
||||
props: {
|
||||
decorations (state) {
|
||||
updateDecorations()
|
||||
if (showDiff) {
|
||||
return _decoration
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
$: updateEditor(editor, field, comparedVersion)
|
||||
$: if (editor) dispatch('editor', editor)
|
||||
$: isStyleToolbarSupported = (!readonly || textNodeActions.length > 0) && canShowPopups
|
||||
|
||||
$: tippyOptions = {
|
||||
@ -335,7 +277,6 @@
|
||||
},
|
||||
selectionRender: noSelectionRender
|
||||
}),
|
||||
DecorationExtension,
|
||||
Completion.configure({
|
||||
...completionConfig,
|
||||
showDoc (event: MouseEvent, _id: string, _class: string) {
|
||||
@ -385,8 +326,6 @@
|
||||
}
|
||||
})
|
||||
|
||||
let showDiff = true
|
||||
|
||||
export let focusIndex = -1
|
||||
const { idx, focusManager } = registerFocus(focusIndex, {
|
||||
focus: () => {
|
||||
@ -421,27 +360,11 @@
|
||||
{/if}
|
||||
|
||||
{#if visible}
|
||||
{#if comparedVersion !== undefined || $$slots.tools}
|
||||
{#if $$slots.tools}
|
||||
<div class="ref-container" style:overflow>
|
||||
{#if comparedVersion !== undefined}
|
||||
<div class="flex-row-center buttons-group xsmall-gap">
|
||||
<StyleButton
|
||||
icon={IconObjects}
|
||||
size={buttonSize}
|
||||
selected={showDiff}
|
||||
showTooltip={{ label: textEditorPlugin.string.EnableDiffMode }}
|
||||
on:click={() => {
|
||||
showDiff = !showDiff
|
||||
editor.chain().focus()
|
||||
}}
|
||||
/>
|
||||
<slot name="tools" />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-editor-toolbar buttons-group xsmall-gap">
|
||||
<slot name="tools" />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="text-editor-toolbar buttons-group xsmall-gap">
|
||||
<slot name="tools" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
100
packages/text-editor/src/components/MarkupDiffViewer.svelte
Normal file
100
packages/text-editor/src/components/MarkupDiffViewer.svelte
Normal file
@ -0,0 +1,100 @@
|
||||
<!--
|
||||
//
|
||||
// Copyright © 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Editor, Extension, mergeAttributes } from '@tiptap/core'
|
||||
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
||||
import { DecorationSet } from '@tiptap/pm/view'
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
import { Markup } from '@hcengineering/core'
|
||||
|
||||
import { calculateDecorations, createMarkupDocument } from './diff/decorations'
|
||||
import { defaultEditorAttributes } from './editor/editorProps'
|
||||
import { defaultExtensions } from './extensions'
|
||||
|
||||
export let content: Markup
|
||||
export let comparedVersion: Markup | undefined = undefined
|
||||
|
||||
let element: HTMLElement
|
||||
let editor: Editor
|
||||
|
||||
let _decoration = DecorationSet.empty
|
||||
let oldContent = ''
|
||||
|
||||
function updateEditor (editor: Editor, comparedVersion?: Markup): void {
|
||||
if (!comparedVersion) {
|
||||
return
|
||||
}
|
||||
|
||||
const r = calculateDecorations(editor, oldContent, createMarkupDocument(editor.schema, comparedVersion))
|
||||
if (r !== undefined) {
|
||||
oldContent = r.oldContent
|
||||
_decoration = r.decorations
|
||||
}
|
||||
}
|
||||
|
||||
const updateDecorations = () => {
|
||||
if (editor?.schema) {
|
||||
updateEditor(editor, comparedVersion)
|
||||
}
|
||||
}
|
||||
|
||||
const DecorationExtension = Extension.create({
|
||||
addProseMirrorPlugins () {
|
||||
return [
|
||||
new Plugin({
|
||||
key: new PluginKey('diffs'),
|
||||
props: {
|
||||
decorations () {
|
||||
updateDecorations()
|
||||
return _decoration
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
$: if (editor && comparedVersion) {
|
||||
updateEditor(editor, comparedVersion)
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
editor = new Editor({
|
||||
editorProps: { attributes: mergeAttributes(defaultEditorAttributes, { class: 'flex-grow' }) },
|
||||
element,
|
||||
content,
|
||||
editable: false,
|
||||
extensions: [...defaultExtensions, DecorationExtension],
|
||||
onTransaction: () => {
|
||||
// force re-render so `editor.isActive` works as expected
|
||||
editor = editor
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
if (editor) {
|
||||
editor.destroy()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="ref-container">
|
||||
<div class="textInput">
|
||||
<div class="select-text" style="width: 100%;" bind:this={element} />
|
||||
</div>
|
||||
</div>
|
@ -19,13 +19,26 @@ import { ChangeSet } from '@tiptap/pm/changeset'
|
||||
import { DOMParser, type Node, type Schema } from '@tiptap/pm/model'
|
||||
import { Decoration, DecorationSet } from '@tiptap/pm/view'
|
||||
import { yDocToProsemirrorJSON } from 'y-prosemirror'
|
||||
import { Doc, applyUpdate } from 'yjs'
|
||||
import { Doc as Ydoc, applyUpdate } from 'yjs'
|
||||
import { recreateTransform } from './recreate'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function createDocument (schema: Schema, content: Markup | ArrayBuffer, field?: string): Node {
|
||||
export function createYdocDocument (schema: Schema, ydoc: Ydoc, field?: string): Node {
|
||||
try {
|
||||
const body = yDocToProsemirrorJSON(ydoc, field)
|
||||
return schema.nodeFromJSON(body)
|
||||
} catch (err: any) {
|
||||
console.error(err)
|
||||
return schema.node(schema.topNodeType)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function createMarkupDocument (schema: Schema, content: Markup | ArrayBuffer, field?: string): Node {
|
||||
if (typeof content === 'string') {
|
||||
const wrappedValue = `<body>${content}</body>`
|
||||
|
||||
@ -34,7 +47,7 @@ export function createDocument (schema: Schema, content: Markup | ArrayBuffer, f
|
||||
return DOMParser.fromSchema(schema).parse(body)
|
||||
} else {
|
||||
try {
|
||||
const ydoc = new Doc()
|
||||
const ydoc = new Ydoc()
|
||||
const uint8arr = new Uint8Array(content)
|
||||
applyUpdate(ydoc, uint8arr)
|
||||
|
||||
@ -53,8 +66,7 @@ export function createDocument (schema: Schema, content: Markup | ArrayBuffer, f
|
||||
export function calculateDecorations (
|
||||
editor?: Editor,
|
||||
oldContent?: string,
|
||||
field?: string,
|
||||
comparedVersion?: Markup | ArrayBuffer
|
||||
comparedDoc?: Node
|
||||
):
|
||||
| {
|
||||
decorations: DecorationSet
|
||||
@ -65,11 +77,9 @@ export function calculateDecorations (
|
||||
if (editor?.schema === undefined) {
|
||||
return
|
||||
}
|
||||
if (comparedVersion === undefined) {
|
||||
if (comparedDoc === undefined) {
|
||||
return
|
||||
}
|
||||
const schema = editor.schema
|
||||
const docOld = createDocument(schema, comparedVersion, field)
|
||||
const docNew = editor.state.doc
|
||||
|
||||
const c = editor.getHTML()
|
||||
@ -77,8 +87,8 @@ export function calculateDecorations (
|
||||
return
|
||||
}
|
||||
|
||||
const tr = recreateTransform(docOld, docNew)
|
||||
const changeSet = ChangeSet.create(docOld).addSteps(tr.doc, tr.mapping.maps, undefined)
|
||||
const tr = recreateTransform(comparedDoc, docNew)
|
||||
const changeSet = ChangeSet.create(comparedDoc).addSteps(tr.doc, tr.mapping.maps, undefined)
|
||||
const changes = changeSet.changes
|
||||
|
||||
const decorations: Decoration[] = []
|
||||
@ -91,18 +101,18 @@ export function calculateDecorations (
|
||||
|
||||
function deleted (prob: any): any {
|
||||
const icon = document.createElement('span')
|
||||
icon.className = 'deletion'
|
||||
icon.className = 'text-editor-highlighted-node-delete'
|
||||
icon.innerText = prob
|
||||
return icon
|
||||
}
|
||||
changes.forEach((change) => {
|
||||
if (change.inserted.length > 0) {
|
||||
decorations.push(Decoration.inline(change.fromB, change.toB, { class: 'diff insertion' }, {}))
|
||||
decorations.push(Decoration.inline(change.fromB, change.toB, { class: 'text-editor-highlighted-node-add' }, {}))
|
||||
decorations.push(Decoration.widget(change.fromB, lintIcon('add')))
|
||||
}
|
||||
|
||||
if (change.deleted.length > 0) {
|
||||
const cont = docOld.textBetween(change.fromA, change.toA)
|
||||
const cont = comparedDoc.textBetween(change.fromA, change.toA)
|
||||
decorations.push(Decoration.widget(change.fromB, deleted(cont)))
|
||||
decorations.push(Decoration.widget(change.fromB, lintIcon('delete')))
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ export { default as Collaboration } from './components/Collaboration.svelte'
|
||||
export { default as CollaborationDiffViewer } from './components/CollaborationDiffViewer.svelte'
|
||||
export { default as CollaboratorEditor } from './components/CollaboratorEditor.svelte'
|
||||
export { default as FullDescriptionBox } from './components/FullDescriptionBox.svelte'
|
||||
export { default as MarkupDiffViewer } from './components/MarkupDiffViewer.svelte'
|
||||
export { default as ReferenceInput } from './components/ReferenceInput.svelte'
|
||||
export { default as StyleButton } from './components/StyleButton.svelte'
|
||||
export { default as StyledTextArea } from './components/StyledTextArea.svelte'
|
||||
@ -65,4 +66,7 @@ export {
|
||||
export { ImageExtension, type ImageOptions } from './components/extension/imageExt'
|
||||
export { TodoItemExtension, TodoListExtension } from './components/extension/todo'
|
||||
|
||||
export { TiptapCollabProvider, type TiptapCollabProviderConfiguration, createTiptapCollaborationData } from './provider'
|
||||
export { CollaborationIds } from './types'
|
||||
|
||||
export { textEditorId }
|
||||
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Doc as Ydoc } from 'yjs'
|
||||
import { HocuspocusProvider, type HocuspocusProviderConfiguration } from '@hocuspocus/provider'
|
||||
|
||||
export type TiptapCollabProviderConfiguration = HocuspocusProviderConfiguration &
|
||||
@ -50,3 +50,24 @@ export class TiptapCollabProvider extends HocuspocusProvider {
|
||||
super.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
export const createTiptapCollaborationData = (params: {
|
||||
collaboratorURL: string
|
||||
documentId: string
|
||||
initialContentId: string | undefined
|
||||
token: string
|
||||
}): { provider: TiptapCollabProvider, ydoc: Ydoc } => {
|
||||
const ydoc: Ydoc = new Ydoc()
|
||||
return {
|
||||
ydoc,
|
||||
provider: new TiptapCollabProvider({
|
||||
url: params.collaboratorURL,
|
||||
name: params.documentId,
|
||||
document: ydoc,
|
||||
token: params.token,
|
||||
parameters: {
|
||||
initialContentId: params.initialContentId ?? ''
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { CollaborationDiffViewer } from '@hcengineering/text-editor'
|
||||
import { MarkupDiffViewer } from '@hcengineering/text-editor'
|
||||
import { ShowMore } from '@hcengineering/ui'
|
||||
|
||||
export let value: string | undefined
|
||||
@ -43,6 +43,6 @@
|
||||
|
||||
<ShowMore>
|
||||
{#key [value, prevValue]}
|
||||
<CollaborationDiffViewer content={value ?? ''} comparedVersion={prevValue ?? ''} noButton readonly />
|
||||
<MarkupDiffViewer content={value ?? ''} comparedVersion={prevValue ?? ''} />
|
||||
{/key}
|
||||
</ShowMore>
|
||||
|
Loading…
Reference in New Issue
Block a user