Newer
Older
import React, { useContext, useState, useEffect, useMemo, useCallback } from 'react';
import { each, uniqBy, sortBy } from 'lodash';
import { WaxContext } from 'wax-prosemirror-core';
import { DocumentHelpers } from 'wax-prosemirror-utilities';
import BoxList from './BoxList';
view: { main },
app,
activeView,
} = useContext(WaxContext);
const commentPlugin = app.PmPlugins.get('commentPlugin');
const [position, setPosition] = useState();
const setTops = useCallback(() => {
const result = [];
let annotationTop = 0;
let boxHeight = 0;
let top = 0;
const nodesMarksToIterrate = marksNodes[area] === 'main' ? sortBy(marksNodes[area], ['pos']) : marksNodes[area];
each(nodesMarksToIterrate, (markNode, pos) => {
const id = markNode instanceof Mark ? markNode.attrs.id : markNode.node.attrs.id;
const activeComment = commentPlugin.getState(activeView.state).comment;
if (activeComment && id === activeComment.attrs.id) isActive = true;
if (markNodeEl) annotationTop = markNodeEl.getBoundingClientRect().top - WaxSurface.top;
const panelWrapper = document.getElementsByClassName('panelWrapper');
const panelWrapperHeight = panelWrapper[0].getBoundingClientRect().height;
markNodeEl = document.querySelector('#notes-container').querySelector(`[data-id="${id}"]`);
if (markNodeEl) annotationTop = markNodeEl.getBoundingClientRect().top - panelWrapperHeight - 50;
const boxEl = document.querySelector(`div[data-box="${id}"]`);
// where the box should move to
top = annotationTop;
// if the above comment box has already taken up the height, move down
if (pos > 0) {
const previousEndHeight = previousBox.endHeight;
if (annotationTop < previousEndHeight) {
top = previousEndHeight + 2;
}
}
// store where the box ends to be aware of overlaps in the next box
allCommentsTop.push({ [id]: result[pos] });
// if active, move as many boxes above as needed to bring it to the annotation's height
if (isActive) {
let b = true;
let i = pos;
// first one active, none above
const boxAboveEnds = boxAbove.endHeight;
const currentTop = result[i];
const doesOverlap = boxAboveEnds > currentTop;
if (doesOverlap) {
const overlap = boxAboveEnds - currentTop;
result[i - 1] -= overlap;
const previousMarkNode =
marksNodes[area][i - 1] instanceof Mark
? marksNodes[area][i - 1].attrs.id
: marksNodes[area][i - 1].node.attrs.id;
}
if (!doesOverlap) b = false;
if (i <= 1) b = false;
i -= 1;
}
}
});
}, [JSON.stringify(updateMarks(view)), JSON.stringify(setTops())]);
const CommentTrackComponent = useMemo(
() => <BoxList commentsTracks={marksNodes[area] || []} area={area} view={main} position={position} />,
// TODO if allInlineNodes and allBlockNodes count don't change, do not compute again
const updateMarks = view => {
if (view.main) {
const allInlineNodes = [];
Object.keys(view).forEach(eachView => {
allInlineNodes.push(...DocumentHelpers.findInlineNodes(view[eachView].state.doc));
});
const allBlockNodes = DocumentHelpers.findBlockNodes(view.main.state.doc);
allInlineNodes.map(node => {
if (node.node.marks.length > 0) {
node.node.marks.filter(mark => {
if (
mark.type.name === 'comment' ||
mark.type.name === 'insertion' ||
mark.type.name === 'deletion' ||
mark.type.name === 'format_change'
finalMarks.push(mark);
}
});
}
allBlockNodes.map(node => {
if (node.node.attrs.track && node.node.attrs.track.length > 0) {
finalNodes.push(node);
}
});
const nodesAndMarks = [...uniqBy(finalMarks, 'attrs.id'), ...finalNodes];
const groupedMarkNodes = {};
nodesAndMarks.forEach(markNode => {
const markNodeAttrs = markNode.attrs ? markNode.attrs : markNode.node.attrs;
if (!groupedMarkNodes[markNodeAttrs.group]) {
groupedMarkNodes[markNodeAttrs.group] = [markNode];
groupedMarkNodes[markNodeAttrs.group].push(markNode);