Fork me on GitHub
CreatePHP and contentblocks provide easy integration libraries for using Create.js with PHP and Node.js systems.

Welcome to the Create.js integration guide. This guide aims to provide all the needed information for CMS developers to integrate Create.js as their front-end editing interface.

This guide is still in early stages, and so if you notice any errors or omissions, pull requests are more than welcome into the gh-pages branch of the Create.js repository.

Introduction

Create.js was originally written in 2010 as the next-generation content editing interface of Midgard CMS. Henri Bergius presented it in the Aloha Editor developer conference in Vienna last year, and the TYPO3 developers expressed interest in reusing the codebase.

Because of this we started extracting the various parts of the Create UI into their own, reusable components. The first one was VIE, which provides the underlaying management of editable objects. In basic use scenario, it loads content annotated with RDFa from the web page, populates it into Backbone.js Models and Collections, and then creates Backbone Views for the original RDFa-annotated parts of DOM.

This way the DOM will automatically stay in sync when data changes, whether that happens by user interaction like editing, or through some server communications (we’ve done collaborative editing demos over WebSockets, for instance).

Backbone.js is used there for two reasons:

  • It handles the management of data in Models and Collections, and the connection of those to Views in an elegant way
  • Backbone.Sync is a very good abstraction when we need to be able to persist/retrieve content from various different CMS back-ends

Later in 2011 the German AI Research Institute (DFKI) and Salzburg Research joined the VIE effort through the EU-funded IKS Project. This enabled us to make the library a lot more capable, adding type information, proper namespace handling, and connections with other semantic tools like Apache Stanbol and DBpedia.

The Create.js interface was then rebuilt on top of this new VIE library by writing a bunch of jQuery UI widgets. This way we have an overall default UX that we can ship, but still provide a bunch of different widgets for CMS vendors to pick-and-choose.

Create.js widgets

Create.js structure

  • Editable: makes an RDFa entities (as identified by about) editable with some editing widget (now plain contentEditable, Aloha, Hallo, Redactor, and CKEditor supported, more to come). Provides the events like “modified” of those widgets in a uniform way. Editable also deals with Collections, allowing user to add/remove items from them
  • Storage: provides localStorage save/restore capability, and keeps track of what entities ought to be saved to the back-end
  • Workflows: retrieves workflows that user can activate for a given entity from the back-end, and handles running them. These could be simply things like publish/unpublish and delete, or more complex workflows
  • Notifications: notification bubbles/dialogs that can be used for telling user what has happened (“X has been saved successfully”), or query them for what they want to do (“You have X local modifications for this page. Restore/Ignore”)
  • Tags: content tagging widget
  • Toolbar: holder widget for a toolbar overlay where widgets like Editable, Storage, and Workflows can place buttons
  • Create: ties all of these together to the default UX

Some CMSs use the full Create UX, and some use just parts to provide the UX they want to have. Examples of custom UXs include Symfony CMF and OpenCms.

Create.js integration in nutshell

In nutshell, you have to do the following:

  • Annotate your content with RDFa
  • Include the Create dependencies (jQuery, jQuery UI, Underscore, Backbone, VIE, the editor of your choice)
  • Include the Create JavaScript file (see examples/create.js and examples/create-min.js)
  • Implement Backbone.sync for your back-end

Blogsiple is a Node.js based CMS integration testbed for Create. It may provide useful examples on how the connection between Create and a REST-capable web tool works.

Integration libraries

There are libraries available for some popular programming environments to make interacting with Create.js easier:

  • CreatePHP provides a PHP library for Create.js integration
  • contentblocks provides a Node.js module for Create.js integration

RDFa: Making content editable

RDFa is a way of making regular HTML pages also understandable by machines. It is often used for communicating the information on your website to search engines in a more structured way, but it is also used by Create.js to make content editable.

The RDFa capabilities in Create.js are provided by VIE, a library that connects RDFa content and Backbone.js models together.

Making a content object editable

The base use case of editing content with RDFa in Create.js is to mark-up an individual content object as such.

If you’re for example displaying an article with:

<div class="article">
  <h1>Some title</h1>
  <div>
    Some content
  </div>
</div>

Then all RDFa needed to make it editable would be:

<div class="article" about="/my/article">
  <h1 property="title">Some title</h1>
  <div property="content">
    Some content
  </div>
</div>

This way VIE understands that the information contained in the outer DIV is an editable object identified by URI /my/article. It also understands that is has two editable properties, title and content.

This information comes from the newly-added attributes:

  • about gives the identifier of an object. The identifiers should be URIs, but basically anything that your back-end will understand is fine
  • property tells that the h1 contains the title of the post, and the div contains the contents. These become attributes of our Backbone model instance

In addition to about and property, you can also tell VIE the type of the content object using the typeof attribute:

