= Ritzy Editor
:toc:
:sectanchors:

image:https://badges.gitter.im/Join%20Chat.svg[link="https://gitter.im/ritzyed/ritzy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]

[[about]]
== About

=== Demo / Short Introduction (TL;DR)

Finally, a good, open source, cross-browser [1], rich text, real-time
collaborative editor for the web! Here is a demo:

<<TODO>>

[1] IE10+ and evergreen browsers supported

=== Longer Introduction

The Ritzy editor is a rich text, real-time character-by-character collaborative
browser-based editor. It shuns use of the
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_Editable[contentEditable]
attribute in favor of a custom editor surface and layout engine, exactly like
the approach
http://googledrive.blogspot.ca/2010/05/whats-different-about-new-google-docs.html[implemented
by] Google Docs.

In addition, and also like Google Docs, Ritzy is built with real-time
collaborative editing support from the ground up, unlike most browser-based
editors that require third-party plugins or that do not support it at all.

Ritzy implements all the basic expected text editing functionality, such as
bold, underline, strikethrough, superscript, subscript, selection via keyboard
and mouse, cut, copy, and paste. More capabilities will be added as needed or as
third-party contributions are received.

==== Limitations and Target Audience

Unlike Google Docs, Ritzy does not (currently) support complex page-based layout
needed to build a word processor. It will be most useful for those developers
who wish to add collaborative rich-text data entry fields to their browser
applications. However, some layout capabilities are planned to be added over
time, such as bulleted and numbered lists, styles, and other such features.

[[about_surface]]
=== JavaScript Surface and Layout Engine

The
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_Editable[contentEditable]
attribute used by most editors allows the editor to delegate the capture of user
input and the display of the editor contents and selections to the browser. This
is "easy" and performs very well, but is https://vimeo.com/76219173[limited] and
https://medium.com/medium-eng/why-contenteditable-is-terrible-122d8a40e480[broken]
by browser capabilities and incompatibilities in `contentEditable`
implementations, and by the underlying HTML data model which is not suited for
collaborative editing. Instead, Ritzy implements a custom surface and layout
engine like Google Docs:

[quote, Jeff Harris (Google Docs Product Manager),http://googledrive.blogspot.ca/2010/05/whats-different-about-new-google-docs.html]
Let’s start by talking about the editing surface, which processes all user input
and makes the application feel like a regular editor. To you, the new editor
looks like a fairly normal text box. But from the browser’s perspective, it’s a
webpage with JavaScript that responds to any user action by dynamically changing
what to display on each line. For example, the cursor you see is actually a
thin, 2 pixel-wide div element that we manually place on the screen. When you
click somewhere, we find the x and y coordinates of your click and draw the
cursor at that position. This lets us do basic things like slanting the cursor
for italicized text, and it also allows more powerful capabilities like showing
multiple collaborators’ cursors simultaneously, in the same document.

==== Pros and Cons ====

This approach is more flexible than `contentEditable`. The logic is consistent
across browsers, and there are no browser-specific workarounds for the document
model. The document model is only ever modified through explicit application
action (rather than by the browser as happens with contentEditable), ensuring
that the content of the internal document model is repeatable and consistent.

The document model is not HTML -- it is completely independent of the editor
surface. Therefore it should be easier to support applications that need to
customize the editor surface with new controls and/or behavior. Examples of this
would be inline spelling error notations or comments.

The downside is that having a custom editor surface unmanaged by the browser
requires significant complexity to do things the browser would normally provide
for free, such as: cursor motion and positioning (even blinking the cursor!),
dealing with accessibility concerns, non-left-to-right text orientations, user
inputs that are not raised as application events by the browser, and other such
capabilities.

[[about_collaboration]]
=== Real-time Character-by-character Collaborative Editing ===

Ritzy's real-time collaborative editing uses a different approach than Google
Docs, which based on public information is based on
http://en.wikipedia.org/wiki/Operational_transformation[operational transform]
(OT). Operational transforms require implementing a transform for every
operation, and dealing specially with lots of corner cases, especially as the
complexity of the model increases.

Instead, Ritzy uses operation-based
http://en.wikipedia.org/wiki/Conflict-free_replicated_data_type[conflict free
replicated data types] (CRDTs) to implement the concurrency control required for
real-time character-by-character collaborative editing. Just like OT, CRDTs
allow changes to happen in different orders on each instance, but the final
editor state to converge.

See <<design_collaboration>> below for more technical details.

[[about_other]]
=== Other Features

Beyond basic text editing, some other features implemented by Ritzy:

* Paragraph flow control, including wrapping support for long words/URLs.

* Selection and keyboard navigation behavior mimicking common platforms like
Microsoft Word and Google Docs.

