Possible to collaborate in different docFormat of the same document?

If the internal document model is the same, could one work in HTML and another work in markdown?

Another example is a real-time html/markdown editor, side by side, change one and result shows in the other in real-time and not converting the entire document?

The docFormat option takes effect only at startup – it indicates how the doc option should be interpreted to convert it to ProseMirror’s own document format.

The conversion to and from Markdown is currently lossy – it loses information such as the precise indentation, line breaks, list marker characters used, etc, so you can’t sync between a Markdown text editor and a ProseMirror instance without some normalization of the text happening. There are plans to build a schema and parser/serializer to accurately represent Markdown annotation, and losslessly serialize it back, but that’s a rather big project and I have a bunch of more important stuff to do first.

1 Like

I understand this lossy issue, I tried to write a HTML->Markdown converter before and I know it is not straight forward like Markdown->HTML and eventually gave up.

I think the approach with converting to/from an internally consistent document format is most likely to succeed in attacking this problem, with or without a rigid schema because at least the document model is consistent and well formed; normalization of text is not a big deal as long as the conversion loss doesn’t accumulate/expand during conversions.

I guess I don’t mind the normalization of text, but how to propagate changes between two editors that could have the same document model to start with?

What I am thinking is when I make changes to markdown, I convert it to a new document tree, compare this against the original document tree to generate the transform steps and apply that to the editor holding the HTML, is that workable?

I tried to follow the demo in the source, but not sure how I can compare two documents and generate the necessary transform steps?

There is no clever diffing available yet. There’s primitives to find the end and start of a change in model/diff.js, and an example of how to use them in edit/domchange.js, but that only works well for single-replaced-range type of changes.

Also, if you allow editing in the HTML view, you’ll have to somehow convert those changes back to Markdown as well, without messing up the structure of the text.

I borrowed applyDOMChange and ad hoc use the default schema, things seems to work, will watch for edge cases:

    function markdown_html(){                                                                                                                                                    
            // takes markdown and convert to internal doc model                                                                                                                  
            let newdoc=fromMarkdown(schema, markitor.getContent("text"));                                                                                                        
                                                                                                                                                                                 
            // find the transform from orig doc to new doc                                                                                                                       
            // borrow from applyDOMChange                                                                                                                                        
            applydocChange(editor,newdoc);                                                                                                                                       
                                                                                                                                                                                 
            html_markdown(); //since the html is the true reference, we take a hit with markdown normalization                                                                   
    };                                                                                                                                                                           
                                                                                                                                                                                 
    function html_markdown(){                                                                                                                                                    
            let markdown=toMarkdown(editor.doc);                                                                                                                                 
            let markdowndoc=fromText(schema,markdown);                                                                                                                           
                                                                                                                                                                                 
            applydocChange(markitor,markdowndoc);

So what I notice is that this applydocchanges technique works quite well for “single-replaced-range” type of changes; this means it works quite well if say you make changes to the markdown editor and then you press a button to affect a separate html editor. It seems to work vice vesa quite well as well.

But in practice you would expect changes to flow in real time between the two editors (in another word you type in markdown editor and the html editor changes immediately). When I tried to do that, things starts to breakdown, it would work sometimes and then suddenly the cursor would fly all over the place. I am guessing the conversion is taking longer than the transform and things starts to get out of order and it gets messy.

And we start to get into collaboration territories, maybe rebasing in collab.js might help or maybe some sort of suppression to avoid overlapping conversion/transform?

Thanks for all your work on ProseMirror!

I was wondering if you had any updated thoughts or progress on this. Has the schema changed in any significant way that would allow this to be more approachable?

Even if the conversion from proseSchema > Markdown is lossy, would there be a lossless way to capture differences?

Say, in Markdown, you change ‘cat’ -> ‘cats’. Would there be a way to identify which ProseMirror schema transform that should be and apply it to the ground truth proseSchema object (thus allowing syncing, etc)?

2 Likes

Hoping to revive this topic since A) I’m really interested in it and B) I don’t understand it so I’d like to write my thoughts out.

Starting with the website example for markdown: http://prosemirror.net/examples/markdown/

As I understand it, this example is not really applicable to collaboration because the editor is either a textArea with markdown in it, or a Prosemirror instance, but it is never a Prosemirror instance with markdown in it.

Now the example could instead convert the Prosemirror code into markdown and replace the state of the existing Prosemirror instance with the markdown code, but this is a naive delete and update of the entire previous state of the document (not that that is any worse than what the example is doing, it just doesn’t get us any closer to collaboration).

To seamlessly collaborate the same content across two editors instances… First instance has the document formatted in Markdown, and Second instance has the document formatted in HTML, you need to normalize the transformations that happen between the two. This is very difficult though because so many things are different between the two editor doc formats. The most basic of them being node position/index.

The first line in a Markdown Prosemirror document might be something this: [weblink](http://web.link)

Whereas in an HTML Prosemirror document it would be: weblink

The internal Prosemirror schema representation would have the former be represented as plain-text node and the latter a node with marks propties of text=“weblink” type.name=“link” attrs.href=“http://web.link” etc…

let’s say you change the text of the link. When modifying this in one type of editor, the position/index is different than in the other, so the transforms are not shareable without some type of fancy normalization.

Now I’m not sure if what I say above is actually true. Even if it is, this is where I totally get lost on what the next step towards a solution would even be. It seems like you’d need some fancy way of parsing an interpreting the changes on the markdown document…

Let’s say you had written [weblink(http://web.link) in the Markdown based editor. This plain text would be propagated over to the HTML Prosemirror editor. Then you realize your mistake and add the closing ] on the right side of weblink.

In the Markdown editor, this change just represents a single step transformation of adding a character to a specific position in a plain text node. In the HTML editor wouldn’t it be necessary for the transformation to be a deletion of the the text node: [weblink(http://web.link) and the insertion of a link node: weblink??

Now looking at this in a slightly different way. Would it be a lot more straightforward if we allowed for markdown to be written in a standard Prosemirror instance, but automatically convert said markdown to HTML. So as soon as someone wrote [weblink](http://web.link) it would be converted into a transformation step that deleted that text node and inserted weblink. Now a user could write either way and doing the collaboration not next to impossible. You could still do read-only conversion of the text to Markdown if you wanted to copy paste Markdown… the only limitation would be that you can’t write and view the native markdown representation.

Would appreciate any feedback on where I am totally not getting things!

Hi!

First, I would say thank for your effort put upon Prosemirror editor. You made a great job there.

My team tries to incorporate Posemirror editor in one of our products and apparently need some advice on how to make it right. In fact we are on the same page where @funkyeah was two years ago.

We have taken http://prosemirror.net/examples/markdown/ as an example and implemented collaborative editing protocol for html (WYSIWYG) editor. It works pretty well, but the problem we faced now is how to support collaborative editing in markdown editor as well, so that one user can type something in html editor and another one in markdown so that both changes would be applied as if those were made in different html editors.

I looked through tracker and forums and found nothing newer than this thread, it looks as if this is a kind of open question that is not solved yet.

I would greatly appreciate if someone who has successfully built such WYSIWYG/Markdown editor could have shared his experience.

We have end up now with some intermediate solution: every change made in markdown makes collaborative clients to reconnect and reload their states, but this obviously is not a convenient approach (collaborative client loose some state on reconnection). Also we have thought about disabling markdown editor input if there are active connections to collaborative(WYSIWYG) clients and vice versa, but that also sounds not excellent. Another solution would have been removing markdown editor at all leaving WYSIWYG only.

Hope for your advice here, thanks for your help in advance.