<div class="article" about="/my/article" typeof="sioc:Post">
  <h1 property="title">Some title</h1>
  <div property="content">
    Some content
  </div>
</div>

This would tell us that the editable entity is a blog post.

Collections

Relationships between entities allow you to communicate structured content to Create.js, which will turn them into Backbone collections. For example, to annotate a list of blog posts:

<div about="http://example.net/blog/" rel="dcTerms:hasPart">
  <div about="http://example.net/my-post">...</div>
  <div about="http://example.net/second-post">...</div>
</div>

This tells Create that there is a blog entity, which contains a collection of two posts. The important things here are:

  • The first about identifies also the blog post container as an entity
  • rel tells that there is a relation between the blog container, and the blog posts under it

Create will use the first entity inside a collection as a “template”, and knows how to add or remove entities from the collection. In Edit mode the user would see an Add button next to the collection.

Vocabularies

You’re free to use any vocabulary to describe your content for Create.js. However, there are some existing vocabulary definitions that are useful, especially if you’d like your RDFa data to be usable by other tools beside Create, like search engines:


Create widget

The Midgard.midgardCreate widget is what ties everything together in the Create.js user interface.

Starting Create:

jQuery(document).ready(function() {
  jQuery('body').midgardCreate({
    url: function() { return '/some/backend/url'; }
  });
});

You can pass Create configuration options when calling the midgardCreate widget. For example, to use Aloha Editor instead of Hallo, do:

jQuery('body').midgardCreate({
  url: function() { return '/some/backend/url'; },
  editor: 'aloha',
  workflows: {
    url: function(model) {
        return '/some/backend/workflows/fetch/url/' + model.id;
    }
  }
});

Configuration

The behavior of Create.js can be modified by passing various configuration keys to the midgardCreate widget:

  • toolbar: Initial toolbar rendering style, either full or minimized
  • state: Initial usage state, either browse or edit
  • highlight: Whether to highlight editable elements when entering edit mode
  • highlightColor: Color to use for the highlights. By default #67cc08 (light green)
  • editorWidgets: widgets for editing different types of content. By default Hallo is used
  • editorOptions: additional editor options
  • collectionWidgets: widgets for managing different types of collections. By default midgardCollectionAdd is used
  • url: callback function used for determining the URL where to save content items
  • vie: an instance of VIE. If this is not provided, Create will instantiate one
  • stanbolUrl: URL for the Stanbol instance used for content enhancements
  • dbPediaUrl: URL for the DBpedia instance used for fetching additional information on linked entities
  • tags: Whether to enable the tag widget
  • buttonContainer: CSS selector for where the Edit and Save buttons should be placed
  • templates: HTML templates used for widget output

Events

Create is an event-based user interface. Normally integrators shouldn’t need to deal with these events, but they’re explained here in case of some customization needs.

  • midgardcreatestatechange: when user switches between browse and edit modes. Event data contains an object with key state telling the state being changed to

Using a custom VIE instance

There are many reasons for using your own configuration of VIE with Create.js. You may for instance want to enable different services, or Stanbol access points there.

The VIE instance should at least have the RDFaService loaded to it. For example:

// Prepare VIE
var v = new VIE();
v.use(new v.RdfaService());

// Load Create.js with your VIE instance
jQuery('body').midgardCreate({
  vie: v
});

Defining custom editors

Managing of different content editors is handled by the Editable widget in Create.js. For convenience, the editor setup can however be provided using a configuration API in the Create widget.

The editors themselves are provided by a Create.js compatible editingWidget. The system comes with some pre-built editing widgets, including plain contentEditable, Hallo, and Aloha Editor, but you can also build your own.

Editor configuration starts by defining a new named editor configuration, in this example an editor called title that uses Hallo:

jQuery('body').midgardCreate('configureEditor', 'title', 'halloWidget', {
  plugins: {
    halloformat: {}
  }
});

Once an editor has been defined, Create can be configured to use it for various editable properties. This can be done by property name, for example:

jQuery('body').midgardCreate('setEditorForProperty', 'dcterms:title', 'title');

The same editor configuration can be reused in as many properties as you like. If you’re using the VIE type system, then editors can also be configured for property types:

jQuery('body').midgardCreate('setEditorForType', 'Text', 'title');

If you want to use a particular editor configuration as the default, you can also do:

jQuery('body').midgardCreate('setEditorForProperty', 'default', 'title');

Making a property non-editable

The editor configuration system can also be used to make properties non-editable by setting their editor to null:

jQuery('body').midgardCreate('setEditorForProperty', 'dcterms:author', null);

Editable widget

The Midgard.midgardEditable widget (or: editable entity widget) is responsible for loading property editor widgets (for example, the Hallo rich text editor) for editing various content elements, and synchronizing those with the underlying VIE entity instances.

