Skip to content
Snippets Groups Projects
Commit 307cad14 authored by chris's avatar chris
Browse files

pass context to active plugin and cleanup

parent a0af3d2e
No related branches found
No related tags found
2 merge requests!548Merge yjs with standard comments,!545Overlapping comments
......@@ -7,14 +7,16 @@ import CopyPasteCommentPlugin from './plugins/CopyPasteCommentPlugin';
import { AnnotationPlugin } from './plugins/AnnotationPlugin';
import './comments.css';
const PLUGIN_KEY = 'commentPlugin';
export default class CommentsService extends Service {
allCommentsFromStates = [];
boot() {
const commentsConfig = this.app.config.get('config.CommentsService');
this.app.PmPlugins.add(PLUGIN_KEY, CommentPlugin(PLUGIN_KEY));
this.app.PmPlugins.add(
'commentPlugin',
CommentPlugin('commentPlugin', this.app.context),
);
this.app.PmPlugins.add(
'copyPasteCommentPlugin',
CopyPasteCommentPlugin('copyPasteCommentPlugin', this.app.context),
......
......@@ -190,7 +190,7 @@ export default ({ comment, top, commentId, recalculateTops, users }) => {
onTextAreaBlur={onTextAreaBlur}
recalculateTops={recalculateTops}
showTitle={showTitle}
title={comment.attrs.title}
// title={comment.attrs.title}
users={users}
/>
</ConnectedCommentStyled>
......
/* eslint-disable no-param-reassign */
/* eslint react/prop-types: 0 */
import { Mark } from 'prosemirror-model';
import React, { useContext, useState, useMemo, useCallback } from 'react';
import useDeepCompareEffect from 'use-deep-compare-effect';
import { each, uniqBy, sortBy, groupBy } from 'lodash';
......@@ -248,6 +247,7 @@ const updateMarks = (views, comments) => {
groupedMarkNodes.main = groupedMarkNodes.main.concat(newComments.main);
if (newComments?.notes?.length > 0)
groupedMarkNodes.notes = groupedMarkNodes.notes.concat(newComments.notes);
console.log(sortBy(groupedMarkNodes.main, ['from']));
return {
main: sortBy(groupedMarkNodes.main, ['from']),
notes: groupedMarkNodes.notes,
......
......@@ -2,7 +2,6 @@
import { v4 as uuidv4 } from 'uuid';
import { Decoration, DecorationSet } from 'prosemirror-view';
import AnnotationDecoration from './AnnotationDecoration';
// import { createAnnotationRendering } from './rendering/engine';
import { AnnotationPluginKey } from './AnnotationPlugin';
export default class AnnotationState {
......@@ -90,37 +89,12 @@ export default class AnnotationState {
to,
);
}
let baseClasses; // = "border-black p-0.5 font-semibold inline relative ";
switch (annotation.rendering) {
case 'fragment-left':
baseClasses = styles.leftFragment;
break;
case 'fragment-middle':
baseClasses = styles.middleFragment;
break;
case 'fragment-right':
baseClasses = styles.rightFragment;
break;
case 'normal':
baseClasses = styles.normal;
break;
default:
break;
}
// set custom background color
let customStyle;
if (annotation.backgroundColor) {
customStyle = {
style: `background-color: ${annotation.backgroundColor};`,
class: baseClasses,
};
}
decorations.push(
Decoration.inline(
from,
to,
customStyle || {
{
class: 'comment',
'data-id': annotation.id,
},
......
......@@ -65,7 +65,7 @@ const getComment = state => {
return commentOnSelection;
};
export default props => {
export default (key, context) => {
return new Plugin({
key: commentPlugin,
state: {
......@@ -73,6 +73,7 @@ export default props => {
return { comment: getComment(state) };
},
apply(tr, prev, _, newState) {
console.log(context);
const comment = getComment(newState);
let createDecoration;
if (comment) {
......
export const isConflicting = (fromA, toA, fromB, toB) => {
// case 1: (non-conflicting) A is before B
if (fromA < toB && toA < fromB) return false;
// case 2: (non-conflicting) B is before A
if (fromB < toA && toB < fromA) return false;
// case 3: (conflicting) some kind of overlap
return true;
};
export const createAnnotationRendering = annotations => {
const renderedAnnotations = [];
const openAnnotationStack = [];
// const actionMap: Map<number, ActionKeyframe[]> = new Map();
const actionMap = [];
const annotationFragmentation = [];
// annotations = sortAnnotationsByStart(annotations);
// STEP 1: Create a Map, containing the rendering actions for each index in the document.
// this could be opening or closing an annotation
annotations.forEach((term, index) => {
// create an opening action keyframe
const open = {
action: 'open',
annotationIndex: index,
textAnchor: term.from,
};
// create a closing action keyframe
const close = {
action: 'close',
annotationIndex: index,
textAnchor: term.to,
};
const openMapElement = actionMap[open.textAnchor];
// create empty actions list if necessary
if (!openMapElement) actionMap[open.textAnchor] = [];
actionMap[open.textAnchor].push(open);
const closeMapElement = actionMap[close.textAnchor];
if (!closeMapElement) actionMap[close.textAnchor] = [];
actionMap[close.textAnchor].push(close);
});
actionMap // STEP 2: iterate the actionMap and generate the annotation UI elements
.forEach((actions, _) => {
actions.forEach(action => {
// check if there are still open annotations
if (openAnnotationStack.length !== 0) {
const actionStackPeek =
openAnnotationStack[openAnnotationStack.length - 1];
if (
actionStackPeek.action === 'open' &&
actionStackPeek.annotationIndex === action.annotationIndex &&
action.action === 'close'
) {
// base case: the last opened annotation is closed by next action
openAnnotationStack.pop();
const rendering = annotationFragmentation[action.annotationIndex]
? 'fragment-right'
: 'normal';
const from = annotationFragmentation[action.annotationIndex]
? renderedAnnotations[renderedAnnotations.length - 1].to
: annotations[action.annotationIndex].from;
const normalTerm = Object.assign(
Object.assign({}, annotations[action.annotationIndex]),
{ from, rendering },
);
renderedAnnotations.push(normalTerm);
} else if (
actionStackPeek.action === 'open' &&
action.action === 'close'
) {
// annotation is closed while being overlapped by another annotation
// -> find "open" action and remove it, otherwise a new truncated segment would be created
const indexOfActionToRemove = openAnnotationStack.findIndex(a => {
return (
a.textAnchor === annotations[action.annotationIndex].from &&
a.annotationIndex === action.annotationIndex &&
a.action === 'open'
);
});
if (indexOfActionToRemove > -1) {
openAnnotationStack.splice(indexOfActionToRemove, 1);
} else {
throw Error(
"Couldn't find opening keyframe for annotation " +
action.annotationIndex,
);
}
} else if (
actionStackPeek.action === 'open' &&
action.action === 'open'
) {
let fragment;
if (annotationFragmentation[actionStackPeek.annotationIndex]) {
// n-th truncation (n > 1): render a middle fragment
fragment = Object.assign(
Object.assign({}, annotations[actionStackPeek.annotationIndex]),
{
rendering: 'fragment-middle',
// start where the last rendered annotation ends + 1
from: renderedAnnotations[renderedAnnotations.length - 1].to,
// stop where the next annotation begins - 1
to: annotations[action.annotationIndex].from,
},
);
} else {
// first-time-truncation: a new annotation begins, truncating the old open annotation
fragment = Object.assign(
Object.assign({}, annotations[actionStackPeek.annotationIndex]),
{
rendering: 'fragment-left',
to: annotations[action.annotationIndex].from,
},
);
// mark the previous annotation as fragmented, by saving where the fragment ends
annotationFragmentation[actionStackPeek.annotationIndex] = true;
}
renderedAnnotations.push(fragment);
openAnnotationStack.push(action);
}
} else if (action.action === 'open') {
openAnnotationStack.push(action);
}
});
});
return renderedAnnotations;
};
export const sortAnnotationsByStart = annotations => {
return annotations.sort((a, b) => a.from - b.from);
};
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment