How it works
Webstrates’ API provides a variety of functionality, but the main functionality that Webstrates resolves around is DOM synchronization.
Webstrates’ DOM synchronized is built around 4 components, namely JsonML,
the MutationObserver
JavaScript API,
Operational Transformations, and ShareDB.
JsonML
JsonML (or JSON Markup Language) is language for representing XML-based markup as JSON. For instance, the following HTML:
<ul>
<li style="color: red">First Item</li>
<li><a href="/" style="color: green">Second Item</a></li>
</ul>
Could in JsonML look like:
"ul",
{},
[
"li", { "style": "color: red" }, "First Item"
],
[
"li",
{},
[
"a", { "href": "/", "style": "color: green" }, "Second Item"
]
]
All webstrates are persisted as JsonML and are converted back to HTML before being presented to the user in the browser.
The MutationObserver
JavaScript API
The MutationObserver
JavaScript API
provides a way for developers to react to changes in the DOM. Every change to the DOM (except
changes to input fields and textareas, as several other mechanism for detecting changes to these
elements exist) triggers a user-defined callback function, allowing developers to track changes
made by other parts of a web application.
In Webstrates, we listen for these changes and calculate the differences (or “deltas”) between the previous DOM state and the new DOM state after the mutation has occurred. We express these differences as Operational Transformation operations.
Operational Transformations
Operational Transformations (OT) is a standard for expressing differences between many types of documents. With Webstrates, we use the json0 standard to represent our HTML differences. These differences are called operations and are intended to be applied to a document to take it from one state to another (like taking a JsonML representation of a webstrate prior to a mutation to a JsonML representation of the same webstrate after the mutation) without needing to calculate (and transmit) an entirely new JsonML representation of the DOM.
For instance, if we’re looking at the HTML document from before and we’d like to change the text
color of “Second Item” by replacing green
with blue
in the style
attribute, this changes (or
operations) could look something like:
[
{
"sd": "green",
"p": [ 3, 2, 1, "style", 7 ]
},
{
"si": "blue",
"p": [ 3, 2, 1, "style", 7 ]
}
]
The first operation here tells us to perform a string deletion (sd
) from the path at
[3, 2, 1, "style", 7]
, meaning the 3rd child, then that child’s 2nd child, that child’s 1st child,
and the style
property of that object. From that object, we delete the word green
starting at
7th characters in. (i.e. after color:
).
The second operation is very similar, but this is instead a string insertion (si
) of blue
again
starting at the 7th character of the property’s value.
However, just keeping a local JsonML representation of an HTML file up-to-date doesn’t provide much collaborability. For that, we need ShareDB.
ShareDB
ShareDB is a real-time, fully-versioned JSON database operated
on with json0
type operational transformations.
For Webstrates, we can therefore use it to store our JsonML documents and submit any changes
detected in the DOM by our MutationObserver
through OT operations. ShareDB will afterwards make
sure to keep the JsonML representations in the clients consistent.
Just as the MutationObserver
JavaScript API provides ways of detecting changes to the DOM, ShareDB
also provides ways of detecting changes to the JsonML document. In Webstrates, we listen for these
changes (also represented as OT operations) and convert them to their equivalent DOM changes, thus
providing us with a synchronized, consistent two-way binding between the DOM and ShareDB’s shared
JsonML representation of the DOM across clients.
For a more in-depth understanding of how Webstrates work, check out the rest of the Developer guide, as well as the source code for Webstrates and the source code for ShareDB, both readily available on GitHub.