Skip to content
Snippets Groups Projects
CommentState.js 3.88 KiB
Newer Older
chris's avatar
chris committed
/* eslint-disable no-param-reassign */
import { v4 as uuidv4 } from 'uuid';
import { Decoration, DecorationSet } from 'prosemirror-view';
chris's avatar
chris committed
import {
  ySyncPluginKey,
  relativePositionToAbsolutePosition,
  absolutePositionToRelativePosition,
} from 'y-prosemirror';
chris's avatar
chris committed
import CommentDecoration from './CommentDecoration';
chris's avatar
chris committed
import { CommentDecorationPluginKey } from './CommentDecorationPlugin';
chris's avatar
chris committed

const randomId = () => {
  return uuidv4();
};

export default class CommentState {
  constructor(options) {
    this.decorations = DecorationSet.empty;
    this.options = options;
  }

  addComment(action) {
    const { map } = this.options;
    const { from, to, data } = action;
    const id = randomId();
    map.set(id, { id, from, to, data });
  }

  updateComment(action) {
    const { map } = this.options;
    const annotationToUpdate = map.get(action.id);
    if (annotationToUpdate) {
      annotationToUpdate.data = action.data;
    }
  }

  deleteComment(id) {
    const { map } = this.options;
    map.delete(id);
  }

  commentsAt(position, to) {
    return this.decorations.find(position, to || position).map(decoration => {
      return new CommentDecoration(decoration);
    });
  }

  allCommentsList() {
    const { map } = this.options;
    return Array.from(map, ([key, value]) => {
chris's avatar
chris committed
      return { ...value, id: key };
chris's avatar
chris committed
    }).filter(value => {
      return 'from' in value && 'to' in value;
    });
  }

  createDecorations(state) {
    const decorations = [];
chris's avatar
chris committed
    const ystate = ySyncPluginKey.getState(state);
    const { doc, type, binding } = ystate;
chris's avatar
chris committed

chris's avatar
chris committed
    const { map } = this.options;
    console.log(binding);
    if (binding) {
      console.log(doc, type, binding);
      map.forEach((annotation, id) => {
        console.log(annotation);
        const from = relativePositionToAbsolutePosition(
          doc,
          type,
          annotation.from,
          binding.mapping,
        );
        console.log(from);
        const to = relativePositionToAbsolutePosition(
          doc,
          type,
          annotation.to,
          binding.mapping,
        );

        if (!from || !to) {
          return;
        }

        decorations.push(
          Decoration.inline(
            from,
            to,
            {
              class: 'comment',
              'data-id': annotation.id,
            },
            {
              id: annotation.id,
              data: annotation,
              inclusiveEnd: true,
            },
          ),
        );
      });
    }

    // this.allCommentsList().forEach(annotation => {
    //   const { from, to } = annotation;

    //   decorations.push(
    //     Decoration.inline(
    //       from,
    //       to,
    //       {
    //         class: 'comment',
    //         'data-id': annotation.id,
    //       },
    //       {
    //         id: annotation.id,
    //         data: annotation,
    //         inclusiveEnd: true,
    //       },
    //     ),
    //   );
    // });
chris's avatar
chris committed
    this.decorations = DecorationSet.create(state.doc, decorations);
  }

  apply(transaction, state) {
chris's avatar
chris committed
    const action = transaction.getMeta(CommentDecorationPluginKey);
chris's avatar
chris committed
    if (action && action.type) {
      if (action.type === 'addComment') {
        this.addComment(action);
      }
      if (action.type === 'updateComment') {
        this.updateComment(action);
      }
      if (action.type === 'deleteComment') {
        this.deleteComment(action.id);
      }
      this.createDecorations(state);
      return this;
    }

    this.options.map.forEach((annotation, _) => {
      if ('from' in annotation && 'to' in annotation) {
        annotation.from = transaction.mapping.map(annotation.from);
        annotation.to = transaction.mapping.map(annotation.to);
      }
    });
    this.createDecorations(state);
    return this;
  }
}

//  let res =
//    annotation.to === state.selection.to &&
//    state.selection.from === state.selection.to;
//  console.log(res, transaction.docChanged);