Create.js will load the EditableEntity widget automatically for all RDFa annotated entities on the page, but you can also do it manually:

jQuery('[about]').midgardEditable({
  vie: new VIE()
});

Let’s clarify the nomenclature to take away any possible confusion:

  • a subject is the identifier of an entity
  • a predicate is the identifier of a property of an entity
  • an entity is an instance of a subject that contains the properties identified for it by (subject, predicate) pairs
  • a property is an instance of a predicate for a given entity (and thus contains the value for that predicate)

So, Create.js will instantiate an editable entity widget for each entity on the page, which in turn will then instantiate a property editor widget for each property within that entity. Note that it is possible to have multiple EditableEntity widgets for the same entity — you may need to do this because your entity may be spread all over the page, for example.

Configuration

  • propertyEditorWidgets: object telling which property editor widget to load for which content type
  • propertyEditorWidgetsConfiguration: object telling how each property editor widget should be configured
  • collectionWidgets: object telling which collection handling widget to load for which content type

States

The EditableEntity widget carries an editable entity through various different states and controls the behavior of the particular property editor widgets as needed. There are various events signaling transitions between different states.

Note: state handling of the EditableEntity widget and the PredicateEditor widgets it may contain still needs to be refined.

  • Inactive - editable has been loaded but editor is not active. Entered via the midgardeditabledisable event
  • Candidate - editor has been enabled for the editable. Entered via the midgardeditableenable and midgardeditablenableproperty events
  • Highlighted - user’s mouse is over an editor but the editor hasn’t been focused yet. Entered via the midgardeditablehighlight event
  • Active - editor is focused. Entered via midgardeditableactivated and exited via midgardeditabledeactivated
  • Modified - contents of the editor have been modified. Entered via midgardeditablechanged event
  • Invalid - contents of the editor have validation error(s)

Events

All events below always contain the following event data:

  • entity: the Backbone model instance for the entity
  • editableEntity: the EditableEntity widget object for the entity
  • entityElement: the DOM element for the entity

If an event is specific to a property of the entity, then it will also contain the following event data:

  • predicate: the identifying predicate for the property of the entity
  • propertyEditor: the PredicateEditor widget object for the predicate of the entity
  • propertyElement: the DOM element for the property of the entity

Events:

  • midgardeditableenable: when an entity has been made editable.
  • midgardeditabledisable: when an entity has been made non-editable.
  • midgardeditableactivated: when a particular property of an entity has been activated in a property editor.
  • midgardeditabledeactivated: when a particular property of an entity has been deactivated in a property editor.
  • midgardeditablechanged: when a particular property of an entity has been changed in a property editor.
  • midgardeditableenableproperty: when a particular property of an entity has been made editable.

Because of a limitation of jQuery UI, please note that this event can be triggered by the EntityEditable widget only. So, with this HTML structure:

<article about="/my/article" typeof="sioc:Post">
    <header>
        <h1 property="title">A title</h1>
    </header>
    <div class="content" property="content">
        Some content
    </div>
</article>

// this works (event triggered on the entity)
jQuery('body article').bind('midgardeditableenableproperty',
    function(event, data) {
        console.log('i am called')
    }
);

// this doesn't work (event triggered on a property of the entity)
jQuery('body article .content').bind('midgardeditableenableproperty',
    function(event, data) {
        console.log('i am called');
    }
);

Workflows widget

The Midgard.midgardWorkflows widget provides a way to see current workflow status of the currently activated content item, and initiate new workflows for it.

The Workflows widget will be automatically initiated by Create.js. You can also run it standalone:

jQuery('body').midgardWorkflows({
  url: function (item) { return '/some/item/workflows.json'; }
});

Configuration

  • url: The URL callback function used for retrieving workflows for an item

Events

  • midgardworkflowschanged: triggered whenever workflows have been retrieved for an item. Event data contains the content item and the available workflows

Toolbar widget

The Midgard.midgardToolbar widget provides the floating toolbar where various Create.js widgets place their buttons.

The toolbar can rendered full, or in a minimized mode where only the logo is shown. The minimized mode also triggers Create’s focus mode where the other UI elements are also shown in a minimalistic fashion, allowing authors to focus on the content they’re writing.

When the Create widget is used the toolbar will be instantiated automatically. If you want to use it standalone, then call it in the following way:

jQuery('body').midgardToolbar({
  display: 'full'
});

Tool areas

The toolbar provides several different areas where buttons can be placed.

  • Session status: Used for actions that affect the current usage session, like Edit and Save. This area is identified by the CSS selector .create-ui-toolbar-wrapper .create-ui-statustools

Configuration

  • display: The display status of the toolbar, either full or minimized

Events

  • midgardtoolbarstatechange: when user opens or minimizes the toolbar. Event data contains an object with key display telling the new state

Tags widget

