Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions foundations/core/packages/text/src/markup/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
isEmptyMarkup,
isEmptyNode,
jsonToMarkup,
type MarkupMark,
MarkupMarkType,
MarkupNode,
MarkupNodeType,
Expand Down Expand Up @@ -300,6 +301,32 @@ describe('jsonToPmNode', () => {
expect(node.content.child(0).type.name).toEqual('text')
expect(node.content.child(0).text).toEqual('Hello, world!')
})

it('ServerKit schema includes node-uuid mark and parses text carrying it (QMS anchors)', () => {
const schema = getSchema(extensions)
expect(schema.marks['node-uuid']).toBeDefined()
const json: MarkupNode = {
type: MarkupNodeType.doc,
content: [
{
type: MarkupNodeType.paragraph,
attrs: { textAlign: null as any },
content: [
{
type: MarkupNodeType.text,
text: 'hello',
marks: [{ type: 'node-uuid' } as unknown as MarkupMark]
}
]
}
]
}
const node = jsonToPmNode(json, schema)
expect(node.type.name).toEqual('doc')
const para = node.content.child(0)
const text = para.content.child(0)
expect(text.marks.some((m) => m.type.name === 'node-uuid')).toBeTruthy()
})
})

describe('htmlToMarkup', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
//
-->
<script lang="ts">
import { Analytics } from '@hcengineering/analytics'
import { Class, Doc, Ref } from '@hcengineering/core'
import { jsonToPmNode, MarkupNode } from '@hcengineering/text'
import presentation from '@hcengineering/presentation'
import { Label } from '@hcengineering/ui'
import { Editor, Extension, mergeAttributes } from '@tiptap/core'
import { Plugin, PluginKey } from '@tiptap/pm/state'
import { DecorationSet } from '@tiptap/pm/view'
Expand All @@ -31,21 +34,29 @@
export let objectClass: Ref<Class<Doc>> | undefined = undefined

let element: HTMLElement
let editor: Editor
let editor: Editor | undefined

let _decoration = DecorationSet.empty
let oldContent: MarkupNode | undefined
let decorateFailed = false
let editorMountFailed = false

function updateEditor (editor: Editor, comparedVersion?: MarkupNode): void {
if (comparedVersion === undefined) {
return
}

const node = jsonToPmNode(comparedVersion, editor.schema)
const r = calculateDecorations(editor, oldContent, node)
if (r !== undefined) {
oldContent = r.oldContent
_decoration = r.decorations
try {
const node = jsonToPmNode(comparedVersion, editor.schema)
const r = calculateDecorations(editor, oldContent, node)
if (r !== undefined) {
oldContent = r.oldContent
_decoration = r.decorations
}
decorateFailed = false
} catch (err: unknown) {
decorateFailed = true
Analytics.handleError(err instanceof Error ? err : new Error(String(err)))
}
}

Expand Down Expand Up @@ -77,33 +88,66 @@
}

onMount(async () => {
const kit = await getEditorKit({
objectClass,
commentNode: true
})
try {
const kit = await getEditorKit({
objectClass,
commentNode: true,
qms: {
qmsInlineComment: {
isHighlightModeOn: () => false,
getNodeHighlight: () => null
}
}
})

editor = new Editor({
editorProps: { attributes: mergeAttributes(defaultEditorAttributes, { class: 'flex-grow' }) },
element,
content,
editable: false,
extensions: [kit, DecorationExtension],
onTransaction: () => {
// force re-render so `editor.isActive` works as expected
editor = editor
}
})
editor = new Editor({
editorProps: { attributes: mergeAttributes(defaultEditorAttributes, { class: 'flex-grow' }) },
element,
content,
editable: false,
extensions: [kit, DecorationExtension],
onContentError: ({ error, disableCollaboration }) => {
disableCollaboration()
Analytics.handleError(error)
editorMountFailed = true
},
onTransaction: () => {
// force re-render so `editor.isActive` works as expected
editor = editor
}
})
} catch (err: unknown) {
editorMountFailed = true
Analytics.handleError(err instanceof Error ? err : new Error(String(err)))
}
})

onDestroy(() => {
if (editor !== undefined) {
editor.destroy()
}
editor?.destroy()
editor = undefined
})
</script>

<div class="ref-container">
<div class="textInput">
<div class="textInput" hidden={editorMountFailed}>
<div class="select-text" style="width: 100%;" bind:this={element} />
</div>
{#if editorMountFailed}
<div class="error-fallback">
<Label label={presentation.string.FailedToPreview} />
</div>
{/if}
{#if decorateFailed && !editorMountFailed}
<div class="error-fallback">
<Label label={presentation.string.FailedToPreview} />
</div>
{/if}
</div>

<style lang="scss">
.error-fallback {
padding: 0.5rem 0;
color: var(--theme-caption-color);
font-size: 0.875rem;
}
</style>
Loading