Late last year, our group, the Network team, was tasked with building the new Acquia Documentation site, meant to be the central repository of documentation for our hosting platform and products.
Mixed with many other requirements, there were two that required some custom code to be written, plus some special configuration to be thought through:
A) The site should have a Book tree to order the content, but the tree should allow to include the same content under different parents to minimize the creation of duplicate nodes that could later be a challenge to update consistently.
B) The site should allow Documentation editors to collaboratively add comments to different sections of a given document, in real time.
Centralizing content
For our requirement A, after tossing around different ideas, we settled on a content centralization schema, and we introduced the concepts of a Documentation Master and Documentation Instances to our new site.
The Documentation Master is a content type that creates nodes only visible to our Documentation Team, where they can write the document’s content and submit it to the right editorial workflow (more on this to come), but remains agnostic to the actual product or section of the site where its contents will be displayed.
The Documentation Instance is another content type that creates nodes that hold no content other than a simple node reference and a taxonomy categorization, plus a custom title. The Documentation Instance nodes are user facing and can be included in the main index Book tree.
After the creation of the Master/Instance architecture, we wrote a small custom module to hook into the load operation of the Documentation Instance nodes, where we simply perform a mapping from the body, teaser and format object properties to those of the parent node object, loaded from the node reference field. Since the Documentation Instance points to the published revision of its master, this does not get in the way of any editorial workflow on the Documentation Master node.
The result is that our Documentation team can now create as many instances of any given content, and quickly make tweaks to the documentation in a centralized way that will be instantly reflected in all the child nodes without any extra effort.
Collaborative comments for our Docs team
For our requirement B, not being able to find a contrib module to handle our issue, we decided to create a new custom module from scratch (plus some site configuration), with the main concept being: Anyone in our Documentation team should be able to create a review of a Master Instance in any given revision, and hand pick reviewers to be tasked on going over the content, and leave their comments on any portion of text or image that would ultimately face the end user. The editor in charge would then collect the feedback and apply as needed on the Documentation Master, being able to publish it or call another round or review comments to it. The actual commenting system required coding of its own, and we called the resulting module “Dynamic Comments”.
The back-end side of the Dynamic Comments module is simple, there is an installation schema to create a simple table to store the comments and the data related to them, a simple settings page to configure what content types the system can be used on, the refresh rate for the comments displayed on the screen, some general options to pass to the front-end side, etc; and a menu callback function to handle the normal CRUD operations, pretty much a middle man between the JavaScript application and the database.
The font-end side of the module is a set of JS functions that handle the user interaction with the document. One of the main pieces on this side is being able to save user text selections to the database, and being able to then retrieve them and re-display them on the screen. We chose an open source JS library to handle the encoding/decoding of the text selection to and from a shape that can be easily stored and retrieved, called Rangy http://code.google.com/p/rangy/
What we get with this portion of the functionality, is that we can highlight text in the document (pretty much like we would do on a text editor to apply a style), make a comment on it, and store this selection in the database together with some related data, like the comment itself, an id, date, user, etc, using some simple jQuery post functions.
Another JS function handles an interval request for new data (this interval time is configurable from the module settings) that queries the database and converts the JSON response from the server to a set of objects, each of them representing a comment and holding its location on the screen, plus the methods to print itself, react to user interaction, etc. This adds comments from other users to our screen without the need of refreshing the page, as they are written and submitted by anyone on the reviewing team.
There is also a set of functions to handle clicking on the side comments and highlighting the related content by placing a native text selection in the original location retrieved by Rangy.
There are though, some caveats to this approach, that to this date still remain on our drawing board and may make part of future builds as we use our Gardening Days (not sure what a Gardening Day means? checkout http://www.acquia.com/careers for an explanation) to further polish the system. One of them, for instance, is the restriction of not being able to tweak the content as you make comments (a good example is Google Docs). Because we store a selection position in the DOM given by Rangy, any content changes would render this position reference useless, as the DOM changes. Another caveat is the intensive querying that could potentially create a scalability issue if used by more people than just our Documentation team, all at the same time.
To solve the first caveat, we are brainstorming around possibly store metadata in HTML comments and use some sort of JS function to parse these comments. For the second caveat, we’ve been talking about changing the system to use with the Node.js integration module http://drupal.org/project/nodejs and developing a push schema instead of the constant pulling of data we currently use.
Last, there are two things to note about this module: first, our team and Acquia will contribute this module to the community after some nice polishing, and second, the system is still in a very alpha state, but could become a very nice piece of functionality as we invest our Gardening time to fine tune.
Conclusion
It’s been and continues to be a lot of fun to implement solutions for these small, yet somehow complex issues. Amongst other, these contributions will allow our Documentation team to better focus in what’s important to our customers, and take the burden of manual revision using different systems and multi-document edition off their plates. And challenges like this one are a fundamental part of how entertaining is to work here in Acquia. Please feel free to leave any comments and keep your eyes open for the soon to be released Dynamic Comments module in Drupal.org!