Ritzy – A collaborative web-based rich text editor
github.com
github.com
- Accessibility. Screen readers don't know what you are doing if the browser doesn't know. They won't communicate your tag soup to the user as an editor interface.
- Cursor motion and selection management hard. Consider right-to-left text and mixed bidirectional text. Getting this right is a big project on its own. You can get the basics working easily, but there's a long tail of hard behavior that you will at some point need.
- Touch interfaces don't interface well with your fake selection. So you'll have to implement your own selection-management interface. Which might not even be possible for some things (like access to the built-in spell checker).
- It isn't needed. Though it also requires some gymnastics, working with the browser's native selection on modern browsers isn't all that hard.
Missing standard text editor behavior that I know of:
- right-clicking on selected text
- dragging-and-dropping selected text
- triple-click to select paragraph
- OS X emacs keybindings: ctrl+n/p/f/b as arrow keys, ctrl+a/e to go to beginning/end of line, ctrl+k/y to cut/paste, etc
If you're going to even entertain the thought of writing an editor I recommend reading Piotrek Koszuliński's article on Medium [1]. There are many pitfalls when writing an editor and the sooner you know of them the better.
On the plus side a new spec for a more low-level version of contentEditable is currently being worked on.[2] It's a complicated undertaking but the task force is making progress. There is participation from all major browser vendors so we have reasons to be optimistic: we may make it out of the Dark Ages of web-based rich editing one day.
[1] https://medium.com/content-uneditable/contenteditable-the-go...
[2] https://medium.com/content-uneditable/fixing-contenteditable...
Tried it on a 2,000 line text file and it caused Chrome 44 on Yosemite to time out close the tab.
https://github.com/ProseMirror/prosemirror
It's by the guy who created CodeMirror and TernJS.
https://github.com/ritzyed/ritzy-demo/blob/master/src/create...
Also, instead of just pointing to the code on github, I'd like to get at least a little insight into the architecture of the project, because that is the interesting part, in my opinion. There is a brief description in the readme on github, but it doesn't really paint a clear picture.
For a game, there's some sophisticated math involved. But for a text editor? You only need to perform basic arithmetic on the scroll position and window height to index in to a vector of lines.
In React, you could render exactly 50 <Line> components and choose which 50 by exactly the same means vim chooses which 50 ncurses lines to show.
Does this handle RTL text input and accessibility issues?
If you're looking for a good collaborative rich text editor on the web, look up Quill or ProseMirror.
ProseMirror looks cool. I wish @Marijn the best with it! Not sure about ProseMirror's offline capabilities. I hope he adds multiple cursors and selections like Google Docs (and Ritzy).
I realize that there is a commercial service aspect that is being worked on to provide server side hosting, however, how easy would it be to self host this on sandstorm.io?
On mac you use cmd-C, cmd-V instead of control-C, control-V.
There is a bug that causes new line to function incorrectly when the cursor is on the first line of the document. New line on other lines work fine. (Safari on Mac)
Some responses to the various comments:
1) This is a very early release. I'm aware of all the missing functionality, and the README is pretty clear about all the missing stuff, including undo/redo, bullets, numbered lists, tables, and more. I don't have access to a Mac, so I wouldn't expect any of the Mac keybindings to work. That should be pretty easy to solve though.
2) Piotrek Koszuliński's article was really eye opening. Being completely new to the field of editors, and even new to Javascript (this is my first major Javascript project -- my background is mostly enterprise Java and some Scala), I defer to experts in this field like Piotrek and Marijn, the author of Codemirror and Prosemirror. I'm honored that Marijn even took the time to comment :-) It's possible that Ritzy could still serve as a useful tool within some narrower contexts that do not require handling the long tail of hard behavior mentioned (accessibility and RTL/bidi). OR, with the appropriate expertise, that some of that functionality could be added. Re. touch interfaces, fair point -- my thought was that could be worked around (e.g. by an alternate native component on touch interfaces that talked the same CRDT language -- I believe that's the approach that Google Docs took with editing Docs on mobile). Currently on mobile, basic cursor navigation by text, keyboard / text input, and viewing others' changes in real-time appears to work pretty well (better than I expected actually!). Selections don't work at all.
@marijn: how difficult would it be to add multiple cursors and selections to Prosemirror? I notice that currently the Prosemirror collaboration demo does not show cursors or selections, which is pretty key to a great user experience.
3) @gritzo (the author of Swarm.js, a key library used in Ritzy) mentions that the implementation uses a JS object for each char. That is true and it's very heavy. My initial goal was correctness and as a POC, with something easy to understand and debug. Optimization can come later, if indeed there is interest in taking this general approach further.
4) Recent changes to Ritzy (not yet pushed to the demo page) make each cursor, line, and selection a separate React component within a hierarchy. This makes navigation, rendering and selections pretty quick. However, the editor has never been tested against documents larger than a few hundred lines. My gut feeling is that the limiting factor right now is not React, but the "fat" CRDT data structure I used. It gets particularly bad when a lot of characters are deleted. There is no tombstone clearing logic yet.
5) It should be pretty easy to strip out the server-side stuff and make it client-side only. You lose the "killer feature" of Docs-style collaborative editing though. The server-side is pretty simple to self-host -- check out the demo source code @ https://github.com/ritzyed/ritzy-demo for an example.
I'll try to get the demo back up and running. Its hosted on the smallest (free) tier of Openshift and I've done zero server-side optimization. I'm sure it didn't take much traffic to kill it. Any other suggestions for (free) hosting for NodeJS projects?
I'll also try to write up a design doc over the next few days for those who requested that / are more interested in those aspects.
Thanks again for all the comments / feedback!
If you mean Sublime Text-style multiple cursors, that'd be very hard. CodeMirror's contentEdtiable-base mobile backend does support them, but that's only possible because it already contains a full implementation of cursor/selection for the non-mobile version.
If, on the other hand, you mean showing the cursors from other people working on a collaborative document, that isn't very hard, it just involves inserting widgets and marked ranges at the right places.
This is what I meant. Good that its not very hard. Though I'm curious: how do you know what the "right place" actually is i.e. don't the coordinates of the cursor position depend on the rendering of the text which is under the browser's control?
What about showing multiple selections from other authors like Google Docs (and Ritzy) does?
Yes, but you can ask the browser (using `getBoundingClientRect` and `getClientRects`, which also exist for text range object on all halfway modern browsers.) Or you can insert the caret element inline at the correct place.
What would be hard about showing a selection from another person?