* Multiple author colored/labeled cursor and selection tracking in real-time.

* Cursor blink control simulating browser function (blink while waiting, no
  blink during operations).

* Cursor slant when traversing italic text.

* Automatically scrolling the document window horizontally and vertically to
keep the cursor visible.

* Cut/copy/paste of clipboard data, including conversion between rich text and
HTML.

* Focus/blur support with appropriate styling for cursors (invisible) and
selections (gray).

* API to control the editor and to obtain selections as HTML, text, or rich
text (though more work is needed here).

[[design]]
== Design and Implementation

[[design_surface]]
=== Editor Surface

The editor uses Facebook's http://facebook.github.io/react/[React] to manage
rendering for the editor surface. React is perfect for this purpose as most user
input and selection operations alter the surface only slightly -- to insert or
remove characters, to highlight selections, and to position the cursor. For each
of these, React can instruct the browser to make the minimum number of required
changes to the DOM that represents the editor surface. Since modifying the DOM
is an expensive operation performance-wise, React is key to Ritzy's smooth
performance. React's virtual DOM / state abstraction also makes code maintenance
simpler.

[[design_layout]]
=== Layout

Managing the layout in JavaScript requires knowledge of the x-y positions of
individual characters, for example to position the cursor when the user clicks
on text, or to wrap text within the editor's bounding box.

Ritzy prefers using http://nodebox.github.io/opentype.js/[Opentype.js] to obtain
the required text metrics from the underlying font, such as
http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html[advance widths] for
the glyphs that represent each character.

When the browser/OS platform supports linear subpixel positioning and faithfully
follows the font's instructions for it's text rendering, the font metrics are
sufficient to calculate x-y positions. However, on some browsers on some
platforms at some font sizes, for various complicated reasons the font metrics
are ignored in favor of http://goo.gl/yf3M7[hinting or other mechanisms]. In
these situations, the layout engine falls back to a slower but reliable
mechanism using the canvas `measureText` function.

To use the Opentype.js mechanism, all fonts displayed by Ritzy must be available
as TrueType or OpenType font files. Note that Opentype.js does not
https://github.com/nodebox/opentype.js/issues/43[currently support] WOFF font
files, but usually TrueType or OpenType equivalents are available. In addition,
the font is loaded into memory twice: by the browser and by Ritzy.

[[design_collaboration]]
=== Collaborative Editing ===

Collaborative editing requires each editor client to "report" changes i.e.
operations such as inserting or deleting characters, or changing character
attributes, to peers. Peers in turn, accept these changes and display them on
their own editor surfaces, while themselves dealing with user input and
reporting their own changes.

To handle this concurrency, Ritzy uses a
http://en.wikipedia.org/wiki/Conflict-free_replicated_data_type[CRDT]-based
http://www.pds.ewi.tudelft.nl/~victor/polo.pdf[causal trees] approach created by
https://github.com/gritzko[Victor Grishchenko], running on the
http://swarmjs.github.io/[Swarm.js] library created by the same author. Each
client possesses a causal trees "replica" of the current state of the rich text
within the Ritzy editor.

Essentially, with causal trees, every character has a unique id, and all
operations and positioning is relative to these ids. This greatly simplifies
simultaneous operations that are complex with index-based approaches, at the
cost of significantly greater disk and memory requirements. This is generally
not an issue for text content on modern machines.

Ritzy requires a NodeJS or io.js server running and bidirectionally connected to
each editor client via WebSockets or a long-polling mechanism. The server is
responsible for receiving changes from all editors and transmitting them back to
other editors. A default server implementation is provided as part of the Ritzy
project. Currently, Ritzy does not operate stand-alone, though it should not be
too difficult to add this capability (see <<roadmap>>).

Unlike other collaborative editing techniques such as OT and diff-match-patch,
the causal trees approach is highly amenable to offline editing, therefore
offline editing is intended to be a valid use case for Ritzy.

[[integration]]
== Ritzy Integration

[[integration_es6]]
=== ES6

The editor uses JavaScript ES6. Ensure your consuming client and server-side
code transpiles to ES5 via babel or similar transpiler, and contains the
appropriate ES6 polyfills. See the
https://github.com/ritzyed/ritzy-demo/blob/master[Ritzy demo] for an example.

[[integration_cs]]
=== Client-Side

See `client.js` or the https://github.com/ritzyed/ritzy-demo/blob/master[Ritzy
demo] for an example of creating and using the editor.

It should be possible to create multiple editors on one page, though this is not
yet a tested configuration.

[[integration_ss]]
=== Server-Side ===

