annotations: refactor annotation representation

This commit is contained in:
Hans Pagel 2021-02-12 13:27:15 +01:00
parent 10fdb79a9d
commit b7f25e131c
4 changed files with 85 additions and 41 deletions

View File

@ -1,10 +1,37 @@
export class AnnotationItem {
public id!: string
private decoration!: any
public content!: string
constructor(decoration: any) {
this.decoration = decoration
}
constructor(id: string, content: string) {
this.id = id
this.content = content
get id() {
return this.decoration.type.spec.id
}
get from() {
return this.decoration.from
}
get to() {
return this.decoration.to
}
get content() {
return this.decoration.type.spec.content
}
get HTMLAttributes() {
return this.decoration.type.attrs
}
toString() {
return JSON.stringify({
id: this.id,
content: this.content,
from: this.from,
to: this.to,
HTMLAttributes: this.HTMLAttributes,
})
}
}

View File

@ -4,6 +4,7 @@ import { Decoration, DecorationSet } from 'prosemirror-view'
import { ySyncPluginKey, relativePositionToAbsolutePosition, absolutePositionToRelativePosition } from 'y-prosemirror'
import { AddAnnotationAction, DeleteAnnotationAction } from './annotation'
import { AnnotationPluginKey } from './AnnotationPlugin'
import { AnnotationItem } from './AnnotationItem'
export interface AnnotationStateOptions {
HTMLAttributes: {
@ -21,11 +22,16 @@ export class AnnotationState {
this.options = options
}
randomId() {
// TODO: That seems … to simple.
return Math.floor(Math.random() * 0xffffffff).toString()
}
findAnnotation(id: string) {
const current = this.decorations.find()
for (let i = 0; i < current.length; i += 1) {
if (current[i].spec.data.id === id) {
if (current[i].spec.id === id) {
return current[i]
}
}
@ -35,14 +41,14 @@ export class AnnotationState {
const ystate = ySyncPluginKey.getState(state)
const { type, binding } = ystate
const { map } = this.options
const { from, to, data } = action
const { from, to, content } = action
const absoluteFrom = absolutePositionToRelativePosition(from, type, binding.mapping)
const absoluteTo = absolutePositionToRelativePosition(to, type, binding.mapping)
map.set(data.id, {
map.set(this.randomId(), {
from: absoluteFrom,
to: absoluteTo,
data,
content,
})
}
@ -53,7 +59,9 @@ export class AnnotationState {
}
annotationsAt(position: number) {
return this.decorations.find(position, position)
return this.decorations.find(position, position).map(decoration => {
return new AnnotationItem(decoration)
})
}
updateDecorations(state: EditorState) {
@ -65,16 +73,16 @@ export class AnnotationState {
Array
.from(map.keys())
.forEach(id => {
const dec = map.get(id)
const from = relativePositionToAbsolutePosition(doc, type, dec.from, binding.mapping)
const to = relativePositionToAbsolutePosition(doc, type, dec.to, binding.mapping)
const decoration = map.get(id)
const from = relativePositionToAbsolutePosition(doc, type, decoration.from, binding.mapping)
const to = relativePositionToAbsolutePosition(doc, type, decoration.to, binding.mapping)
if (!from || !to) {
return
}
return decorations.push(
Decoration.inline(from, to, HTMLAttributes, { data: dec.data }),
Decoration.inline(from, to, HTMLAttributes, { id, content: decoration.content }),
)
})

View File

@ -1,23 +1,23 @@
import * as Y from 'yjs'
import { Extension, Command } from '@tiptap/core'
import { AnnotationItem } from './AnnotationItem'
import { AnnotationPlugin, AnnotationPluginKey } from './AnnotationPlugin'
function randomId() {
// TODO: That seems … to simple.
return Math.floor(Math.random() * 0xffffffff).toString()
}
export interface AddAnnotationAction {
type: 'addAnnotation',
content: any,
from: number,
to: number,
data: AnnotationItem,
}
export interface UpdateAnnotationAction {
type: 'updateAnnotation',
id: string,
content: any,
}
export interface DeleteAnnotationAction {
id: string,
type: 'deleteAnnotation',
id: string,
}
export interface AnnotationOptions {
@ -89,10 +89,17 @@ export const Annotation = Extension.create({
type: 'addAnnotation',
from: selection.from,
to: selection.to,
data: new AnnotationItem(
randomId(),
content,
),
content,
})
}
return true
},
updateAnnotation: (id: string, content: any): Command => ({ dispatch, state }) => {
if (dispatch) {
state.tr.setMeta(AnnotationPluginKey, <UpdateAnnotationAction>{
type: 'updateAnnotation',
content,
})
}

View File

@ -8,10 +8,14 @@
comment
</button>
<editor-content :editor="editor" />
<div v-for="comment in comments" :key="comment.type.spec.data.id">
{{ comment.type.spec.data }}
<div v-for="comment in comments" :key="comment.id">
{{ comment }}
<button @click="deleteComment(comment.type.spec.data.id)">
<button @click="updateComment(comment.id)">
update
</button>
<button @click="deleteComment(comment.id)">
remove
</button>
</div>
@ -23,11 +27,6 @@
comment
</button>
<editor-content :editor="anotherEditor" />
<h2>
Y.js document
</h2>
{{ json }}
</div>
</div>
</template>
@ -108,19 +107,22 @@ export default {
this.editor.commands.addAnnotation(content)
},
addAnotherComment() {
const content = prompt('Comment', '')
updateComment(id) {
const comment = this.comments.find(item => {
return id === item.id
})
this.anotherEditor.commands.addAnnotation(content)
const content = prompt('Comment', comment.content)
this.editor.commands.updateAnnotation(id, content)
},
deleteComment(id) {
this.editor.commands.deleteAnnotation(id)
},
},
addAnotherComment() {
const content = prompt('Comment', '')
computed: {
json() {
return this.ydoc.toJSON()
this.anotherEditor.commands.addAnnotation(content)
},
},