I have a collaborative text editor that allows others to leave comments on the owners document. This is done with prosemirror decorations, and stored in a Ydoc as a YMap with a key of “annotations.” The primary content of the document is the YXMLFragment with the “default” key. Accessable via:
console.log("getMap for annotations :>> ", provider.document.getMap("annotations"));
console.log(
"getXmlFragment for main doc :>> ",
provider.document.getXmlFragment("default")
);
Saving usually looks like this:
const documentState = Y.encodeStateAsUpdate(provider.document); // is a Uint8Array
const base64Encoded = fromUint8Array(documentState);
I’ve prevented users from making changes to the document content by using proseMirror’s “handleDOMEvents” for a variety of cases, but it’s still allowing contributors (who are just supposed to annotate) to update a field that stores the main document content which seems like a recipe for disaster (already had some issues).
I think it might be better to store the Map (annotations) and XMLfragment (content) separately. Any suggestions on how to do this? I’m struggling to figure out an approach for initializing/saving in a model like this. Any suggestions would be greatly appreciated.
Conceptually, I was considering something like this. But Ideally, I want to prevent non-owners from ever updating the main content XMLFragment (key = default) in the first place because I wouldn’t want that visible in the collaborative editor, becuase when the main user makes a change, it would like see the unapproved change and accept whatever was there. Is there a way to detect which document type was modified or is trying to be modified?
import { toUint8Array, fromUint8Array } from 'js-base64';
import * as Y from 'yjs';
const ydoc = new Y.Doc();
async function initialize(base64MainContent, base64Annotations) {
const mainContentUint8Array = toUint8Array(base64MainContent);
const annotations = toUint8Array(base64Annotations);
const mainContent = Y.decodeStateAsUpdate(mainContentUint8Array);
const annotationsUpdate = Y.decodeStateAsUpdate(annotations);
//set???
ydoc.transact(() => {
ydoc.getXmlFragment('default').applyUpdate(mainContent);
ydoc.getMap('annotations').applyUpdate(annotationsUpdate);
});
}
function save() {
//prevent if not authorized??
const mainContent = Y.encodeStateAsUpdate(ydoc.getXmlFragment('default'));
const base64MainContent = fromUint8Array(toUint8Array(mainContent));
saveMainContentToDB(base64MainContent);
//Allow for contributors??
const annotations = Y.encodeStateAsUpdate(ydoc.getMap('annotations'));
const base64Annotations = fromUint8Array(toUint8Array(annotations));
saveAnnotationsToDB(base64Annotations);
}