The server-side integration mechanism for most applications employing Ritzy will
be to create a Ritzy Swarm.js peer within their server-side application, which
will be responsible for receiving all updates to text replicas. The application
can then use that text replica for any purpose.

See https://github.com/ritzyed/ritzy/blob/master/src/server.js[server.js] or the
https://github.com/ritzyed/ritzy-demo/blob/master[Ritzy demo] for an example of
this.

Currently, Swarm.js peers only run within JavaScript environments, but the
author http://swarmjs.github.io/articles/android-is-coming/[plans] to support
other languages in the future.

See also <<commercial_features>>.

[[developers]]
== Developers

See
https://github.com/ritzyed/ritzy/blob/master/docs/CONTRIBUTIONS.adoc[CONTRIBUTIONS]
and
https://github.com/ritzyed/ritzy/blob/master/docs/DEVELOPMENT.adoc[DEVELOPMENT].

[[roadmap]]
== Roadmap

The following is a tentative list of features and capabilities that will be
added over time.
https://github.com/ritzyed/ritzy/blob/master/docs/CONTRIBUTIONS.adoc[Contributions]
are welcome.

* Tests (many, see GitHub issue xx) (hard!).

* Once tests are in place, refactoring to make the editor code more modular /
easier to understand (hard).

* Performance improvements. Performance is not bad right now, but much can
be done to improve it further. Some ideas:
** Create finer-grained React components (see refactor above) to avoid
re-rendering the entire editor on updates (this should be a big win).
** Use immutable collections as much as possible e.g.
http://facebook.github.io/immutable-js/
** Implement `shouldComponentUpdate` and/or `PureRenderMixin` to avoid
unnecessary component renders, taking advantage of reference equality with
immutable data structures.
** Implement some type of indexing for characters.
** Cache frequently used / slow operations where possible.
** Server-side performance improvements. Currently the initial load can become
very slow as the replica continues to grow.

* Undo/redo

* Styles for content e.g. headings, lists, etc. (medium).

* Expose an API for programmatic access to the editor and contents (medium):
** Get/set contents using the native data model for proper concurrency control
** Get contents as HTML
** Insert HTML at a particular position specified by the native data model
** Event callbacks for inserts, deletions, changes, and selections
** Command and status support for text attributes e.g. to support a toolbar
** See http://w3c.github.io/editing/historic-editing-apis.html[Historic Editing
APIs] for comparison/implementation with
contentEditable-based APIs

* Better input handling for non-English languages (medium to hard?).

* A skinnable and/or replaceable toolbar that leverages the editor API (medium).

* Make Ritzy work apart from a shared replica and server implementation. Create
a local-only replica with the same API (medium).

* Test and support editor fonts other than OpenSans (easy to medium?).

* Handle font size as a character attribute (medium to hard).

* Reduce the number of dependencies and lower download size as much as is
possible without sacrificing clarity and maintainability.

* Search/replace

* Figures and tables (TODO).

* Bullets and numbering (TODO).

* Inline images (TODO).

* Right-click menu support (medium).

* Color-coded authoring display (medium).

* Text highlighting (easy to medium?).

* History/timeline/revision view (hard).

* Drag and drop support (medium).

[[commercial_features]]
== Commercial Features (Future)

In addition to the editor which will remain free and open source,
http://vivosys.com[VIVO Systems], the organization behind Ritzy, is considering
offering the Ritzy editor as a service. Because it is intended for real-time
collaboration, a server-side component is required by Ritzy.

NOTE: A simple but working server-side component is bundled with the free and
open source Ritzy editor. See <<integration_ss>>.

The commercial server-side solution will handle storage, communications,
security, availability, and provide a simple but powerful server-side API for
developers to interact with the editors under their control, and the data they
contain. Some of the features of this API may include:

* Create, archive, and destroy text replicas.

* User identification and specification of authoring labels.

* Set and modify access control.

* Get editor contents (snapshot + real-time bidirectional push).
** Integration with various server-side libraries e.g. Akka, Vert.X, RxJava,
Kafka, etc.

* Set or modify editor contents.

* Show server feedback on editor surface e.g. comments/errors/word highlights.

* Get revision history.

* Get editing statistics e.g. authors, character count overall and by author,
word count overall and by author, time spent editing overall and by author, and
so forth.

* Isomorphic rendering of editor's server-side and client-side for performance.

Please
mailto:sales@vivosys.com?subject=Interested%20in%20the%20Ritzy%20Service[let us
know] if your company or startup may be interested in such a service.

== Support

Support is provided on an as-available basis via
https://github.com/ritzyed/ritzy/issues[GitHub issues].

Contact mailto:raman@vivosys.com[raman@vivosys.com] @
http://vivosys.com[VIVO Systems] for paid support or enhancements.