The Midgard.midgardTags widget provides a way for tagging content items. Tags can be set manually, or suggested by the Apache Stanbol enhancer based on item contents.

Create.js will instantiate the Tags widget automatically if tagging is enabled, but you can also run it standalone:

jQuery('body').midgardTags({
  vie: new VIE(),
  entityElement: jQuery('div.article'),
  entity: myArticle
});

Configuration

  • vie: VIE instance
  • entity: VIE entity to handle tagging for
  • entityElement: DOM element containing the RDFa-annotated entity
  • parentElement: CSS selector for where the tags widget should be placed
  • predicate: entity property where tags should be stored. By default skos:related

Storage widget

The Midgard.midgardStorage widget keeps track of content items edited using the Editable widget, and provides saving and loading functionality via both localStorage (for unsaved drafts) and the CMS back-end.

The Storage widget will be automatically instatiated by Create.js, but if you want to use it standalone, you can also:

jQuery('body').midgardStorage({
  vie: new VIE(),
  url: function (item) { return '/some/url'; }
});

Communications with the CMS back-end

Create communicates with your server-side system using Backbone.sync. By default this means that we send and retrieve content encoded in JSON-LD over XmlHttpRequest calls.

If you’re using this default approach, it is important to provide the URL of the endpoint on your server that you want Backbone and Create to talk with. This can be done by passing a string when initializing midgardCreate:

jQuery('body').midgardCreate({
  url: function() { return '/some/backend/url'; }
});

When implemented this way, all communications from Create will happen using normal RESTful HTTP calls to that URL.

  • Creating a new object makes a HTTP POST to the URL
  • Updating or fetching an object makes a HTTP PUT or HTTP GET to that URL with the id of the object appended (for example /some/backend/url/objectId)

If you need to use different URIs for different entities, you can accomplish this by modifying the URL callback function. In the function the this context will refer to the entity being saved. For example:

jQuery('body').midgardCreate({
  url: function () {
    if (this.isNew() && this.collection) {
      return this.collection.url;
    }
    return this.getSubjectUri();
  }
});

You can override this default communications layer by implementing your own Backbone.sync method. Some examples:

Configuration

  • localStorage: Whether to enable localStorage. The Storage widget will automatically probe whether browser has support for it and enable it accordingly
  • vie: VIE instance to be used for content items
  • url: The URL callback function used with Backbone.sync
  • autoSave: Whether autosaving is enabled. false by default
  • autoSaveInterval: autosaving interval, in milliseconds
  • editableNs: jQuery UI event namespace used for Editable widgets. By default midgardeditable
  • templates: HTMl templates for user interface message contents of this widget

Methods

The Storage widget provides some public methods you can call:

  • saveRemote: save a single entity to the remote server. Takes an options object with success and error callbacks

  • saveRemoteAll: save all pending changes to the remote server. Takes an options object with success and error callbacks. Example:

      jQuery('body').midgardStorage('saveRemoteAll', {
        success: function () {
          console.log("All saved!");
        },
        error: function () {
          console.log("Failed");
        }
      });
  • hasLocal: check whether an entity has values in localStorage

  • readLocal: update an entity with the values from localStorage

  • checkRestore: if there are local modifications to editable entities, show a notification dialog asking whether to restore them. Example:

      jQuery('body').midgardStorage('checkRestore');
  • disableSave: temporarily prevent autosaving

  • enableSave: re-enable autosaving

Events

  • midgardstorageloaded: when an item has been restored from localStorage
  • midgardstoragesave: when save to back-end has been initiated. Event data contains models key with all the changed entities
  • midgardstoragesaved: when save has completed succesfully
  • midgardstorageerror: when saving an entity failes. Event data contains the failed entity instance

Notifications widget

The Midgard.midgardNotifications widget provides a way to display notifications on various events to the user. These notifications may optionally provide buttons that the user can act on.

When initialized, the notifications widget will instantiate a div element for containing any notifications being displayed.

The notifications widget will be instantiated by the Create widget automatically. If you want to use it standalone, simply call:

jQuery('body').midgardNotifications();

Displaying notifications

When the notifications widget is instantiated to an element, it will set a data attribute midgardNotifications pointing to itself.

This allows new notifications to be shown using the following call:

jQuery('body').data('midgardNotifications').create({
  body: 'Hello, world!'
});

The create method accepts various properties to affect the behavior of a notification pop-up. These include:

  • body: Textual contents of the notification
  • class_prefix: Prefix for the CSS classes of the notification element
  • auto_show: whether the notification should be displayed automatically
  • bindTo: a CSS selector to bind the notification into a particular DOM element instead of the notifications area
  • gravity: the direction from the notification to the bound element. For example TR for top-right
  • timeout: how many milliseconds the notification should be shown, or 0 for forever
  • actions: array of action buttons to be added to the notification